使用 make_axes_locatable 和固定的 imshow 宽高比将颜色条添加到 matplotlib 轴
Adding colorbar to matplotlib axis with make_axes_locatable and fixed imshow aspect ratio
我正在尝试绘制一些数组数据并在轴的右侧添加一个颜色条,以匹配高度和设置的宽度。
首先生成一些数据。
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
data = np.random.rand(700, 400)
我有以下功能。
def plot_data(data, aspect, pad):
fig, ax = plt.subplots()
img = ax.imshow(data, aspect=aspect)
last_axes = plt.gca()
divider = make_axes_locatable(ax)
cax = divider.append_axes('right', size='5%', pad=pad)
cbar = fig.colorbar(im, cax=cax)
plt.sca(last_axes)
运行 plot_data(data, None, 0.05)
给出了我所期望的 - an image with colorbar taking up 5% of the width, matched to the same height and padded correctly.
然而 运行 plot_data(data, 2.5, 0)
导致 a figure with an image that has the correct aspect ratio, but a colorbar that's padded way too much. 我可以通过使填充为负来纠正这个问题,通过反复试验找到一个好的值。但是我需要它是通用的并且无需用户监控即可工作。
我找到了 this thread 但答案似乎并没有解决这个特殊情况。
非常感谢任何建议!
问题的解决方案
一个区间(1,2.5)有几个近似值的"nonlinear regression"给了我:
y=a*x^2+b*x+c
a=0.25
b=-1.29
c=1.09
尝试使用:
cax = divider.append_axes('right', size='5%', pad=0.25*aspect**2-1.29*aspect+1.09)
现在您不能使用 None
作为 aspect=1
的方面并且您不需要通过 pad
。此外,此公式适用于 aspect>=1
,您可能需要为小于 1 的值获取另一个公式,因为行为确实不同。对于高于 2.5 的值,您需要计算新的系数(解释如下)。
def plot_data(data, aspect, pad=None):
if aspect == None:
aspect = 1
fig, ax = plt.subplots()
img = ax.imshow(data, aspect=aspect)
last_axes = plt.gca()
divider = make_axes_locatable(ax)
cax = divider.append_axes('right', size='5%', pad=0.25*aspect**2-1.29*aspect+1.09)
cbar = fig.colorbar(img, cax=cax)
plt.sca(last_axes)
关于"nonlinear regression"
要获得系数,我需要做的第一件事就是获得几对(纵横比、填充)。怎么得到它们?反复试验:第一对是原始的 (1, 0.05),其他的视觉效果良好:(1.5, -0.305)、(2, -0.48)、(2.5, -0.58)。如果您看到,数据中没有线性关系,但无论如何我们都可以绘制它
import matplotlib.pyplot as plt
data = [(1,0.05),(1.5,-0.305),(2,-0.48),(2.5,-0.58)]
plt.plot(*zip(*data))
plt.plot(*zip(*data),'or')
plt.xlabel("aspect")
plt.ylabel("padding")
plt.show()
现在,让我们获取执行曲线拟合的系数:
fit = np.polynomial.polynomial.Polynomial.fit(*zip(*pairs),2)
c,b,a = fit.convert().coef
(是的,我只用二次多项式做了曲线拟合,抱歉!)我最初写的值和 python 给出的值之间的差异出现了,因为我使用了其他软件并且我做了一个在大多数情况下四舍五入到小数点后两位。
为什么我使用二次多项式 (fit(x,y,2))?我尽量保持模型简单。
pairs = [(1,0.05),(1.5,-0.305),(2,-0.48),(2.5,-0.58)]
x = np.linspace(1,2.5,100)
yp = [a*x**2+b*x+c for x in x]
plt.plot(*zip(*pairs),'or', label='pairs')
plt.plot(x,yp,'g', label='Curve fitting')
plt.xlabel("aspect")
plt.ylabel("padding")
plt.legend(loc="upper right")
plt.show()
这对 [1,2.5] 以外的值有效吗?并不真地。为此,您应该在曲线拟合中包含更多点,也许将 2 阶多项式更改为对数多项式。
我一直在玩这个,看起来颜色条总是基于数据图边缘的原始位置。这意味着,对于正宽高比,图形的高度保持不变,图形的宽度减小。
然后图像居中,因此需要使用填充分别(向内)按宽度调整颜色条 - height/aspect
width=last_axes.get_position().width
height=last_axes.get_position().height
cax = divider.append_axes('right', size='5%', pad=-((width/0.7)-(height/(0.7*aspect)) + pad))
我遇到的奇怪的事情是,它并没有完全使数据居中,而是数据和轴标签的中心,因此我们必须相应地缩小调整,因此公式中为 1/0.7。我意识到这并不完美,因为可挠痒痒点没有按纵横比缩小,所以线性移动会更合适,但我现在已经做到了!
请注意,这不适用于纵横比小于 1 的情况,因为此时宽度是固定的,而在应用纵横比时高度会发生变化。我会继续弄乱它,看看我是否可以概括景观
编辑:
好的,我有。由于某种原因,追加轴功能强制垂直颜色条成为绘图的原始高度。对于肖像图来说很好,但对于数据垂直收缩但情节不是这样的景观来说是坏的,所以我不得不在下面放一个开关盒,这是完整的代码:
def plot_data(data, aspect, pad):
fig, ax = plt.subplots()
img = ax.imshow(data, aspect=aspect)
last_axes = plt.gca()
divider = make_axes_locatable(ax)
if(aspect<1):
hscale=aspect
cbar = fig.colorbar(img,shrink=hscale,pad=(-0.43+pad))
else:
hscale=1
width=last_axes.get_position().width
height=last_axes.get_position().height
padfix = -((width/0.7)-(height/(0.7*aspect)))
cax = divider.append_axes('right',size='5%', pad=padfix+ pad)
cbar = fig.colorbar(img,cax=cax)
同样,固定偏移量(这次约为 0.43)有些奇怪,这是通过反复试验发现的,如果绘制 真的 细长可能需要调整地块。
我正在尝试绘制一些数组数据并在轴的右侧添加一个颜色条,以匹配高度和设置的宽度。
首先生成一些数据。
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
data = np.random.rand(700, 400)
我有以下功能。
def plot_data(data, aspect, pad):
fig, ax = plt.subplots()
img = ax.imshow(data, aspect=aspect)
last_axes = plt.gca()
divider = make_axes_locatable(ax)
cax = divider.append_axes('right', size='5%', pad=pad)
cbar = fig.colorbar(im, cax=cax)
plt.sca(last_axes)
运行 plot_data(data, None, 0.05)
给出了我所期望的 - an image with colorbar taking up 5% of the width, matched to the same height and padded correctly.
然而 运行 plot_data(data, 2.5, 0)
导致 a figure with an image that has the correct aspect ratio, but a colorbar that's padded way too much. 我可以通过使填充为负来纠正这个问题,通过反复试验找到一个好的值。但是我需要它是通用的并且无需用户监控即可工作。
我找到了 this thread 但答案似乎并没有解决这个特殊情况。
非常感谢任何建议!
问题的解决方案
一个区间(1,2.5)有几个近似值的"nonlinear regression"给了我:
y=a*x^2+b*x+c
a=0.25
b=-1.29
c=1.09
尝试使用:
cax = divider.append_axes('right', size='5%', pad=0.25*aspect**2-1.29*aspect+1.09)
现在您不能使用 None
作为 aspect=1
的方面并且您不需要通过 pad
。此外,此公式适用于 aspect>=1
,您可能需要为小于 1 的值获取另一个公式,因为行为确实不同。对于高于 2.5 的值,您需要计算新的系数(解释如下)。
def plot_data(data, aspect, pad=None):
if aspect == None:
aspect = 1
fig, ax = plt.subplots()
img = ax.imshow(data, aspect=aspect)
last_axes = plt.gca()
divider = make_axes_locatable(ax)
cax = divider.append_axes('right', size='5%', pad=0.25*aspect**2-1.29*aspect+1.09)
cbar = fig.colorbar(img, cax=cax)
plt.sca(last_axes)
关于"nonlinear regression"
要获得系数,我需要做的第一件事就是获得几对(纵横比、填充)。怎么得到它们?反复试验:第一对是原始的 (1, 0.05),其他的视觉效果良好:(1.5, -0.305)、(2, -0.48)、(2.5, -0.58)。如果您看到,数据中没有线性关系,但无论如何我们都可以绘制它
import matplotlib.pyplot as plt
data = [(1,0.05),(1.5,-0.305),(2,-0.48),(2.5,-0.58)]
plt.plot(*zip(*data))
plt.plot(*zip(*data),'or')
plt.xlabel("aspect")
plt.ylabel("padding")
plt.show()
现在,让我们获取执行曲线拟合的系数:
fit = np.polynomial.polynomial.Polynomial.fit(*zip(*pairs),2)
c,b,a = fit.convert().coef
(是的,我只用二次多项式做了曲线拟合,抱歉!)我最初写的值和 python 给出的值之间的差异出现了,因为我使用了其他软件并且我做了一个在大多数情况下四舍五入到小数点后两位。
为什么我使用二次多项式 (fit(x,y,2))?我尽量保持模型简单。
pairs = [(1,0.05),(1.5,-0.305),(2,-0.48),(2.5,-0.58)]
x = np.linspace(1,2.5,100)
yp = [a*x**2+b*x+c for x in x]
plt.plot(*zip(*pairs),'or', label='pairs')
plt.plot(x,yp,'g', label='Curve fitting')
plt.xlabel("aspect")
plt.ylabel("padding")
plt.legend(loc="upper right")
plt.show()
这对 [1,2.5] 以外的值有效吗?并不真地。为此,您应该在曲线拟合中包含更多点,也许将 2 阶多项式更改为对数多项式。
我一直在玩这个,看起来颜色条总是基于数据图边缘的原始位置。这意味着,对于正宽高比,图形的高度保持不变,图形的宽度减小。 然后图像居中,因此需要使用填充分别(向内)按宽度调整颜色条 - height/aspect
width=last_axes.get_position().width
height=last_axes.get_position().height
cax = divider.append_axes('right', size='5%', pad=-((width/0.7)-(height/(0.7*aspect)) + pad))
我遇到的奇怪的事情是,它并没有完全使数据居中,而是数据和轴标签的中心,因此我们必须相应地缩小调整,因此公式中为 1/0.7。我意识到这并不完美,因为可挠痒痒点没有按纵横比缩小,所以线性移动会更合适,但我现在已经做到了!
请注意,这不适用于纵横比小于 1 的情况,因为此时宽度是固定的,而在应用纵横比时高度会发生变化。我会继续弄乱它,看看我是否可以概括景观
编辑:
好的,我有。由于某种原因,追加轴功能强制垂直颜色条成为绘图的原始高度。对于肖像图来说很好,但对于数据垂直收缩但情节不是这样的景观来说是坏的,所以我不得不在下面放一个开关盒,这是完整的代码:
def plot_data(data, aspect, pad):
fig, ax = plt.subplots()
img = ax.imshow(data, aspect=aspect)
last_axes = plt.gca()
divider = make_axes_locatable(ax)
if(aspect<1):
hscale=aspect
cbar = fig.colorbar(img,shrink=hscale,pad=(-0.43+pad))
else:
hscale=1
width=last_axes.get_position().width
height=last_axes.get_position().height
padfix = -((width/0.7)-(height/(0.7*aspect)))
cax = divider.append_axes('right',size='5%', pad=padfix+ pad)
cbar = fig.colorbar(img,cax=cax)
同样,固定偏移量(这次约为 0.43)有些奇怪,这是通过反复试验发现的,如果绘制 真的 细长可能需要调整地块。