Reputation: 65
I want to make a categorical plot in python to represent the range of several variables. I thought maybe I would use a bar plot and set ranges for the bars. Here is my bar plot
import matplotlib.pyplot as plt
import numpy as np
data = {'a':.3, 'b': .3, 'c': .3, 'd': .1,'e':.1,'f':.1}
names = list(data.keys())
values = list(data.values())
plt.bar(names,values)
plt.show()
Barplot produced from given code:
Please tell me how set the value of the bars to something like
range(.3,.4)
. In other words, I want the bars to go from say (.3 to .4 to represent a range) instead of (0 to .3 the way it currently is).
I know using a barplot to represent a range is odd, and if someone has another way for me to do this please add your code. I don't really care as long as I get a plot which represents ranges of at least 6 variables in which I can easily and manually change the value of the ranges.
Upvotes: 6
Views: 13589
Reputation: 2993
Updated answer
To solve the issue with axvline
, the ratio of width (pixels) versus the range has to be taken into account. I feel that this is a hack.
Therefore, here is a solution that uses axvspan
.
import numpy as np
from matplotlib import pyplot as plt
data = {'a':(0,.3), 'b': (0.2,.3), 'c': (.1,.3), 'd': (0.3,0.4),'e':(.1,.2),'f':(.1,.4)}
width = 0.5 # adjust to your liking
fig, ax = plt.subplots()
for i, values in enumerate(data.values()):
ymin, ymax = values
ax.axvspan(xmin=i-width/2, xmax=i+width/2, ymin=ymin,ymax=ymax)
# to illustrate that ranges are properly drawn
ax.grid(True)
#add ticks
ax.set_xticks(np.arange(0,len(data)))
ax.set_xticklabels(data.keys())
Output:
Original answer
Another option would be to use axvline
:
from matplotlib import pyplot as plt
data = {'a':(0,.3), 'b': (0.2,.3), 'c': (.1,.3), 'd': (0.3,0.4),'e':(.1,.2),'f':(.1,.4)}
for key, values in data.items():
ymin, ymax = values
plt.axvline(x=key, ymin=ymin, ymax=ymax, lw=5)
Output:
By adjusting lw
you can approach a bar plot if required.
Upvotes: 3
Reputation: 2740
One approach would be to use a LineCollection
and set the linewidth to resemble a bar plot.
To use a LineCollection
you need to provide a set of x values that plot each range provided in data
. To create the y values associated with your range, I used np.arange
. Since np.arange
can only count integers, I multiplied each value in data
10 and divided the result by 10 to get back to the input data.
data = {'a':(.3,.4), 'b': (.3,.4), 'c': (.3,.4), 'd': (0,.1),'e':(0,.1),'f':(0,.1)}
names = list(data.keys())
values = list(data.values())
values = [np.arange(a[0]*10, (a[1]+0.1)*10,1)/10 for a in values]
xs = [np.ones(a.shape) for a in values]
xs = [i*a for i,a in zip(range(len(xs)), xs)]
verts = []
for x,y in zip(xs, values):
verts.append(list(zip(x.tolist(), y.tolist())))
lc = LineCollection(verts, linewidths=40)
fig,ax = plt.subplots()
ax.add_collection(lc)
ax.set_xlim(-0.5,len(values) )
plt.xticks(np.arange(len(values)), names)
Upvotes: 3