Reputation: 560
I'm trying to make a plot using matplotlib that resembles the following:
However, I'm not quite sure which type of graph to use. My data has the following form, where start x position is a positive value greater or equal to 0:
<item 1><start x position><end x position>
<item 2><start x position><end x position>
Looking at the docs, I see that there is barh and errorbar, but I'm not sure if its possible to use barh with a start offset. What would be the best method to use, given my type of data? I'm not that familiar with the library, so I was hoping to get some insight.
Upvotes: 3
Views: 2334
Reputation: 25053
As far as I know, the most direct way to do what you want requires that you directly draw your rectangles on the matplotlib
canvas using the patches
module of matplotlib
A simple implementation follows
import matplotlib.pyplot as plt
import matplotlib.patches as patches
def plot_rect(data, delta=0.4):
"""data is a dictionary, {"Label":(low,hi), ... }
return a drawing that you can manipulate, show, save etc"""
yspan = len(data)
yplaces = [.5+i for i in range(yspan)]
ylabels = sorted(data.keys())
fig = plt.figure()
ax = fig.add_subplot(111)
ax.set_yticks(yplaces)
ax.set_yticklabels(ylabels)
ax.set_ylim((0,yspan))
# later we'll need the min and max in the union of intervals
low, hi = data[ylabels[0]]
for pos, label in zip(yplaces,ylabels):
start, end = data[label]
ax.add_patch(patches.Rectangle((start,pos-delta/2.0),end-start,delta))
if start<low : low=start
if end>hi : hi=end
# little small trick, draw an invisible line so that the x axis
# limits are automatically adjusted...
ax.plot((low,hi),(0,0))
# now get the limits as automatically computed
xmin, xmax = ax.get_xlim()
# and use them to draw the hlines in your example
ax.hlines(range(1,yspan),xmin,xmax)
# the vlines are simply the x grid lines
ax.grid(axis='x')
# eventually return what we have done
return ax
# this is the main script, note that we have imported pyplot as plt
# the data, inspired by your example,
data = {'A':(1901,1921),
'B':(1917,1935),
'C':(1929,1948),
'D':(1943,1963),
'E':(1957,1983),
'F':(1975,1991),
'G':(1989,2007)}
# call the function and give its result a name
ax = plot_rect(data)
# so that we can further manipulate it using the `axes` methods, e.g.
ax.set_xlabel('Whatever')
# finally save or show what we have
plt.show()
The result of our sufferings has been shown in the first paragraph of this post...
Let's say that you feel that blue is a very dull color...
The patches
you've placed in your drawing are accessible as a property (aptly named patches
...) of the drawing and modifiable too, e.g.,
ax = plot_rect(data)
ax.set_xlabel('Whatever')
for rect in ax.patches:
rect.set(facecolor=(0.9,0.9,0.2,1.0), # a tuple, RGBA
edgecolor=(0.6,0.2,0.3,1.0),
linewidth=3.0)
plt.show()
In my VH opinion, a custom plotting function should do the least indispensable to characterize the plot, as this kind of post-production is usually very easy in matplotlib
.
Upvotes: 5