python - Matplotlib 中的可编辑表格:如何在表格单元格上叠加 TextBox 小部件?
问题描述
我正在朝着在 Matplotlib 中创建交互式表格的方向前进。我希望用户能够单击表格中的数据单元格,以便他们可以编辑其值。根据@ImportanceOfBeingErnest here的建议,我为表中的每个真实数据单元格注册了一个选择事件处理程序。然后我可以检测到用户点击了哪个单元格。但是我不能将TextBox
对象完全叠加在拾取的单元格上,以便用户看起来他们正在编辑他们拾取的单元格。
用于说明问题的虚拟代码:
import matplotlib.pyplot as plt
from matplotlib.table import CustomCell
from matplotlib.widgets import TextBox
def on_pick(event):
if isinstance(event.artist, CustomCell):
cell = event.artist
# Doesn't work because cell.get_y() is negative:
#text_box_axes = plt.axes([cell.get_x(), cell.get_y(), cell.get_width(), cell.get_height()])
# This doesn't work either but at least you can see the TextBox on the figure!
text_box_axes = plt.axes([cell.get_x(), -cell.get_y(), cell.get_width(), cell.get_height()])
cell_text = cell.get_text().get_text()
TextBox(text_box_axes, '', initial=cell_text)
plt.draw()
column_labels = ('Length', 'Width', 'Height', 'Sold?')
row_labels = ['Ferrari', 'Porsche']
data = [[2.2, 1.6, 1.2, True],
[2.1, 1.5, 1.4, False]]
table = plt.table(cellText=data, colLabels=column_labels, rowLabels=row_labels, cellLoc='center', loc='bottom')
text_box = None
celld = table.get_celld()
for key in celld.keys():
# Each key is a tuple of the form (row, column).
# Column headings are in row 0. Row headings are in column -1.
# So the first item of data in the table is actually at (1, 0).
if key[0] > 0 and key[1] > -1:
cell = celld[key]
cell.set_picker(True)
canvas = plt.gcf().canvas
canvas.mpl_connect('pick_event', on_pick)
plt.axis('off')
plt.show()
但是,如果我运行它然后单击其中包含的单元格,1.2
我会看到:
那么如何让 的边界TextBox
与用户单击的单元格的边界完全匹配?
似乎文本框的轴是相对于整个图形而不是表本身的。
解决方案
单元格的位置确实在轴坐标中给出,而TextBox
' 轴位于图形坐标中。您可以在两个坐标系之间转换为
trans = figure.transFigure.inverted()
trans2 = ax.transAxes
bbox = cell.get_bbox().transformed(trans2 + trans)
text_box_axes.set_position(bbox.bounds)
当然,您还需要确保TextBox
每次提交时都根据 的内容更新单元格文本。
以下将是一个功能齐全的可编辑 matplotlib 表。
import matplotlib.pyplot as plt
from matplotlib.table import CustomCell
from matplotlib.widgets import TextBox
class EditableTable():
def __init__(self, table):
self.table = table
self.ax = self.table.axes
celld = table.get_celld()
for key in celld.keys():
if key[0] > 0 and key[1] > -1:
cell = celld[key]
cell.set_picker(True)
self.canvas = self.table.get_figure().canvas
self.cid = self.canvas.mpl_connect('pick_event', self.on_pick)
self.tba = self.ax.figure.add_axes([0,0,.01,.01])
self.tba.set_visible(False)
self.tb = TextBox(self.tba, '', initial="")
self.cid2 = self.tb.on_submit(self.on_submit)
self.currentcell = celld[(1,0)]
def on_pick(self, event):
if isinstance(event.artist, CustomCell):
# clear axes and delete textbox
self.tba.clear()
del self.tb
# make textbox axes visible
self.tba.set_visible(True)
self.currentcell = event.artist
# set position of textbox axes to the position of the current cell
trans = self.ax.figure.transFigure.inverted()
trans2 = self.ax.transAxes
bbox = self.currentcell.get_bbox().transformed(trans2 + trans)
self.tba.set_position(bbox.bounds)
# create new Textbox with text of the current cell
cell_text = self.currentcell.get_text().get_text()
self.tb = TextBox(self.tba, '', initial=cell_text)
self.cid2 = self.tb.on_submit(self.on_submit)
self.canvas.draw()
def on_submit(self, text):
# write the text box' text back to the current cell
self.currentcell.get_text().set_text(text)
self.tba.set_visible(False)
self.canvas.draw_idle()
column_labels = ('Length', 'Width', 'Height', 'Sold?')
row_labels = ['Ferrari', 'Porsche']
data = [[2.2, 1.6, 1.2, True],
[2.1, 1.5, 1.4, False]]
fig, ax = plt.subplots()
table = ax.table(cellText=data, colLabels=column_labels, rowLabels=row_labels,
cellLoc='center', loc='bottom')
et = EditableTable(table)
ax.axis('off')
plt.show()
但是请注意,有时存在一些错误会阻止单元格正确更新。我还没有找到这个的原因。
请注意,在此之前的版本中,使用了单个 TextBox 实例。然而,这导致了无法追踪的错误。相反,每次单击单元格时都需要创建一个新实例,如上述更新版本。
推荐阅读
- list - Flutter - 每次关闭应用程序时存储对象列表的最佳方式?
- r - 如何在 R 中构建 100 个带有条件变量的投资组合?
- google-cloud-platform - Google Speech Diarization 标签一直在变化
- r - 创建一个以一个特定值及其另一个变量的行索引为条件的分类变量
- sql - 执行 SELECT 或 INSERT
- css - 使用网格模板区域的网格显示中的过渡持续时间:如何使其工作?
- html - 正确显示 SCSS 时出现问题
- python - Python从列表和元组创建字典
- laravel - 如何在 Dialogflow 中获取用户访问令牌?
- git - 防止“预提交”钩子循环