matplotlib log date tick labels - python

My question is if there is any way to use matplotlib date tick labels with a log xscale.
I find whenever I try to set_xscale('log') it just erases the labels and doesn't actually log the xscale...
Example code:
import datetime
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import matplotlib.cbook as cbook
years = mdates.YearLocator() # every year
months = mdates.MonthLocator() # every month
yearsFmt = mdates.DateFormatter('%Y')
# Load a numpy record array from yahoo csv data with fields date, open, close,
# volume, adj_close from the mpl-data/example directory. The record array
# stores the date as an np.datetime64 with a day unit ('D') in the date column.
with cbook.get_sample_data('goog.npz') as datafile:
r = np.load(datafile)['price_data'].view(np.recarray)
# Matplotlib works better with datetime.datetime than np.datetime64, but the
# latter is more portable.
date = r.date.astype('O')
fig, ax = plt.subplots()
ax.plot(date, r.adj_close)
# format the ticks
ax.xaxis.set_major_locator(years)
ax.xaxis.set_major_formatter(yearsFmt)
ax.xaxis.set_minor_locator(months)
datemin = datetime.date(date.min().year, 1, 1)
datemax = datetime.date(date.max().year + 1, 1, 1)
ax.set_xlim(datemin, datemax)
# format the coords message box
def price(x):
return '$%1.2f' % x
ax.format_xdata = mdates.DateFormatter('%Y-%m-%d')
ax.format_ydata = price
ax.grid(True)
# rotates and right aligns the x labels, and moves the bottom of the
# axes up to make room for them
fig.autofmt_xdate()
ax.set_xscale('log')
plt.show()

Try using ScalarFormatter:
from matplotlib.ticker import ScalarFormatter
ax.xaxis.set_major_formatter(ScalarFormatter())

Related

Convert x-axis from days to month in matplotlib

i have x-axis which is in terms of days (366 days Feb was taken as 29 days) but instead I want to convert it in terms of months (Jan - Dec). What should i do...
def plotGraph():
line, point = getXY()
plt.plot(line['xlMax'], c='orangered', alpha=0.5, label = 'Minimum Temperature (2005-14)')
plt.plot(line['xlMin'], c='dodgerblue', alpha=0.5, label = 'Minimum Temperature (2005-14)')
plt.scatter(point['xsMax'].index, point['xsMax'], s = 10, c = 'maroon', label = 'Record Break Minimum (2015)')
plt.scatter(point['xsMin'].index, point['xsMin'], s = 10, c = 'midnightblue', label = 'Record Break Maximum (2015)')
ax1 = plt.gca() # Primary axes
ax1.fill_between(line['xlMax'].index , line['xlMax'], line['xlMin'], facecolor='lightgray', alpha=0.25)
ax1.grid(True, alpha = 1)
for spine in ax1.spines:
ax1.spines[spine].set_visible(False)
ax1.spines['bottom'].set_visible(True)
ax1.spines['bottom'].set_alpha(0.3)
# Removing Ticks
ax1.tick_params(axis=u'both', which=u'both',length=0)
plt.show()
I think the quickest change might be to just set new ticks and tick labels at the starts of months; I found the conversion from day-of-the-year to month here, the first table:
import numpy as np
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
x = range(1,367)
y = np.random.rand(len(range(1,367)))
ax.plot(x,y)
month_starts = [1,32,61,92,122,153,183,214,245,275,306,336]
month_names = ['Jan','Feb','Mar','Apr','May','Jun',
'Jul','Aug','Sep','Oct','Nov','Dec']
ax.set_xticks(month_starts)
ax.set_xticklabels(month_names)
Note I assumed your days were numbered 1 to 366; if they are 0 to 365 you may have to change the range.
But I think usually a better approach is to get your days into some sort of datetime; this is more flexible and usually pretty smart. If say, your days were not confined to one year, it would be more complicated to associate day numbers with months.
This example uses datetime instead of integers. The dates are plotted on the x-axis directly, and then the DateFormatter and MonthLocator from matplotlib.dates are used to format the axis appropriately:
import datetime as dt
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import numpy as np
start = dt.datetime(2016,1,1) #there has to be a year given, even if it isn't plotted
new_dates = [start + dt.timedelta(days=i) for i in range(366)]
fig, ax = plt.subplots()
x = new_dates
y = np.random.rand(len(range(1,367)))
xfmt = mdates.DateFormatter('%b')
months = mdates.MonthLocator()
ax.xaxis.set_major_locator(months)
ax.xaxis.set_major_formatter(xfmt)
ax.plot(x,y)

