Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I invert the bar size in matplotlib pyplot bar charts?

I'm trying to set up an inverted axis bar chart such that smaller numbers have bigger bars, and those bars start from the top of the bar chart. Ideally, my y-axis would vary from 10e-10 on the bottom to 10e-2 on the top, and would look similar to this excel plot: enter image description here

In presenting this data, getting to a lower number is better, so I was hoping to represent this with bigger bars, rather than the absence of bars.

Inverting the y-axis limits makes the bars start from the top, but it does not solve my problem, since the smaller bars are still associated with the smaller numbers. Is there some way to move the origin, and specify that bars should be drawn from the origin to the appropriate tick on the axis?

The data and code are really not so important here, but here is an excerpt:

plt.rcParams['xtick.bottom'] = plt.rcParams['xtick.labelbottom'] = False
plt.rcParams['xtick.top'] = plt.rcParams['xtick.labeltop'] = True
barVals = [ 10**(-x) for x in range(10) ]
ticks = [x for x in range(10)]
plt.bar(ticks, barVals)
plt.yscale('log')
plt.ylim([1e-2, 1e-10])
#plt.axes().spines['bottom'].set_position(('data', 0))
plt.show()

enter image description here

The resultant plot has bigger bars for bigger numbers and smaller bars for smaller numbers. I could instead plot the difference between each value and the maximum, but I was hoping there was some built-in way to do this in matplotlib/pyplot.

Using matlab, the functionality I am looking for is setting the axis base value:

b = bar(ticks, barValues);
b(1).BaseValue = 1e0;
like image 630
Onofog Avatar asked Nov 19 '25 12:11

Onofog


1 Answers

Given the way a normal log-scaling of the axis works, I think your best bet is to scale the data manually, and adjust the labels to match. The following is a simple example to get you started, using the OO API:

data = 10.0**np.arange(-2, -7, -1)
plot_data = np.log10(data)

fig, ax = plt.subplots()
ax.bar(np.arange(data.size) + 1, plot_data)

You can set the ticks manually, but I would recommend using a Formatter:

from matplotlib.ticker import StrMethodFormatter
...
ax.yaxis.set_major_formatter(StrMethodFormatter('$10^{{{x}}}$'))

This particular Formatter accepts a template string suitable for str.format and interpolates it with the tick value bound to the name x. If you only wanted to display the integer portion of the exponent, you could initialize it as

 StrMethodFormatter('$10^{{{x:.0f}}}$')

The symbols $...$ tell matplotlib that the string is LaTeX, and {{...}} are escaped curly braces to tell LaTeX to group the entire exponent as a superscript.

To adjust the limits of your chart:

ax.set_ylim([plot_data.min() - 0.5, -1])
like image 171
Mad Physicist Avatar answered Nov 22 '25 01:11

Mad Physicist



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!