英文:
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.
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)
<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="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)
[![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() --> 你的代码,不再需要
r = fig.canvas.get_renderer()
transf = ax.transAxes.inverted()
bb = text_box1.get_window_extent(renderer = r)
bb_datacoords = bb.transformed(transf)
- 使用bbox的x1位置作为第二个文本框的起点,如下所示...
bb_datacoords.x1+0.01, #text_box1_pos[0],
请注意,正如上述SO答案中所提到的,精确位置在绘图完成之前是未知的,因此可以添加一个小的增量0.01,使它们不重叠。如果你想在两个框之间看到一个小间隙,可以增加它(比如0.02)。
生成的图表如下所示...希望对你有所帮助。
英文:
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...
- Update the x position of the first text box to
0.9
, so that both the labels are within the plot - 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 thebb_datacoords
will now have the x and y coordinates of the first textbox
#text_box1_pos = text_box1.get_position() --> 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)
- 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论