How to make the horizontal axis of a chart show dates

I've been trying to plot my data on a line chart, and I expect it to show dates on the horizontal axis, i used index_col to set the index as date but that returns an empty dataframe.. can some one help please
data = pd.read_csv('good_btc_dataset.csv', warn_bad_lines= True,
index_col= ['date'])
data.dropna(inplace=True)
data.index = range(3169)
data.head()
I expect my chart to show dates on the horizontal axis but all it shows is numbers
thanks in advance
I recommend you to check this script (it is a copy and paste from the documentation). I think you just need to adapt your own data.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import matplotlib.cbook as cbook
years = mdates.YearLocator() # every year
months = mdates.MonthLocator() # every month
years_fmt = mdates.DateFormatter('%Y')
# Load a numpy structured array from yahoo csv data with fields date, open,
# close, volume, adj_close from the mpl-data/example directory. This array
# stores the date as an np.datetime64 with a day unit ('D') in the 'date'
# column.
with cbook.get_sample_data('goog.npz') as datafile:
data = np.load(datafile)['price_data']
fig, ax = plt.subplots()
ax.plot('date', 'adj_close', data=data)
# format the ticks
ax.xaxis.set_major_locator(years)
ax.xaxis.set_major_formatter(years_fmt)
ax.xaxis.set_minor_locator(months)
# round to nearest years.
datemin = np.datetime64(data['date'][0], 'Y')
datemax = np.datetime64(data['date'][-1], 'Y') + np.timedelta64(1, 'Y')
ax.set_xlim(datemin, datemax)
# format the coords message box
ax.format_xdata = mdates.DateFormatter('%Y-%m-%d')
ax.format_ydata = lambda x: '$%1.2f' % x # format the price.
ax.grid(True)
# rotates and right aligns the x labels, and moves the bottom of the
# axes up to make room for them
fig.autofmt_xdate()
plt.show()

Adding formatted dates as xticks in Matplotlib

I am trying to add a list of dates to Matplotlib xticks and when I do that the actual plot disappears keeping only xticks.
For example, I have the following code:
import numpy as np
import datetime as dt
import matplotlib.pyplot as plt
from matplotlib.dates import (DateFormatter, rrulewrapper, RRuleLocator, YEARLY)
# Generate random data and dates
data = np.random.randn(10000)
start = dt.datetime.strptime("2019-03-14", "%Y-%m-%d")
end = dt.datetime.strptime("2046-07-30", "%Y-%m-%d")
date = [start + dt.timedelta(days=x) for x in range(0, (end-start).days)]
rule = rrulewrapper(YEARLY, byeaster=1, interval=2)
loc = RRuleLocator(rule)
formatter = DateFormatter('%d/%m/%y')
fig, ax = plt.subplots()
ax.xaxis.set_major_locator(loc)
ax.xaxis.set_major_formatter(formatter)
ax.xaxis.set_tick_params(rotation=30, labelsize=10)
plt.plot(data)
# ax.set_xlim(min(date), max(date))
plt.show()
This code plots the data which looks like this:
Now if I uncomment ax.set_xlim(min(date), max(date)) and rerun the code I get:
You can see that I only get the dates, formatted correctly but not the plot. I am not sure what the problem here. Any help would be appreciated.
Update
If I change data = np.random.randn(10000) to data = np.random.randn(1000000), then I am able to see the plot Which is not what I want
Most likely your data is plotted, but not at the correct location. If you go along that example you would need to add something like fig.autofmt_xdate() to your code.
The way to do this is by passing the date array along with data array in the plot method. That is with the given example it will be:
import numpy as np
import datetime as dt
import matplotlib.pyplot as plt
from matplotlib.dates import (DateFormatter, rrulewrapper, RRuleLocator, YEARLY)
# Generate random data and dates
data = np.random.randn(10000)
start = dt.datetime.strptime("2019-03-14", "%Y-%m-%d")
end = dt.datetime.strptime("2046-07-30", "%Y-%m-%d")
date = [start + dt.timedelta(days=x) for x in range(0, (end-start).days)]
rule = rrulewrapper(YEARLY, byeaster=1, interval=2)
loc = RRuleLocator(rule)
formatter = DateFormatter('%d/%m/%y')
fig, ax = plt.subplots()
ax.xaxis.set_major_locator(loc)
ax.xaxis.set_major_formatter(formatter)
ax.xaxis.set_tick_params(rotation=30, labelsize=10)
plt.plot(date, data)
ax.set_xlim(min(date), max(date))
plt.show()
Then you'll get:
See matplotlib.pyplot.plot() for more information.

