3

I have a python dataframe with two columns, a numeric column (total_outbounds) on the y-axis and a date column (month, pardon the bad name) for x-axis:

enter image description here

and when when I run this code to create a graph using this dataframe:

fig,ax = plt.subplots()

my_df.plot(x='month', y='total_outbounds', ax=ax, label = 'Total Email Outbounds on LE Change')
ax.xaxis.set_major_formatter(mdates.DateFormatter('%m/%y'))
plt.xlabel('')
plt.title('Total LE Changes and Outbounds by Month', pad = 10)

I receive a graph where the X-axis is not what I was hoping for... Am I using mdates.DateFormatter wrong? Looking to receive mm/yy on the X-Axis, instead of the Apr, Jul, etc. that are currently appearing.

enter image description here

For reproducibility, here is the dataframe output with my_df.to_dict()

{'month': {0: Timestamp('2020-01-01 00:00:00'),
  1: Timestamp('2020-02-01 00:00:00'),
  2: Timestamp('2020-03-01 00:00:00'),
  3: Timestamp('2020-04-01 00:00:00'),
  4: Timestamp('2020-05-01 00:00:00'),
  5: Timestamp('2020-06-01 00:00:00'),
  6: Timestamp('2020-07-01 00:00:00'),
  7: Timestamp('2020-08-01 00:00:00'),
  8: Timestamp('2020-09-01 00:00:00'),
  9: Timestamp('2020-10-01 00:00:00'),
  10: Timestamp('2020-11-01 00:00:00'),
  11: Timestamp('2020-12-01 00:00:00'),
  12: Timestamp('2021-01-01 00:00:00'),
  13: Timestamp('2021-02-01 00:00:00'),
  14: Timestamp('2021-03-01 00:00:00')},
 'total_outbounds': {0: 26364,
  1: 33081,
  2: 35517,
  3: 34975,
  4: 40794,
  5: 51659,
  6: 50948,
  7: 65332,
  8: 82839,
  9: 96408,
  10: 86923,
  11: 99176,
  12: 122199,
  13: 116057,
  14: 108439}}

and I think you should be able to use pd.DataFrame.from_dict() to turn that back into a dataframe my_df from the dictionary. Please let me know if there's a more reproducible way to share the dataframe.

Edit: the solution in the comments works, however now I cannot rotate the minor ticks using plt.xaxis(rotation=50), this only rotates the two major ticks... also the X-axis values appearing are odd (showing 71 as the year?)

enter image description here

Fiori
  • 181
  • 1
  • 12
  • 2
    The Apr/Jul/Oct are the minor ticks. Your code only sets the major ticks atm. – tdy Mar 26 '21 at 01:44
  • 2
    That does seem to be the case. I'll add minor ticks as well. Do you know if there's a way to combine them in one line? so as to not call `set_minor_formatter` and `set_major_formatter`? It doesn't look like `set_formatter` exists... – Fiori Mar 26 '21 at 01:46
  • 3
    Only way I know is to call both. Also you might consider increasing your major tick interval so you don't have to deal with minor ticks at all (and then the font styling will be consistent as well). – tdy Mar 26 '21 at 01:50
  • 2
    thanks this worked, however I have a new issue with rotating ticks now... – Fiori Mar 26 '21 at 01:50

2 Answers2

3

As discussed in the comments, the Apr/Jul/Oct are minor ticks.

However, rather than customizing both major/minor ticks, I suggest increasing the major tick frequency, disabling minor ticks, and using autofmt_xdate() to style the date ticks:

fig, ax = plt.subplots()
ax.plot(df.month, df.total_outbounds, label='Total Email Outbounds on LE Change')
ax.legend()

# increase the major tick frequency (8 ticks in this example)
start, end = ax.get_xlim()
xticks = np.linspace(start, end, 8)
ax.set_xticks(xticks)
ax.set_xticklabels(xticks)

# set date format
ax.xaxis.set_major_formatter(mdates.DateFormatter('%m/%y'))

# use matplotlib's auto date styling
fig.autofmt_xdate()

# disable minor ticks
plt.minorticks_off()

manual date ticks

tdy
  • 36,675
  • 19
  • 86
  • 83
  • 2
    Thanks for sharing on how to update the major tick interval. Super helpful. I just updated the question as I realized now that the year `71` is oddly showing in x-axis, rather than the current year 2020 or 2021... – Fiori Mar 26 '21 at 02:04
  • 2
    @FjoriShemaj - quick fix: `ax.plot(df['month'], df['total_outbounds'], label='Total Email Outbounds on LE Change')` and `plt.legend()`. – BigBen Mar 26 '21 at 02:10
  • 1
    Hmm yeah I guess there's some bug in dataframe plotting. `ax.plot` fixes it on my end too. Answer updated. – tdy Mar 26 '21 at 02:15
  • 2
    I think matplotlib and pandas don't play very nicely when it comes to dates, more explanation [here](https://stackoverflow.com/a/44214830/9245853). Another option is to add `x_compat=True` if using `df.plot`. – BigBen Mar 26 '21 at 02:22
0

I also had this issue. Finally fixed it and hope my little experience can help you here, and hope this can be more clear.

The reason causing this is that your 'dates' inside your [month] column are strings, not Datetime. Then the Dateformatter don't recognise the 'dates' in the way you want.

So what you need to do first is to transform the format of the 'dates' in your [month] column into Datetime objects. To do this, simply use:

df['month'] = pd.to_datetime(df['month'])

(please be aware that this line of code may be stoped if you set xlim using Matplotlib 3.4.2, but works fine using Matplotlib 3.3.0 )

then use this transformed df['month'] as x-axis to plot (for exp):

 fig, ax = plt.subplots(figsize=(12, 12))

 ax.plot(
    df['month'],
    df['total_outbounds']
    )

Then you can add the formatting (for exp):

ax.xaxis.set_major_formatter(mdates.DateFormatter("%b, %Y"))

Then everything just worked out, at lest on my Mac.

Dharman
  • 30,962
  • 25
  • 85
  • 135