How to draw a rectangular on subplotted figure using matlibplot in python?

Viewed 302

I successfully draw a subplot of the histogram figure contains three subplots as shown in the figure below. enter image description here

The question is that I need to draw dashed rectangular covers the three subplots at a specific area of the figure to show the importance of that covered part as shown in the below figure.

enter image description here

I tried to use some online codes using "add-patch", however, the rectangular appears on one subplot and compress the bars of that subplot.

ax0.add_patch(patches.Rectangle((147,100),100,300,linewidth=1,edgecolor='r',facecolor='none'))

enter image description here

This is the code:

bins =[50, 100,150, 200,250,300,350]
y= [55,75,85,90,120,110,115,140,145,160,170,181,185,175,190,210,220,250,280,290,320]
fig, (ax0, ax1, ax2) = plt.subplots(nrows=3)
colors = ['r','k','b']

ax0.hist(y,  bins, histtype='bar',   stacked=True,   rwidth=0.8, color = colors[0])
ax1.hist(y,  bins, histtype='bar',   stacked=True,  rwidth=0.8, color = colors[1])
ax2.hist(y,  bins, histtype='bar',   stacked=True,  rwidth=0.8, color = colors[2])
fig.subplots_adjust(hspace=0.6)
ax0.add_patch(patches.Rectangle((147, 100), 100, 300, linewidth=1, edgecolor='r', facecolor='none'))

plt.show()
1 Answers

I would use transforms (see Transformation Tutorial) to generate coordinates that are partly aligned to the data in the x direction, and to the figure in the y direction.

bins =[50, 100,150, 200,250,300,350]
y= [55,75,85,90,120,110,115,140,145,160,170,181,185,175,190,210,220,250,280,290,320]
fig, (ax0, ax1, ax2) = plt.subplots(nrows=3, sharex=True)
colors = ['r','k','b']

ax0.hist(y,  bins, histtype='bar',   stacked=True,   rwidth=0.8, color = colors[0])
ax1.hist(y,  bins, histtype='bar',   stacked=True,  rwidth=0.8, color = colors[1])
ax2.hist(y,  bins, histtype='bar',   stacked=True,  rwidth=0.8, color = colors[2])
fig.subplots_adjust(hspace=0.6)

xmin, xmax = 150,250
trans = matplotlib.transforms.blended_transform_factory(ax0.transData, fig.transFigure)
r = matplotlib.patches.Rectangle(xy=(xmin,0), width=xmax-xmin, height=1, transform=trans,
                                 fc='none', ec='b', lw=2)
fig.add_artist(r)

plt.show()

enter image description here

EDIT If you want to extend the box only to the top of the top axes, and to the bottom of the bottom axes, you can also use transforms to get those positions in figure coordinates:

bins =[50, 100,150, 200,250,300,350]
y= [55,75,85,90,120,110,115,140,145,160,170,181,185,175,190,210,220,250,280,290,320]
fig, (ax0, ax1, ax2) = plt.subplots(nrows=3, sharex=True)
colors = ['r','k','b']

ax0.hist(y,  bins, histtype='bar',   stacked=True,   rwidth=0.8, color = colors[0])
ax1.hist(y,  bins, histtype='bar',   stacked=True,  rwidth=0.8, color = colors[1])
ax2.hist(y,  bins, histtype='bar',   stacked=True,  rwidth=0.8, color = colors[2])
fig.subplots_adjust(hspace=0.6)

xmin, xmax = 150,250
_,top = fig.transFigure.inverted().transform(ax0.transAxes.transform([0,1]))
_,bottom = fig.transFigure.inverted().transform(ax2.transAxes.transform([0,0]))
trans = matplotlib.transforms.blended_transform_factory(ax0.transData, fig.transFigure)
r = matplotlib.patches.Rectangle(xy=(xmin,bottom), width=xmax-xmin, height=top-bottom, transform=trans,
                                 fc='none', ec='C0', lw=5)
fig.add_artist(r)

plt.show()

enter image description here

Related