Unable to show Pandas dateindex on a matplotlib x axis

I'm trying to build matplotlib charts whose x-axis is a dateIndex from a pandas dataframe. Trying to mimic some examples from matplotlib, I've been unsuccessful. The xaxis ticks and labels never appear.
I thought maybe matplotlib wasn't properly digesting the pandas index, so I converted it to ordinal with the matplotlib date2num helper function, but that gave the same result.
# https://matplotlib.org/api/dates_api.html
# https://matplotlib.org/examples/api/date_demo.html
import datetime as dt
import matplotlib.dates as mdates
import matplotlib.cbook as cbook
import matplotlib.dates as mpd
years = mdates.YearLocator() # every year
months = mdates.MonthLocator() # every month
yearsFmt = mdates.DateFormatter('%Y')
majorLocator = years
majorFormatter = yearsFmt #FormatStrFormatter('%d')
minorLocator = months
y1 = np.arange(100)*0.14+1
y2 = -(np.arange(100)*0.04)+12
"""neither of these indices works"""
x = pd.date_range(start='4/1/2012', periods=len(y1))
#x = map(mpd.date2num, pd.date_range(start='4/1/2012', periods=len(y1)))
fig, ax = plt.subplots()
ax.plot(x,y1)
ax.plot(x,y2)
ax.xaxis.set_major_locator(years)
ax.xaxis.set_major_formatter(yearsFmt)
ax.xaxis.set_minor_locator(months)
datemin = x[0]
datemax = x[-1]
ax.set_xlim(datemin, datemax)
fig.autofmt_xdate()
plt.show()
The problem is the following. pd.date_range(start='4/1/2012', periods=len(y1)) creates dates from the first of April 2012 to the 9th of July 2012.
Now you set the major locator to be a YearLocator. This means, that you want to have a tick for each year on the axis. However, all dates are within the same year 2012. So there is no major tick to be shown within the plot range.
The suggestion would be to use a MonthLocator instead, such that the first of each month is ticked. Also if would make sense to use a formatter, which actually shows the months, e.g. '%b %Y'. You may use a DayLocator for the minor ticks, if you want, to show the small tickmarks for each day.
ax.xaxis.set_major_locator(mdates.MonthLocator())
ax.xaxis.set_major_formatter(mdates.DateFormatter('%b %Y'))
ax.xaxis.set_minor_locator(mdates.DayLocator())
Complete example:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
y1 = np.arange(100)*0.14+1
y2 = -(np.arange(100)*0.04)+12
x = pd.date_range(start='4/1/2012', periods=len(y1))
fig, ax = plt.subplots()
ax.plot(x,y1)
ax.plot(x,y2)
ax.xaxis.set_major_locator(mdates.MonthLocator())
ax.xaxis.set_major_formatter(mdates.DateFormatter('%b %Y'))
ax.xaxis.set_minor_locator(mdates.DayLocator())
fig.autofmt_xdate()
plt.show()
You could use pd.DataFrame.plot to handle most of that
df = pd.DataFrame(dict(
y1=y1, y2=y2
), index=x)
df.plot()

