简体   繁体   English

Matplotlib - axvspan vs subplots

[英]Matplotlib - axvspan vs subplots

I'm writing a pythonic script for a coastal engineering application which should output, amongst other things, a figure with two subplots. 我正在为一个沿海工程应用程序编写一个pythonic脚本,除其他外,它应该输出一个包含两个子图的图形。

The problem is that I would like to shade a section of both subplots using plt.axvspan() but for some reason it only shades one of them. 问题是我想使用plt.axvspan()来遮蔽两个子图的一部分,但由于某种原因它只遮蔽其中一个。

Please find below an excerpt of the section of the code where I set up the plots as well as the figure that it's currently outputting (link after code). 请在下面找到我设置图表的代码部分的摘录以及它当前输出的图(代码后链接)。

Thanks for your help, and sorry if this is a rookie question (but it just happens that I am indeed a rookie in Python... and programming in general) but I couldn't find an answer for this anywhere else. 感谢您的帮助,对不起,如果这是一个菜鸟问题(但事实上我确实是Python中的新手...以及一般的编程)但我无法在其他任何地方找到答案。

Feel free to add any comments to the code. 随意添加任何注释代码。

# PLOTTING
# now we generate a figure with the bathymetry vs required m50 and another figure with bathy vs Hs

#1. Generate plots

fig = plt.figure() # Generate Figure
ax = fig.add_subplot(211) # add the first plot to the figure.
depth = ax.plot(results[:,0],results[:,1]*-1,label="Depth [mDMD]") #plot the first set of data onto the first set of axis.
ax2 = ax.twinx() # generate a secondary vertical axis with the same horizontal axis as the first
m50 = ax2.plot(results[:,0],results[:,6],"r",label="M50 [kg]") # plot the second set of data onto the second vertical axis
ax3 = fig.add_subplot(212) # generate the second subplot
hs = ax3.plot(results[:,0],results[:,2],"g",label="Hs(m)")

#Now we want to find where breaking starts to occur so we shade it on the plot.
xBreakingDistance = results[numpy.argmax(breakingIndex),0]

# and now we plot a box from the origin to the depth of breaking.

plt.axvspan(0,xBreakingDistance,facecolor="b",alpha=0.1) # this box is called a span in matplotlib (also works for axhspan)

# and then we write BREAKING ZONE in the box we just created

yLimits = ax.get_ylim() # first we get the range of y being plotted
yMiddle = (float(yLimits[1])-float(yLimits[0])) / 2 + yLimits[0] # then we calculate the middle value in y (to center the text)
xMiddle = xBreakingDistance / 2 # and then the middle value in x (to center the text)
#now we write BREAKING ZONE in the center of the box.
ax.text(xMiddle,yMiddle,"BREAKING ZONE",fontweight="bold",rotation=90,verticalalignment="center",horizontalalignment="center")

#FIGURE FORMATTING
ax.set_xlabel("Distance [m]") # define x label
ax.set_ylabel("Depth [mDMD]") # define y label on the first vertical axis (ax)
ax2.set_ylabel("M50 [kg]") # define y label on the second vertical axis (ax2)
ax.grid() # show grid
ax3.set_xlabel("Distance[m]") #define x label
ax3.set_ylabel("Hs[m]") # define y label
ax3.grid()
plt.tight_layout() # minimize subplot labels overlapping

# generating a label on a plot with 2 vertical axis is not very intuitive. Normally we would just write ax.label(loc=0)
combined_plots = depth+m50 #first we need to combine the plots in a vector
combined_labels = [i.get_label() for i in combined_plots] # and then we combine the labels
ax.legend(combined_plots,combined_labels,loc=0) # and finally we plot the combined_labels of the combined_plots
plt.savefig("Required M50(kg) along the trench.png",dpi=1000)
plt.close(fig)

Output Figure: 输出图:

By just calling plt.axvspan , you are telling matplotlib to create the axvspan on the currently active axes (ie in this case, the last one you created, ax3 ) 通过调用plt.axvspan ,您告诉matplotlib在当前活动的轴上创建axvspan (即在这种情况下,您创建的最后一个轴, ax3

You need to plot the axvspan on both of the axes you would like for it to appear on. 你需要在你希望它出现的两个轴上绘制axvspan In this case, ax and ax3 . 在这种情况下, axax3

So, you could do: 所以,你可以这样做:

ax.axvspan(0,xBreakingDistance,facecolor="b",alpha=0.1)    
ax3.axvspan(0,xBreakingDistance,facecolor="b",alpha=0.1)

or in one line: 或者在一行中:

[this_ax.axvspan(0,xBreakingDistance,facecolor="b",alpha=0.1) for this_ax in [ax,ax3]]

It's difficult to analyze your code and not being able to reproduce it. 分析代码并且无法重现代码很困难。 I advise you to build a minimal example. 我建议你建立一个最小的例子。 In any case notice that you are calling "plt.axvspan(" which is general call to the library. 在任何情况下,请注意您正在调用“plt.axvspan(”这是对库的一般调用。

You need to specifically state that you want this in both "ax" and "ax2" (i think). 你需要在“ax”和“ax2”(我认为)中明确说明你想要这个。

Also if you need more control consider using Patches (I don't know axvspan): 此外,如果您需要更多控制,请考虑使用补丁(我不知道axvspan):

import matplotlib.pyplot as plt
import matplotlib.patches as patches

fig1 = plt.figure()
ax1 = fig1.add_subplot(111, aspect='equal')
ax1.add_patch(
    patches.Rectangle(
        (0.1, 0.1),   # (x,y)
        0.5,          # width
        0.5,          # height
    )
)
fig1.savefig('rect1.png', dpi=90, bbox_inches='tight')

See that call to "ax1" in the example? 在示例中看到对“ax1”的调用? Just make something similar to yours. 只需制作类似于你的东西。 Or just add axvspan to each of your plots. 或者只是将axvspan添加到每个图中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM