【问题标题】:Is there a way to set the background color of a specific subplot in python matplotlib?有没有办法在 python matplotlib 中设置特定子图的背景颜色?
【发布时间】:2021-06-23 16:34:03
【问题描述】:

我想使用subplot 制作多图,这样一个或多个特定子图的背景颜色与其他子图不同,如下例所示:

请注意,我感兴趣的是设置子图外部补丁的背景颜色,而不是图内部的背景颜色(可以使用 facecolor='gray' 完成)。这是因为我想绘制密度图,并且想将其中一些与其他部分区分开来。

我发现了类似this 之类的问题,例如每行子图都有不同的背景颜色,但我无法修改代码以便可以将颜色应用于特定子图(例如 (1, 2)、(1,3)、(2,1)、(2,2)如上图)。

这是一个示例代码:

import numpy as np
import matplotlib.pyplot as plt

fig, subs = plt.subplots(3,3,figsize=(10,10))

images = []
for i in range(3):
    for j in range(3): 
        data = np.random.rand(20,20)
        images.append(subs[i, j].imshow(data))
        subs[i, j].label_outer()

plt.show()

任何帮助将不胜感激。

【问题讨论】:

  • ax.set_facecolor("red") 轴对象的方法,更多详情请看这个链接-stackoverflow.com/questions/14088687/…
  • 我的问题是,与这篇文章相比,我感兴趣的是改变子图周围框架的颜色,而不是子图内空间的背景。 ax.set_facecolor()只能更改子图的内部颜色,fig.patch.set_facecolor更改外部颜色但为全图,因此不能为每个子图单独设置。

标签: python matplotlib subplot


【解决方案1】:

根据[this post],您可以使用fig.patches.extend在图形上绘制一个矩形。 zorder 高时,矩形将位于子图的顶部,zorder 低时,它可能在后面。

现在,属于子图周围环境的确切区域没有明确定义。 一种简单的方法是为每个子图分配相等的空间,但这不适用于共享轴,也不适用于图形边缘附近的空白。

示例代码使用不同数量的列和行来确保水平和垂直计算不会翻转。

import numpy as np
import matplotlib.pyplot as plt

fig, subs = plt.subplots(3, 4, figsize=(10, 8))
images = []
for i in range(3):
    for j in range(4):
        data = np.random.rand(20, 20)
        images.append(subs[i, j].imshow(data))
        subs[i, j].label_outer()

m, n = subs.shape
for _ in range(50):
    i = np.random.randint(m)
    j = np.random.randint(n)
    color = ['r', 'b', 'g'][np.random.randint(3)]
    fig.patches.extend([plt.Rectangle((j / n, (m - 1 - i) / m), 1 / n, 1 / m,
                                      fill=True, color=color, alpha=0.2, zorder=-1,
                                      transform=fig.transFigure, figure=fig)])
plt.show()

另一种方法是使用subs[i, j].get_tightbbox(fig.canvas.get_renderer()),但该边界框仅包含属于子图的文本,仅此而已。

一种更复杂的方法是计算相邻子图之间的差异,并使用它来扩大子图轴所占据的区域:

m, n = subs.shape
bbox00 = subs[0, 0].get_window_extent()
bbox01 = subs[0, 1].get_window_extent()
bbox10 = subs[1, 0].get_window_extent()
pad_h = 0 if n == 1 else bbox01.x0 - bbox00.x0 - bbox00.width
pad_v = 0 if m == 1 else bbox00.y0 - bbox10.y0 - bbox10.height
for _ in range(20):
    i = np.random.randint(m)
    j = np.random.randint(n)
    color = ['r', 'b', 'g'][np.random.randint(3)]
    bbox = subs[i, j].get_window_extent()
    fig.patches.extend([plt.Rectangle((bbox.x0 - pad_h / 2, bbox.y0 - pad_v / 2),
                                      bbox.width + pad_h, bbox.height + pad_v,
                                      fill=True, color=color, alpha=0.2, zorder=-1,
                                      transform=None, figure=fig)])

根据地块的布局,它仍然不完美。该方法可以进一步细化,例如对第一列和最低行进行特殊处理。如果重叠不是问题,边界框也可以通过get_tightbbox()的结果进行扩展,使用较浅的颜色和alpha=1

四边都有刻度标签的绘图是这样的:

【讨论】:

  • 谢谢!最后一种方法对我的目的来说已经足够好了。特别是考虑到subplot 函数中似乎没有预定义的子图框架,并且显然需要计算正确的尺寸并绘制矩形。
【解决方案2】:

设置fig的颜色:

fig, subs = plt.subplots(3,3,figsize=(10,10))

images = []
for i in range(3):
    for j in range(3): 
        data = np.random.rand(20,20)
        images.append(subs[i, j].imshow(data))
        subs[i, j].label_outer()

# this    
fig.set_facecolor('red')
plt.show()

输出:

【讨论】:

  • 谢谢,但我想要更改仅部分 子图周围的框架颜色,而不是全部子图。目的是突出它们。我现在通过在帖子中包含示例图像(使用另一个程序生成)来更清楚地说明我想要做什么。
【解决方案3】:

我使用的替代解决方案是用某种颜色填充图像:

img_padded = cv2.copyMakeBorder(img, border_size, border_size, border_size, border_size, cv2.BORDER_CONSTANT, value=[0, 255, 0]);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-08-14
    • 1970-01-01
    • 2014-06-12
    • 2020-12-10
    • 2020-09-19
    • 2011-02-11
    • 2017-11-17
    • 2021-09-30
    相关资源
    最近更新 更多