Python Matplotlib: Changing color in plot_date

I wanted to plot a data which has datetime values for the x axis and another set of values as y. As an example, I will use the example from matplotlib where y in this case are stock prices. Here is the code for that.
import matplotlib.pyplot as plt
from matplotlib.finance import quotes_historical_yahoo_ochl
from matplotlib.dates import YearLocator, MonthLocator, DateFormatter
import datetime
date1 = datetime.date(1995, 1, 1)
date2 = datetime.date(2004, 4, 12)
years = YearLocator() # every year
months = MonthLocator() # every month
yearsFmt = DateFormatter('%Y')
quotes = quotes_historical_yahoo_ochl('INTC', date1, date2)
if len(quotes) == 0:
raise SystemExit
dates = [q[0] for q in quotes]
opens = [q[1] for q in quotes]
fig, ax = plt.subplots()
ax.plot_date(dates, opens, '-')
# format the ticks
ax.xaxis.set_major_locator(years)
ax.xaxis.set_major_formatter(yearsFmt)
ax.xaxis.set_minor_locator(months)
ax.autoscale_view()
# format the coords message box
def price(x):
return '$%1.2f' % x
ax.fmt_xdata = DateFormatter('%Y-%m-%d')
ax.fmt_ydata = price
ax.grid(True)
fig.autofmt_xdate()
plt.show()
Now, what I want to do is color each value in the graph based on some criterion. For simplicity's sake, let's say that the criterion in the case of the example is based on the year. That is, prices belonging to the same year will be colored the same. How would I do that? Thanks!
You can use numpy arrays with masks over the range you want (in this case a year). In order to use the inbuilt YearLocator function from your example, you need to plot the graph first and set the ticks, then remove and replace with the range per year, from your example,
import matplotlib.pyplot as plt
from matplotlib.finance import quotes_historical_yahoo_ochl
from matplotlib.dates import YearLocator, MonthLocator, DateFormatter
import datetime
import numpy
date1 = datetime.date(1995, 1, 1)
date2 = datetime.date(2004, 4, 12)
years = YearLocator() # every year
months = MonthLocator() # every month
yearsFmt = DateFormatter('%Y')
quotes = quotes_historical_yahoo_ochl('INTC', date1, date2)
if len(quotes) == 0:
raise SystemExit
dates = np.array([q[0] for q in quotes])
opens = np.array([q[1] for q in quotes])
fig, ax = plt.subplots()
l = ax.plot_date(dates, opens, '-')
# format the ticks
ax.xaxis.set_major_locator(years)
ax.xaxis.set_major_formatter(yearsFmt)
ax.xaxis.set_minor_locator(months)
ax.autoscale_view()
l[0].remove()
py = years()[0]
for year in years()[1:]:
mask = (py < dates) & (dates < year)
ax.plot_date(dates[mask], opens[mask], '-')
py = year
# format the coords message box
def price(x):
return '$%1.2f' % x
ax.fmt_xdata = DateFormatter('%Y-%m-%d')
ax.fmt_ydata = price
ax.grid(True)
fig.autofmt_xdate()
plt.show()
which gives,
The way I typically do this is by using a for loop to plot different sections of the data, coloring each section as I go. In your example, this section:
fig, ax = plt.subplots()
ax.plot_date(dates, opens, '-')
becomes:
# import the colormaps
from maplotlib import cm
fig, ax = plt.subplots()
for y in years:
y_indices = [i for i in range(len(dates)) if dates[i].year==y]
# subset the data, there are better ways to do this
sub_dates = [dates[i] for i in y_indices]
sub_opens = [opens[i] for i in y_indices]
# plot each section of data, using a colormap to change the color for
# each iteration.
ax.plot_date(sub_dates, sub_opens, '-', linecolor=cm.spring((y-2000)/10.0)

Categories

Resources