如何将两个Matplotlib文本框侧边对齐在右上角?

huangapple go评论79阅读模式
英文:

How to align two matplotlib text-boxes side-by-side in the top-right corner?

问题

我正在尝试将两个文本框并排放在matplotlib图形的右上角。我遵循了这个文本对齐的教程,可以将一个文本框放在右上角。但我不知道如何添加第二个文本框,使得左上角框的右边缘与右上角框的左边缘相交。

以下是运行最小工作示例的代码:

import numpy as np
import matplotlib.pyplot as plt

# 数据
x = np.linspace(-10, 10, 51)
shrink_factors = np.linspace(1, 0, x.size)
y1 = shrink_factors*np.sin(np.exp(-x))
y2 = shrink_factors*np.cos(np.exp(-x))

# 获取绘图参数
xlim = [np.min(x), np.max(x)]
ylim = [0, 1.125*np.max([np.max(y1), np.max(y2)])]
facecolors = ("red", "blue")
(color1, color2) = facecolors
label1 = "Label 1"
label2 = "Label 2"
text1 = "RED 1"
text2 = "BLUE 2"
text_background_color = "gainsboro"
text_size = 12
figsize = (12, 7)

# 初始化图
fig, ax = plt.subplots(
    figsize=figsize)

# 绘制数据
ax.plot(x, y1, color=color1, label=label1)
ax.plot(x, y2, color=color2, label=label2)
ax.grid(color="black", linestyle=":", alpha=0.3)
ax.set_xlim(xlim)
ax.set_ylim(ylim)
fig.legend(mode="expand", loc="lower center", ncol=2)

# 并排添加文本框
text_box1 = ax.text(0.95, 0.95, text1, 
                    color=color1, 
                    fontsize=text_size,
                    horizontalalignment="right", 
                    verticalalignment="top", 
                    transform=ax.transAxes)
text_box1.set_bbox({"facecolor": text_background_color, "edgecolor": "black"})
text_box1_pos = text_box1.get_position()
text_box2 = ax.text(text_box1_pos[0], 0.95, text2, 
                    color=color2, 
                    fontsize=text_size, 
                    horizontalalignment="left", 
                    verticalalignment="top", 
                    transform=ax.transAxes)
text_box2.set_bbox({"facecolor": text_background_color, "edgecolor": "black"})

# 完成绘图
plt.show()
plt.close()
英文:

I am trying to put two text-boxes side-by-side in the top-right corner of a matplotlib figure. I followed this tutorial on text-alignment and can place one text-box in the top-right corner. But I do not know how to add a second text-box such that the right-edge of the top-left box intersects the left-edge of the top-right box.

如何将两个Matplotlib文本框侧边对齐在右上角?

The code to output run the minimal working example is below:

import numpy as np
import matplotlib.pyplot as plt

# data
x = np.linspace(-10, 10, 51)
shrink_factors = np.linspace(1, 0, x.size)
y1 = shrink_factors*np.sin(np.exp(-x))
y2 = shrink_factors*np.cos(np.exp(-x))

# get plot parameters
xlim = [np.min(x), np.max(x)]
ylim = [0, 1.125*np.max([np.max(y1), np.max(y2)])]
facecolors = ("red", "blue")
(color1, color2) = facecolors
label1 = "Label 1"
label2 = "Label 2"
text1 = "RED 1"
text2 = "BLUE 2"
text_background_color = "gainsboro"
text_size = 12
figsize = (12, 7)
# figsize = (7, 12)

# initialize plot
fig, ax = plt.subplots(
    figsize=figsize)

# plot data
ax.plot(x, y1, color=color1, label=label1)
ax.plot(x, y2, color=color2, label=label2)
ax.grid(color="black", linestyle=":", alpha=0.3)
ax.set_xlim(xlim)
ax.set_ylim(ylim)
fig.legend(mode="expand", loc="lower center", ncol=2)

# add text-boxes side-by-side
text_box1 = ax.text(0.95, 0.95, text1, 
                    color=color1, 
                    fontsize=text_size,
                    horizontalalignment="right", 
                    verticalalignment="top", 
                    transform=ax.transAxes)
text_box1.set_bbox({"facecolor": text_background_color, "edgecolor": "black"})
text_box1_pos = text_box1.get_position()
text_box2 = ax.text(text_box1_pos[0], 0.95, text2, 
                    color=color2, 
                    fontsize=text_size, 
                    horizontalalignment="left", 
                    verticalalignment="top", 
                    transform=ax.transAxes)
text_box2.set_bbox({"facecolor": text_background_color, "edgecolor": "black"})

# finish plot
plt.show()
plt.close()

答案1

得分: 3

你想将左侧框右对齐到右侧框的左侧 x 值。因此,您需要获取围绕文本框绘制的矩形。它们由一个与变异比例尺度相关的 pad 值填充。要获取这些值,您首先需要绘制图形(可以在不渲染的情况下完成以加快速度)。

以下是一个假设两个文本使用相同(默认)填充的最小示例:

import matplotlib.pyplot as plt

fig, ax = plt.subplots()

bbox_kwds = dict(fc="gainsboro", ec="black")
text_box1 = ax.text(0.95, 0.95, "RIGHT", ha="right", va="top", transform=ax.transAxes, bbox=bbox_kwds)

fig.draw_without_rendering()
pad = text_box1.get_bbox_patch().get_boxstyle().pad * text_box1.get_bbox_patch().get_mutation_scale()
x = ax.transAxes.inverted().transform(text_box1.get_bbox_patch().get_window_extent().p0 - [pad, 0])[0]

text_box2 = ax.text(x, 0.95, "LEFT", ha="right", va="top", transform=ax.transAxes, bbox=bbox_kwds)

如何将两个Matplotlib文本框侧边对齐在右上角?


<details>
<summary>英文:</summary>
You want to right-align the left box to the left x value of the right box. So you need to get the rectangles drawn around the text boxes. They are padded by a value of pad scaled with a mutation scale factor. To get these values you first need to draw the figure (you can do it without rendering to speed it up a bit).
Here is a minimal examples assuming both texts using the same (default) padding:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
bbox_kwds = dict(fc=&quot;gainsboro&quot;, ec=&quot;black&quot;)
text_box1 = ax.text(0.95, 0.95, &quot;RIGHT&quot;, ha=&quot;right&quot;, va=&quot;top&quot;, transform=ax.transAxes, bbox=bbox_kwds)
fig.draw_without_rendering()
pad = text_box1.get_bbox_patch().get_boxstyle().pad * text_box1.get_bbox_patch().get_mutation_scale()
x = ax.transAxes.inverted().transform(text_box1.get_bbox_patch().get_window_extent().p0 - [pad, 0])[0]
text_box2 = ax.text(x, 0.95, &quot;LEFT&quot;, ha=&quot;right&quot;, va=&quot;top&quot;, transform=ax.transAxes, bbox=bbox_kwds)
[![enter image description here][1]][1]
[1]: https://i.stack.imgur.com/bZzJA.png
</details>
# 答案2
**得分**: 2
这是我之前遇到过的一个类似问题。这是我所做的事情...这是基于另一篇帖子中提供的一些信息[这里](https://stackoverflow.com/questions/24581194/matplotlib-text-bounding-box-dimensions)。以下是对你的代码的更新...
1. 更新第一个文本框的x位置为`0.9`,以便两个标签都在图中。
2. 一旦绘制了第一个文本框,请添加下面的代码...这类似于我提到的帖子中所解释的。请注意,我正在使用`transAxes`,以便在任何地方都有相同的坐标。更多信息[在这里](https://matplotlib.org/stable/tutorials/advanced/transforms_tutorial.html)。请注意,`bb_datacoords`现在将具有第一个文本框的x和y坐标。
```python
# text_box1_pos = text_box1.get_position()  --&gt; 你的代码,不再需要
r = fig.canvas.get_renderer()
transf = ax.transAxes.inverted()
bb = text_box1.get_window_extent(renderer = r)
bb_datacoords = bb.transformed(transf)
  1. 使用bbox的x1位置作为第二个文本框的起点,如下所示...
    bb_datacoords.x1+0.01, #text_box1_pos[0],

请注意,正如上述SO答案中所提到的,精确位置在绘图完成之前是未知的,因此可以添加一个小的增量0.01,使它们不重叠。如果你想在两个框之间看到一个小间隙,可以增加它(比如0.02)。

生成的图表如下所示...希望对你有所帮助。

如何将两个Matplotlib文本框侧边对齐在右上角?

英文:

I had encountered a similar issue some time back. Here is what I did... This is based on some of the info provide in another post here. Given below are the updates to your code...

  1. Update the x position of the first text box to 0.9, so that both the labels are within the plot
  2. Once the first text box is plotted, add the below code.. this is similar what is explained in the post I mentioned. Note that I am using transAxes so that we have same coordinates everywhere. More info here. Note the bb_datacoords will now have the x and y coordinates of the first textbox
#text_box1_pos = text_box1.get_position()  --&gt; You code, not required anymore
r = fig.canvas.get_renderer()
transf = ax.transAxes.inverted()
bb = text_box1.get_window_extent(renderer = r)
bb_datacoords = bb.transformed(transf)
  1. Use the x1 position from bbox as the start point for the second text box, like below...
    bb_datacoords.x1+0.01, #text_box1_pos[0],

Note that, as mentioned in the above SO answer, the exact position is not known till the plot is done, so there is a small delta of 0.01 that you can add to make them non-overlapping. You can increase it (to say 0.02) if you want to see a small gap in between the two boxes.

The resulting plot looks like this... Hope this helps.

如何将两个Matplotlib文本框侧边对齐在右上角?

huangapple
  • 本文由 发表于 2023年6月30日 05:12:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/76584630.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定