Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Matplotlib bar chart negative values below x-axis

I'm new to using Matplotlib. I'm trying to build a chart where values can also be negative. Using the generic graph from matplotlib

import matplotlib.pyplot as plt; plt.rcdefaults()
import numpy as np
import matplotlib.pyplot as plt

objects = ('Python', 'C++', 'Java', 'Perl', 'Scala', 'Lisp')
y_pos = np.arange(len(objects))
performance = [10,8,6,-4,2,1]

plt.bar(y_pos, performance, align='center', alpha=0.5)
plt.xticks(y_pos, objects)
plt.ylabel('Usage')
plt.title('Programming language usage')

plt.show()

This produces

enter image description here

However, I would like to use x-axis as y=0 line instead of having separate y=0. So for any negative values, it would appear below x-axis and for positive values, it will appear above x-axis.

It would somehow look like this.

enter image description here

I've managed to get rid of the surrounding lines and values on y-axis. Need to know how to make the x-axis the y=0 line.

Any help would be appreciated.

Thank you so much in advance.

like image 333
joo hwan kwon Avatar asked Mar 04 '20 05:03

joo hwan kwon


1 Answers

From here it's reasonably straightforward by accessing the axes object and modifying the spines, you just have to expose the Axes object first with the plt.gca() method.

The downside here is that getting the xticklabels how you've put them is a bit trickier, but is just a case of placing the relevant text on the Axes and then repeating that for the xlabel. You could always try using the labelpad argument for plt.xlabel() but I've not really played much with that.

import matplotlib.pyplot as plt 
plt.rcdefaults()
import numpy as np
import matplotlib.pyplot as plt

objects = ('Python', 'C++', 'Java', 'Perl', 'Scala', 'Lisp')
y_pos = np.arange(len(objects))
performance = [10,8,6,-4,2,1]

plt.bar(y_pos, performance, align='center', alpha=0.5)
# Get the axes object
ax = plt.gca()
# remove the existing ticklabels
ax.set_xticklabels([])
# remove the extra tick on the negative bar
ax.set_xticks([idx for (idx, x) in enumerate(performance) if x > 0])
ax.spines["bottom"].set_position(("data", 0))
ax.spines["top"].set_visible(False)
ax.spines["right"].set_visible(False)
# placing each of the x-axis labels individually
label_offset = 0.5
for language, (x_position, y_position) in zip(objects, enumerate(performance)):
    if y_position > 0:
        label_y = -label_offset
    else:
        label_y = y_position - label_offset
    ax.text(x_position, label_y, language, ha="center", va="top")
# Placing the x-axis label, note the transformation into `Axes` co-ordinates
# previously data co-ordinates for the x ticklabels
ax.text(0.5, -0.05, "Usage", ha="center", va="top", transform=ax.transAxes)

plt.show()

Result:

bar plot output from code above

like image 154
Andrew Avatar answered Sep 20 '22 17:09

Andrew