0

In the following code snippet, I want to append a percentage sign to all Y axis tick labels of a plot:

import matplotlib as mpl
import pandas as pd
from matplotlib import pyplot as plt
print mpl.__version__, mpl.get_backend()

df = pd.DataFrame({'a': [10, 40], 'b': [20, 30]})
ax = df.plot(kind='bar', title='Plot of Percentage')
plt.draw()
ax.set_yticklabels([x.get_text() + '%' for x in ax.get_yticklabels()])
ax.get_figure().savefig('test.png', bbox_inches='tight')

In python 2.7.13 + matplotlib 1.5.3, using backend Qt5Agg, ax.get_yticklabels() returns a list of empty Text objects, resulting in the following output image:

enter image description here

The above code snippet works correctly under python 2.6.9 + matplotlib 1.4.2 + Qt4Agg backend and under python 2.6.6 + matplotlib 1.3.1 + TkAgg backend.

Possibly related to: https://github.com/matplotlib/matplotlib/issues/6103/

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Libo Yin
  • 15
  • 4
  • It is not the optimal solution, but it works. Change plt.draw () to plt.show (), after closing the window save the image with the modified labels – eyllanesc Jan 05 '17 at 23:35
  • @eyllanesc: Thanks for inline-ing the image. I tried to replace the sivefig line with plt.show(), but it doesn't seem to work. Is there any other environment that I missed? – Libo Yin Jan 06 '17 at 00:07
  • import matplotlib as mpl import pandas as pd from matplotlib import pyplot as plt print(mpl.__version__, mpl.get_backend()) df = pd.DataFrame({'a': [10, 40], 'b': [20, 30]}) ax = df.plot(kind='bar', title='Plot of Percentage') plt.show() ax.set_yticklabels([x.get_text() + '%' for x in ax.get_yticklabels()]) ax.get_figure().savefig('test.png', bbox_inches='tight') – eyllanesc Jan 06 '17 at 00:12
  • @eyllanesc: Yes, it worked. Many thanks! – Libo Yin Jan 06 '17 at 00:26
  • A walk-around: Use `ax.yaxis.get_ticklocs()` to extract the numbers from the yticks first, and then use `ax.yaxis.set_ticklabels()` to set the new tick labels with the percentage sign. Thanks @WuSun for the contribution. – Libo Yin Jan 06 '17 at 00:29
  • I have placed my answer, and as I help you, please mark it as correct. – eyllanesc Jan 06 '17 at 00:33

1 Answers1

0

The ticklabels are not actually filled until the canvas is completely drawn. Since the ticklabels are determined by a matplotlib.ticker.***Formatter, the best solution is of course not trying to change the ticklabels themselves but to use a convenient Formatter.

Here a FuncFormatter seems a good choice.

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

df = pd.DataFrame({'a': [10, 40], 'b': [20, 30]})
ax = df.plot(kind='bar', title='Plot of Percentage')

func = lambda x, pos: "{} %".format(x)
ax.yaxis.set_major_formatter(matplotlib.ticker.FuncFormatter(func))
plt.show()

enter image description here

There is no need to draw anything and this solution is also independent on backends.

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712