如何使用 Python 和 Matplotlib 将一个子图的视觉宽度设置为等于另一个子图的宽度?第一个图具有固定的纵横比和来自 imshow 的方形像素。然后我想在其下方放置一个线图,但我无法这样做并使所有内容对齐。
我相当确定解决方案涉及关于此 Transform Tutorial 的信息页。我试过使用 fig.transFigure、ax.transAxes、ax.transData 等,但没有成功。我需要在上面板中找到轴的宽度和高度以及偏移量,然后能够在下面板中设置轴的宽度、高度和偏移量。不应包含轴标签和刻度等或更改对齐方式。
例如下面的代码
fig = plt.figure(1)
fig.clf()
data = np.random.random((3,3))
xaxis = np.arange(0,3)
yaxis = np.arange(0,3)
ax = fig.add_subplot(211)
ax.imshow(data, interpolation='none')
c = ax.contour(xaxis, yaxis, data, colors='k')
ax2 = fig.add_subplot(212)
最佳答案
matplotlib 轴的轮廓由三件事控制:
- 图中轴的边界框(由子图规范或特定范围控制,例如
fig.add_axes([left, bottom, width, height])
。轴限制(不是计数刻度标签)将始终在此框内。 adjustable
参数控制是否通过更改数据限制或轴“框”的形状来适应限制或纵横比的变化。这可以是"datalim"
、"box"
或"box-forced"
。 (后者用于共享轴。)- 轴限制和纵横比。对于具有固定纵横比的绘图,轴框或数据限制(取决于
adjustable
)将更改以保持指定的纵横比。纵横比指数据坐标,不直接指坐标轴的形状。
对于最简单的情况:
import numpy as np
import matplotlib.pyplot as plt
fig, axes = plt.subplots(nrows=2)
data = np.random.random((3,3))
xaxis = np.arange(0,3)
yaxis = np.arange(0,3)
axes[0].imshow(data, interpolation='none')
c = axes[0].contour(xaxis, yaxis, data, colors='k')
axes[1].set_aspect(1)
plt.show()
共享轴
但是,如果您想确保它无论如何都保持相同的形状,并且您可以接受两个具有相同数据限制的图,您可以这样做:
import numpy as np
import matplotlib.pyplot as plt
fig, axes = plt.subplots(nrows=2), sharex=True, sharey=True)
plt.setp(axes.flat, adjustable='box-forced')
data = np.random.random((5,3))
xaxis = np.arange(0,3)
yaxis = np.arange(0,5)
axes[0].imshow(data, interpolation='none')
c = axes[0].contour(xaxis, yaxis, data, colors='k')
axes[1].plot([-0.5, 2.5], [-0.5, 4.5])
axes[1].set_aspect(1)
plt.show()
但是,您可能会注意到这看起来不太正确。这是因为根据我们绘制事物的顺序,第二个子图控制着第一个子图的范围。
基本上,对于共享轴,我们最后绘制的任何内容都将控制初始范围,因此如果我们只是交换我们绘制的顺序:
import numpy as np
import matplotlib.pyplot as plt
fig, axes = plt.subplots(nrows=2, sharex=True, sharey=True)
plt.setp(axes.flat, adjustable='box-forced')
data = np.random.random((5,3))
xaxis = np.arange(0,3)
yaxis = np.arange(0,5)
axes[1].plot([-0.5, 2.5], [-0.5, 4.5])
axes[1].set_aspect(1)
axes[0].imshow(data, interpolation='none')
c = axes[0].contour(xaxis, yaxis, data, colors='k')
plt.show()
当然,如果您不关心所链接图的交互式缩放/平移,您可以完全跳过共享轴,而只是为了:
import numpy as np
import matplotlib.pyplot as plt
fig, axes = plt.subplots(nrows=2)
data = np.random.random((5,3))
xaxis = np.arange(0,3)
yaxis = np.arange(0,5)
axes[0].imshow(data, interpolation='none')
c = axes[0].contour(xaxis, yaxis, data, colors='k')
axes[1].plot([-0.5, 2.5], [-0.5, 4.5])
# Copy extents and aspect from the first axes...
axes[1].set_aspect(axes[0].get_aspect())
axes[1].axis(axes[0].axis())
plt.show()
非共享轴
如果您不希望两个轴具有相同的数据范围,可以强制它们具有相同的大小(但如果您交互式缩放,它们将不会链接)。为此,您需要根据第二个图的范围和第一个图的范围/纵横比来计算第二个图的纵横比。
import numpy as np
import matplotlib.pyplot as plt
fig, axes = plt.subplots(nrows=2)
data = np.random.random((3,3))
xaxis = np.arange(0,3)
yaxis = np.arange(0,3)
axes[0].imshow(data, interpolation='none')
c = axes[0].contour(xaxis, yaxis, data, colors='k')
axes[1].plot(np.linspace(0, 10, 100), np.random.normal(0, 1, 100).cumsum())
# Calculate the proper aspect for the second axes
aspect0 = axes[0].get_aspect()
if aspect0 == 'equal':
aspect0 = 1.0
dy = np.abs(np.diff(axes[1].get_ylim()))
dx = np.abs(np.diff(axes[1].get_xlim()))
aspect = aspect0 / (float(dy) / dx)
axes[1].set_aspect(aspect)
plt.show()
关于Python Matplotlib 线图与轮廓/imshow 对齐,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26985210/