Problem with inconsistent barplot: small bars missing

Having a problem with small bars disappearing…
The first plot has six bars for ‘75573’. The second and third plots have only one bar visible. The only difference being deletion of the underscore in the xlabel and no rotation of the xlabel. Additionally, if I save the first plot with plt.save_fig() at high resolution, the bar are missing as in the 2nd and 3rd plots. Honestly, that’s my real problem…
Thanks in advance…

import pandas as pd

dict={‘2012’: {‘75571’: 2643.0, ‘75572’: 4459.0, ‘75573’: 30.0, ‘75574’: 31456.0},
‘2013’: {‘75571’: 2833.0, ‘75572’: 6192.0, ‘75573’: 13.0, ‘75574’: 31473.0},
‘2014’: {‘75571’: 4548.0, ‘75572’: 8290.0, ‘75573’: 41.0, ‘75574’: 33045.0},
‘2015’: {‘75571’: 7501.0, ‘75572’: 10031.0, ‘75573’: 40.0, ‘75574’: 35093.0},
‘2016’: {‘75571’: 9027.0, ‘75572’: 13310.0, ‘75573’: 409.0, ‘75574’: 41982.0},
‘2017’: {‘75571’: 11607.0, ‘75572’: 15535.0, ‘75573’: 75.0, ‘75574’: 48975.0}}

df=pd.DataFrame(dict)
df.index.name=‘AAAA_AAAA’ #NOTE UNDERSCORE
df.plot(kind=‘bar’,rot=70) #NOTE ROTATE

df=pd.DataFrame(dict)
df.index.name=‘AAAA AAAA’ #NO UNDERSCOE
ax=df.plot(kind=‘bar’,rot=70)

df=pd.DataFrame(dict)
df.index.name=‘AAAA_AAAA’ #NOTE UNDERSCORE
df.plot(kind=‘bar’) #NOTE NO ROTATE

Your y-range in 50,000 and if we (over) estimate that the Axes is 500 pixels high, then we should have 1,000 data units / pixel. At that scale the bars in 75573 should be “invisible” as they are only a fraction of a pixel high and when we are rasterizing, the smallest amount we can color is 1 pixel. I am inclined to think that the bug here is that you ever do see the bars.

We use some pixel snapping logic when drawing (if a line is going to go between two pixels, which when anti-aliased will result in each pixel being colored a little bit we will “snap” the line to one or the other to make the lines look “sharp”). I suspect what is happening is that in some cases the rectangle is getting it’s edges snapped away from each other making the rectangle bigger than it should be.

I suspect you are using the inline backend in a notebook? If so, it uses bounding_box='tight' when saving the png. This “shrink wraps” the figure so when you rotate the labels the size of the overall figure changes, which it turn affects what pixels the rectangle falls into and changes the “snapping” artifact. I suspect something similar happened when you saved at a high dpi. Most image viewers will down-sample the image to show to you (if there are more pixels in the image that available to the viewer on your screen), you can also have aliasing issues from that as well.

I suggest:

  • using a vector backend (which defers this snapping / aliasing issue to the renderer rather than Matplotlib taking care of it in Agg)
  • passing edgecolor='k' which will wrap your bars in a black edge but will distort the bar size
  • use a log scale on the y-axis if you need to be able to see data that spans 5 orders of magnitude.