Matplotlib 辅助/双轴 - 用圆圈和箭头标记 - 用于黑白 (bw) 发布
Matplotlib secondary / dual axis - marking with circle and arrow - for black and white (bw) publishing
通常两个y轴用不同的颜色分开,如下例所示。
对于出版物,通常需要使其易于区分,即使是黑白印刷也是如此。
这通常是通过围绕一条线绘制圆圈来完成的,这些圆圈在相应轴的方向上有一个箭头。
如何使用 matplotlib 实现这一点?或者有没有更好的方法来实现没有这些圆圈的黑白可读性?
来自 matplotlib.org 的代码:
import numpy as np
import matplotlib.pyplot as plt
# Create some mock data
t = np.arange(0.01, 10.0, 0.01)
data1 = np.exp(t)
data2 = np.sin(2 * np.pi * t)
fig, ax1 = plt.subplots()
color = 'tab:red'
ax1.set_xlabel('time (s)')
ax1.set_ylabel('exp', color=color)
ax1.plot(t, data1, color=color)
ax1.tick_params(axis='y', labelcolor=color)
ax2 = ax1.twinx() # instantiate a second axes that shares the same x-axis
color = 'tab:blue'
ax2.set_ylabel('sin', color=color) # we already handled the x-label with ax1
ax2.plot(t, data2, color=color)
ax2.tick_params(axis='y', labelcolor=color)
fig.tight_layout() # otherwise the right y-label is slightly clipped
plt.show()
您可以使用 matplotlib 的 axes annotate to draw arrows to the y-axes. You will need to find the points in the plot where the arrows should start. However, this does not plot circles around lines. If you really want to plot a circle, you could use plt.scatter or plt.Circle 绘制一个覆盖相关区域的适当圆。
import numpy as np
import matplotlib.pyplot as plt
# Create some mock data
t = np.arange(0.01, 10.0, 0.01)
data1 = np.exp(t)
data2 = np.sin(2 * np.pi * t)
fig, ax1 = plt.subplots()
color = 'tab:red'
ax1.set_xlabel('time (s)')
ax1.set_ylabel('exp', color=color)
ax1.plot(t, data1, color=color)
ax1.tick_params(axis='y', labelcolor=color)
ax1.annotate('', xy=(7, 1096), xytext=(-0.5, 1096), # start the arrow from x=7 and draw towards primary y-axis
arrowprops=dict(arrowstyle="<-", color=color))
ax2 = ax1.twinx() # instantiate a second axes that shares the same x-axis
color = 'tab:blue'
ax2.set_ylabel('sin', color=color) # we already handled the x-label with ax1
ax2.plot(t, data2, color=color)
ax2.tick_params(axis='y', labelcolor=color)
# plt.arrow()
ax2.annotate('', xy=(6,0), xytext=(10.4, 0), # start the arrow from x=6 and draw towards secondary y-axis
arrowprops=dict(arrowstyle="<-", color=color))
fig.tight_layout() # otherwise the right y-label is slightly clipped
plt.show()
以下是示例输出图。
编辑: 以下是您请求的圈子的片段。我用过plt.scatter
.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Circle
# Create some mock data
t = np.arange(0.01, 10.0, 0.01)
data1 = np.exp(t)
data2 = np.sin(2 * np.pi * t)
fig, ax1 = plt.subplots()
color = 'tab:red'
ax1.set_xlabel('time (s)')
ax1.set_ylabel('exp', color=color)
ax1.plot(t, data1, color=color)
ax1.tick_params(axis='y', labelcolor=color)
ax1.annotate('', xy=(7, 1096), xytext=(-0.5, 1096), # start the arrow from x=7 and draw towards primary y-axis
arrowprops=dict(arrowstyle="<-", color=color))
# circle1 = Circle((5, 3000), color='r')
# ax1.add_artist(circle1)
plt.scatter(7, 1096, s=100, facecolors='none', edgecolors='r')
ax2 = ax1.twinx() # instantiate a second axes that shares the same x-axis
color = 'tab:blue'
ax2.set_ylabel('sin', color=color) # we already handled the x-label with ax1
ax2.plot(t, data2, color=color)
ax2.tick_params(axis='y', labelcolor=color)
# plt.arrow()
ax2.annotate('', xy=(6.7,0), xytext=(10.5, 0), # start the arrow from x=6.7 and draw towards secondary y-axis
arrowprops=dict(arrowstyle="<-", color=color))
plt.scatter(6,0, s=2000, facecolors='none', edgecolors=color)
fig.tight_layout() # otherwise the right y-label is slightly clipped
plt.savefig('fig')
plt.show()
这是示例输出。
此方法基于此answer。它使用arc,可以这样配置:
import matplotlib.pyplot as plt
from matplotlib.patches import Arc
# Generate example graph
fig = plt.figure(figsize=(5, 5))
ax = fig.add_subplot(1, 1, 1)
ax.plot([1,2,3,4,5,6], [2,4,6,8,10,12])
# Configure arc
center_x = 2 # x coordinate
center_y = 3.8 # y coordinate
radius_1 = 0.25 # radius 1
radius_2 = 1 # radius 2 >> for cicle: radius_2 = 2 x radius_1
angle = 180 # orientation
theta_1 = 70 # arc starts at this angle
theta_2 = 290 # arc finishes at this angle
arc = Arc([center_x, center_y],
radius_1,
radius_2,
angle = angle,
theta1 = theta_1,
theta2=theta_2,
capstyle = 'round',
linestyle='-',
lw=1,
color = 'black')
# Add arc
ax.add_patch(arc)
# Add arrow
x1 = 1.9 # x coordinate
y1 = 4 # y coordinate
length_x = -0.5 # length on the x axis (negative so the arrow points to the left)
length_y = 0 # length on the y axis
ax.arrow(x1,
y1,
length_x,
length_y,
head_width=0.1,
head_length=0.05,
fc='k',
ec='k',
linewidth = 0.6)
结果如下图:
通常两个y轴用不同的颜色分开,如下例所示。
对于出版物,通常需要使其易于区分,即使是黑白印刷也是如此。
这通常是通过围绕一条线绘制圆圈来完成的,这些圆圈在相应轴的方向上有一个箭头。
如何使用 matplotlib 实现这一点?或者有没有更好的方法来实现没有这些圆圈的黑白可读性?
来自 matplotlib.org 的代码:
import numpy as np
import matplotlib.pyplot as plt
# Create some mock data
t = np.arange(0.01, 10.0, 0.01)
data1 = np.exp(t)
data2 = np.sin(2 * np.pi * t)
fig, ax1 = plt.subplots()
color = 'tab:red'
ax1.set_xlabel('time (s)')
ax1.set_ylabel('exp', color=color)
ax1.plot(t, data1, color=color)
ax1.tick_params(axis='y', labelcolor=color)
ax2 = ax1.twinx() # instantiate a second axes that shares the same x-axis
color = 'tab:blue'
ax2.set_ylabel('sin', color=color) # we already handled the x-label with ax1
ax2.plot(t, data2, color=color)
ax2.tick_params(axis='y', labelcolor=color)
fig.tight_layout() # otherwise the right y-label is slightly clipped
plt.show()
您可以使用 matplotlib 的 axes annotate to draw arrows to the y-axes. You will need to find the points in the plot where the arrows should start. However, this does not plot circles around lines. If you really want to plot a circle, you could use plt.scatter or plt.Circle 绘制一个覆盖相关区域的适当圆。
import numpy as np
import matplotlib.pyplot as plt
# Create some mock data
t = np.arange(0.01, 10.0, 0.01)
data1 = np.exp(t)
data2 = np.sin(2 * np.pi * t)
fig, ax1 = plt.subplots()
color = 'tab:red'
ax1.set_xlabel('time (s)')
ax1.set_ylabel('exp', color=color)
ax1.plot(t, data1, color=color)
ax1.tick_params(axis='y', labelcolor=color)
ax1.annotate('', xy=(7, 1096), xytext=(-0.5, 1096), # start the arrow from x=7 and draw towards primary y-axis
arrowprops=dict(arrowstyle="<-", color=color))
ax2 = ax1.twinx() # instantiate a second axes that shares the same x-axis
color = 'tab:blue'
ax2.set_ylabel('sin', color=color) # we already handled the x-label with ax1
ax2.plot(t, data2, color=color)
ax2.tick_params(axis='y', labelcolor=color)
# plt.arrow()
ax2.annotate('', xy=(6,0), xytext=(10.4, 0), # start the arrow from x=6 and draw towards secondary y-axis
arrowprops=dict(arrowstyle="<-", color=color))
fig.tight_layout() # otherwise the right y-label is slightly clipped
plt.show()
以下是示例输出图。
编辑: 以下是您请求的圈子的片段。我用过plt.scatter
.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Circle
# Create some mock data
t = np.arange(0.01, 10.0, 0.01)
data1 = np.exp(t)
data2 = np.sin(2 * np.pi * t)
fig, ax1 = plt.subplots()
color = 'tab:red'
ax1.set_xlabel('time (s)')
ax1.set_ylabel('exp', color=color)
ax1.plot(t, data1, color=color)
ax1.tick_params(axis='y', labelcolor=color)
ax1.annotate('', xy=(7, 1096), xytext=(-0.5, 1096), # start the arrow from x=7 and draw towards primary y-axis
arrowprops=dict(arrowstyle="<-", color=color))
# circle1 = Circle((5, 3000), color='r')
# ax1.add_artist(circle1)
plt.scatter(7, 1096, s=100, facecolors='none', edgecolors='r')
ax2 = ax1.twinx() # instantiate a second axes that shares the same x-axis
color = 'tab:blue'
ax2.set_ylabel('sin', color=color) # we already handled the x-label with ax1
ax2.plot(t, data2, color=color)
ax2.tick_params(axis='y', labelcolor=color)
# plt.arrow()
ax2.annotate('', xy=(6.7,0), xytext=(10.5, 0), # start the arrow from x=6.7 and draw towards secondary y-axis
arrowprops=dict(arrowstyle="<-", color=color))
plt.scatter(6,0, s=2000, facecolors='none', edgecolors=color)
fig.tight_layout() # otherwise the right y-label is slightly clipped
plt.savefig('fig')
plt.show()
这是示例输出。
此方法基于此answer。它使用arc,可以这样配置:
import matplotlib.pyplot as plt
from matplotlib.patches import Arc
# Generate example graph
fig = plt.figure(figsize=(5, 5))
ax = fig.add_subplot(1, 1, 1)
ax.plot([1,2,3,4,5,6], [2,4,6,8,10,12])
# Configure arc
center_x = 2 # x coordinate
center_y = 3.8 # y coordinate
radius_1 = 0.25 # radius 1
radius_2 = 1 # radius 2 >> for cicle: radius_2 = 2 x radius_1
angle = 180 # orientation
theta_1 = 70 # arc starts at this angle
theta_2 = 290 # arc finishes at this angle
arc = Arc([center_x, center_y],
radius_1,
radius_2,
angle = angle,
theta1 = theta_1,
theta2=theta_2,
capstyle = 'round',
linestyle='-',
lw=1,
color = 'black')
# Add arc
ax.add_patch(arc)
# Add arrow
x1 = 1.9 # x coordinate
y1 = 4 # y coordinate
length_x = -0.5 # length on the x axis (negative so the arrow points to the left)
length_y = 0 # length on the y axis
ax.arrow(x1,
y1,
length_x,
length_y,
head_width=0.1,
head_length=0.05,
fc='k',
ec='k',
linewidth = 0.6)
结果如下图: