我需要使用matplotlib来布置一个充满文本框的表格。应该很容易做到这一点:为表成员创建一个gridspec,填充网格的每个元素,取网格中元素的最大高度和宽度,修改网格列和行的适当高度和宽度。简单吧?
错了。
除了项目本身的度量之外,其他一切都正常。Matplotlib总是为每个项目返回错误的大小。我相信我已经能够追踪到甚至不能正确度量文本路径的大小:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as mpatch
import matplotlib.text as mtext
import matplotlib.path as mpath
import matplotlib.patches as mpatches
fig, ax = plt.subplots(1, 1)
ax.set_axis_off()
text = '!?' * 16
size=36
## Buildand measure hidden text path
text_path=mtext.TextPath(
(0.0, 0.0),
text,
prop={'size' : size}
)
vertices = text_path.vertices
code = text_path.codes
min_x, min_y = np.min(
text_path.vertices[text_path.codes != mpath.Path.CLOSEPOLY], axis=0)
max_x, max_y = np.max(
text_path.vertices[text_path.codes != mpath.Path.CLOSEPOLY], axis=0)
## Transform measurement to graph units
transData = ax.transData.inverted()
((local_min_x, local_min_y),
(local_max_x, local_max_y)) = transData.transform(
((min_x, min_y), (max_x, max_y)))
## Draw a box which should enclose the path
x_offset = (local_max_x - local_max_y) / 2
y_offset = (local_max_y - local_min_y) / 2
local_min_x = 0.5 - x_offset
local_min_y = 0.5 - y_offset
local_max_x = 0.5 + x_offset
local_max_y = 0.5 + y_offset
path_data = [
(mpath.Path.MOVETO, (local_min_x, local_min_y)),
(mpath.Path.LINETO, (local_max_x, local_min_y)),
(mpath.Path.LINETO, (local_max_x, local_max_y)),
(mpath.Path.LINETO, (local_min_x, local_max_y)),
(mpath.Path.LINETO, (local_min_x, local_min_y)),
(mpath.Path.CLOSEPOLY, (local_min_x, local_min_y)),
]
codes, verts = zip(*path_data)
path = mpath.Path(verts, codes)
patch = mpatches.PathPatch(
path,
facecolor='white',
edgecolor='red',
linewidth=3)
ax.add_patch(patch)
## Draw the text itself
item_textbox = ax.text(
0.5, 0.5,
text,
bbox=dict(boxstyle='square',
fc='white',
ec='white',
alpha=0.0),
transform=ax.transAxes,
size=size,
horizontalalignment="center",
verticalalignment="center",
alpha=1.0)
plt.show()
在Python 3.8下运行此代码
期望:红色框是文本的精确高度和宽度
观察:红色框的高度正确,但宽度肯定不正确。
1条答案
按热度按时间vwkv1x7d1#
似乎没有任何直接的方法可以做到这一点,但有一种间接的方法可以做到这一点:不使用文本框,而是使用TextPath,将其转换为Axis坐标,然后使用每个坐标的最小值和最大值之间的差值。(https://matplotlib.org/stable/gallery/text_labels_and_annotations/demo_text_path.html#sphx-glr-gallery-text-labels-and-annotations-demo-text-path-py有关示例实现,请参见www.example.com。此实现有一个严重的错误--它直接使用顶点和代码,在剪切文本路径的情况下会中断。)