0

I'm getting some overcrowding for the tick labels on the x-axis of a matplotlib chart, so I'm thinking to reduce the frequency at which the labels appear. There seems to be a few functions for this (multiplelocator, maxnlocator) but these just space the existing labels out, rather than skipping any actual labels. For example, if I run this

df = pd.DataFrame(columns=['bond 1','bond 2'],
                  index=[2017,2018,2019,2020,2021,2022])
df['bond 1'] = [4,5,6,6,5,4]
df['bond 2'] = [8,6,4,4,6,8]

fig,ax=plt.subplots(1)
ax = df.plot(ax=ax, kind='bar', colormap='copper')

locator = tick.MultipleLocator(base=2)
ax.xaxis.set_major_locator(locator)

Then I get this: enter image description here

In terms of format this looks great, but the data points are actually mis-labelled - where it says 2018 is actually the 2017 data, where it says 2020 is the 2021 data.

Could anyone let me know if there's any easy way to space the labels out without having them map onto the wrong data points?

Thanks!

Chris Harris
  • 177
  • 3
  • 9
  • I don't know about locators, but in [this answer](https://stackoverflow.com/a/20341184/2454357) there is a way how to do it. Adapting to your example: `for label in ax.xaxis.get_ticklabels()[1::2]:` and then `label.set_visible(False)`. – Thomas Kühn Jan 26 '18 at 06:18
  • @ThomasKühn: Thanks, that's actually a pretty good workaround. – Chris Harris Jan 26 '18 at 07:37
  • Ok, if that helps you, do you mind if I flag this as duplicate (even though it's not a `Locator` solution)? – Thomas Kühn Jan 26 '18 at 07:45
  • @ThomasKühn Yes, sure - whatever you think best. – Chris Harris Jan 26 '18 at 08:12
  • Possible duplicate of [Cleanest way to hide every nth tick label in matplotlib colorbar?](https://stackoverflow.com/questions/20337664/cleanest-way-to-hide-every-nth-tick-label-in-matplotlib-colorbar) – Thomas Kühn Jan 26 '18 at 08:17

1 Answers1

2

The pandas bar plot produces a plot where each bar is placed at a successive integer position, starting at 0. The locator in use is a FixedLocator, which stores those positions (0,1,2,3,...) and the formatter is a FixedFormatter that stores a ticklabel for each of those positions. If you now change the locator without changing the formatter things get out of sync. To avoid this, one needs to change both, the formatter and the locator. Since we do not have a good formatter to use in this case, we should rather stick to the FixedFormatter, which also implies to stick with the FixedLocator. We may still change the number of ticks for a FixedLocator and change the FixedFormatter to reflect this.

import matplotlib.pyplot as plt
from matplotlib import ticker 
import pandas as pd

df = pd.DataFrame(columns=['bond 1','bond 2'],
                  index=[2017,2018,2019,2020,2021,2022])
df['bond 1'] = [4,5,6,6,5,4]
df['bond 2'] = [8,6,4,4,6,8]

fig,ax=plt.subplots(1)
ax = df.plot(ax=ax, kind='bar', colormap='copper')

locator = ax.xaxis.get_major_locator()
locator.locs = locator.locs[::2]
formatter = ax.xaxis.get_major_formatter()
formatter.seq = formatter.seq[::2]

plt.show()
ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
  • 1
    @ThomasKühn Uhhh, I just saw that the solution would not work for the general case, there is some strange magic happening in calculating the number of ticks from `nbins`, which one would need to take care of. I therefore edited the answer. Of course now instead of `[::2]` one may use `[::N]` with N being any non-zero positive integer. – ImportanceOfBeingErnest Jan 26 '18 at 11:01
  • Thanks - that's very helpful and a clear explanation as well. – Chris Harris Jan 29 '18 at 07:11