Reputation: 433
I'm looking for help on an issue I have with my graphs.
I'm trying to plot financial data contained inside a dataframe with dates and hours as index, however, matplotlib standard dates formatting doesn't do the trick here as I don't want evenly spread ticks on the x axis, as it shows big horizontal lines between business hours.
The solution I came up with is simply to plot this graph using np.arange on the x axis, and to use the index as the label on the x axis, thus not using matplotlib date formatting, but still displaying the dates on my graph.
My code is the following:
L = np.arange(len(DAX_M15.index))
def format_date(x, pos=None):
return DAX_M15.index[x].strftime("%Y-%m-%d %H-%M-%S")
fig, ax = plt.subplots()
ax.plot(L, DAX_M15["Open"])
ax.xaxis.set_major_formatter(ticker.FuncFormatter(format_date))
ax.set_title("Custom tick formatter")
fig.autofmt_xdate()
However, I get the following error when using this:
File "D:\Anaconda\lib\site-packages\matplotlib\backends\backend_qt5agg.py", line 197, in __draw_idle_agg
FigureCanvasAgg.draw(self)
File "D:\Anaconda\lib\site-packages\matplotlib\backends\backend_agg.py", line 464, in draw
self.figure.draw(self.renderer)
File "D:\Anaconda\lib\site-packages\matplotlib\artist.py", line 63, in draw_wrapper
draw(artist, renderer, *args, **kwargs)
File "D:\Anaconda\lib\site-packages\matplotlib\figure.py", line 1144, in draw
renderer, self, dsu, self.suppressComposite)
File "D:\Anaconda\lib\site-packages\matplotlib\image.py", line 139, in _draw_list_compositing_images
a.draw(renderer)
File "D:\Anaconda\lib\site-packages\matplotlib\artist.py", line 63, in draw_wrapper
draw(artist, renderer, *args, **kwargs)
File "D:\Anaconda\lib\site-packages\matplotlib\axes\_base.py", line 2426, in draw
mimage._draw_list_compositing_images(renderer, self, dsu)
File "D:\Anaconda\lib\site-packages\matplotlib\image.py", line 139, in _draw_list_compositing_images
a.draw(renderer)
File "D:\Anaconda\lib\site-packages\matplotlib\artist.py", line 63, in draw_wrapper
draw(artist, renderer, *args, **kwargs)
File "D:\Anaconda\lib\site-packages\matplotlib\axis.py", line 1136, in draw
ticks_to_draw = self._update_ticks(renderer)
File "D:\Anaconda\lib\site-packages\matplotlib\axis.py", line 969, in _update_ticks
tick_tups = [t for t in self.iter_ticks()]
File "D:\Anaconda\lib\site-packages\matplotlib\axis.py", line 969, in <listcomp>
tick_tups = [t for t in self.iter_ticks()]
File "D:\Anaconda\lib\site-packages\matplotlib\axis.py", line 916, in iter_ticks
for i, val in enumerate(majorLocs)]
File "D:\Anaconda\lib\site-packages\matplotlib\axis.py", line 916, in <listcomp>
for i, val in enumerate(majorLocs)]
File "D:\Anaconda\lib\site-packages\matplotlib\ticker.py", line 386, in __call__
return self.func(x, pos)
File "D:/Finance python/test_data_formatter.py", line 40, in format_date
return DAX_M15.index[x].strftime("%Y-%m-%d %H-%M-%S")
File "D:\Anaconda\lib\site-packages\pandas\tseries\base.py", line 247, in __getitem__
raise ValueError
ValueError
Would anyone have an idea on the issue here and how to solve it?
Thanks.
Upvotes: 2
Views: 480
Reputation: 339340
As said in the comments, the problem is that the index of a list or series needs to be an integer between 0 and the length of the list. Something like DAX_M15.index[4.5]
will not work.
In order to ensure that only those locations that have a datapoint associated with them are ticked, you may use a matplotlib.ticker.IndexLocator
. E.g. if you want to label every fifth point of the list,
ax.xaxis.set_major_locator(ticker.IndexLocator(5,0))
ax.xaxis.set_major_formatter(ticker.FuncFormatter(format_date))
Inside the formatter you would also need to make sure the index is an integer and within the range of allowed values.
def format_date(x, pos=None):
if int(x) >= len(df.index) or int(x) < 0: return ""
return df.index[int(x)].strftime("%Y-%m-%d %H-%M-%S")
A complete example:
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import numpy as np
import pandas as pd
inx = pd.DatetimeIndex(start="2017-05-05", freq="7H", periods=45)
df = pd.DataFrame({"open" : np.random.rand(len(inx))}, index=inx)
L = np.arange(len(df.index))
def format_date(x, pos=None):
return df.index[int(x)].strftime("%Y-%m-%d %H-%M-%S")
fig, ax = plt.subplots()
ax.plot(L, df["open"])
ax.xaxis.set_major_locator(ticker.IndexLocator(5,0))
ax.xaxis.set_major_formatter(ticker.FuncFormatter(format_date))
ax.set_title("Custom tick formatter")
fig.autofmt_xdate()
plt.show()
Upvotes: 1