如何在matplotlib中测量文本元素

ckocjqey  于 2022-11-30  发布在  其他
关注(0)|答案(1)|浏览(112)

我需要使用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下运行此代码
期望:红色框是文本的精确高度和宽度
观察:红色框的高度正确,但宽度肯定不正确。

vwkv1x7d

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。此实现有一个严重的错误--它直接使用顶点和代码,在剪切文本路径的情况下会中断。)

相关问题