有没有办法在 python matplotlib 中设置特定子图的背景颜色? [英] Is there a way to set the background color of a specific subplot in python matplotlib?

查看:82
本文介绍了有没有办法在 python matplotlib 中设置特定子图的背景颜色?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

我发现了类似的问题,例如

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

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

m, n = subs.shapebbox00 = subs[0, 0].get_window_extent()bbox01 = subs[0, 1].get_window_extent()bbox10 = subs[1, 0].get_window_extent()pad_h = 0 如果 n == 1 否则 bbox01.x0 - bbox00.x0 - bbox00.widthpad_v = 0 如果 m == 1 否则 bbox00.y0 - bbox10.y0 - bbox10.height对于 _ 范围(20):i = np.random.randint(m)j = np.random.randint(n)颜色 = ['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,填充=真,颜色=颜色,alpha=0.2,zorder=-1,变换=无,图=无花果)])

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

这就是四个边都有刻度标签的图的样子:

I would like to make a multiple plot using subplot, such that one or more specific subplots have a different background color than the rest, like in this example:

Note that I'm interested in setting the background color of the exterior patch of the subplots not the background color inside the plot (which can be done with facecolor='gray'). This is because I want to plot density plots and I want to distinguish some of them from the rest.

I have found similar questions like this for example where each row of subplots has a different background color, but I wasn't able to modify the code so that the color can be applied on specific subplots (say (1,2), (1,3), (2,1) and (2,2) as in the attached figure above).

This is an example code:

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()

Any help would be greatly appreciated.

解决方案

According [this post] you can use fig.patches.extend to draw a rectangle on the figure. With a high zorder the rectangle will be on top of the subplots, with a low zorder it can be behind.

Now, the exact area belonging to the surroundings of a subplot isn't well-defined. A simple approach would be to give equal space to each subplot, but that doesn't work out well with shared axes nor with the white space near the figure edges.

The example code uses a different number of columns and rows to be sure horizontal and vertical calculations aren't flipped.

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()

Another approach would be to use subs[i, j].get_tightbbox(fig.canvas.get_renderer()), but that bounding box just includes the texts belonging to the subplot and nothing more.

A more involved approach calculates the difference between neighboring subplots and uses that to enlarge the area occupied by the axes of the subplots:

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)])

Depending on the layout of the plots, it still isn't perfect. The approach can be refined further, such as special treatment for the first column and lowest row. If overlapping isn't a problem, the bounding box can also be extended by the result of get_tightbbox(), using a lighter color and alpha=1.

This is how it looks like with plots that have tick labels at the four sides:

这篇关于有没有办法在 python matplotlib 中设置特定子图的背景颜色?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