3

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 havefreqset 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)
Dan Ward
  • 31
  • 2
  • 1
    can you tell it's my first post :~ – Dan Ward Mar 10 '20 at 20:39
  • pandas bars are categorical. The first bar is at 0, second at 1, etc. You can easily set the ticks to negative numbers, `ax.set_xticks(np.arange(-3, 10))` – ImportanceOfBeingErnest Mar 10 '20 at 21:10
  • @ImportanceOfBeingErnest, when I use plt.plot.bar() with the same set-up (no stacking) the xticks do come back as integers corresponding to the dates though. I want to be able to add additional bars later so it will be hard to have to align on categorical xticks – Dan Ward Mar 10 '20 at 21:38
  • Strange enough. I do get the same error, no matter if `stacked=True` or not. And that error is actually expectedto my knowledge. – ImportanceOfBeingErnest Mar 10 '20 at 21:55

0 Answers0