I have found what appears to me to be a bug in the integration between matplotlib
and pandas.DataFrame
though it could be I am making a mistake.
I have a period of time I want to plot barcharts with bars representing quarterly periods. I want to fix the axis start and end date even if my data does not run all the way to the left or right of the axis.
My dataframe I am plotting has the periods as the index.
What I have found is that while the manual (https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.plot.bar.html) indicates that the index is taken as x
we see that ax.get_xticks()
returns 0,1,2,..
integers as the xticks which means I cannot easily provide a new max/min for the scale.
Further, when I try to set a range through ax.set_xticks()
or ax.set_xlim()
I get the error TypeError: Axis must have
freqset to convert to Period
.
So it appears that i) I cannot add tick ranges easily as I cannot set x
to be the index; and ii) I cannot use series of Periods (or it seems DateTime) as input to the axis functions to set the range as it requires a frequency.
I am doing this because stacked=True
is a valid input into py.DataFrame.plot.bar()
whereas there is no integrated manner to build stacked charts with plt.plot()
or plt.plot.bar()
.
Note I have done this the 'long way' and issue i) is resolved which makes me think its a bug. I am still not able to provide my periodindex idx_dts
to set the range of the x-axis though.
Here is a sample of code:
# external modules
import pandas as pd
# create a dataframe with a long periodindex
asof = pd.datetime(2019, 12, 31)
report_freq = 'Q-NOV'
num_periods = 8
idx_dts = pd.date_range(end=asof,
freq=report_freq,
periods=num_periods,
name='periods')
idx_dts = idx_dts.to_period(report_freq)
idx_dts # a period.PeriodIndex
# set a shorter dataframe not covering the full span of periods
df = pd.DataFrame({'a': (1,2,3,4), 'b': (6,7,8,9), 'c': (10,20,30,40)})
df.index = idx_dts[3:7]
# take a look at the dataframe
df
# plot as a stacked barchart
ax=df.plot.bar(stacked=True)
# notice ticks are array([0,1,2,3]) NOT the index of df as indicated
ax.get_xticks()
# labels have been taken from the index though
ax.get_xticklabels()[:]
# I want to set a wider periods axis corresponding toe idx_dts
# error: 'TypeError: Axis must have `freq` set to convert to Periods'
ax.set_xticks(idx_dts)