【问题标题】:Plot table along chart using matplotlib使用 matplotlib 沿图表绘制表格
【发布时间】:2019-05-03 12:42:05
【问题描述】:

目前我有这段代码:

import pandas as pd
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
from matplotlib.font_manager import FontProperties


data = np.random.uniform(0, 1, 80).reshape(20, 4)
final_data = [['%.3f' % j for j in i] for i in data]

mpl.style.use('seaborn')
mpl.rc('xtick', labelsize = 7)
mpl.rc('ytick', labelsize = 7)

fig = plt.figure()

fig.subplots_adjust(left=0.1, wspace=0.1)
plt.subplot2grid((1, 4), (0, 0), colspan=3)

table_subplot = plt.subplot2grid((1, 4), (0, 3))

table = plt.table(cellText=final_data, colLabels=['A', 'B', 'C', 'D'], loc='center', cellLoc='center', colColours=['#FFFFFF', '#F3CC32', '#2769BD', '#DC3735'])
table.auto_set_font_size(False)
table.set_fontsize(7)
table.auto_set_column_width((-1, 0, 1, 2, 3))

for (row, col), cell in table.get_celld().items():
    if (row == 0):
        cell.set_text_props(fontproperties=FontProperties(weight='bold', size=7))

plt.axis('off')
plt.show()

将其作为输出产生:

我知道情节是空的,但我打算在那里添加一些数据,所以我需要记住这一点!我想在表格中再添加一行以获得标题。这一行应该只超过最后三列,如下所示:

      +-----------------+
      |      Header     |
+-----+-----------------+
|  A  |  B  |  C  |  D  |
+-----+-----+-----+-----+
| ... | ... | ... | ... |
+-----+-----+-----+-----+
| ... | ... | ... | ... |
+-----+-----+-----+-----+

标题行的宽度应与 A、B 和 C 列的宽度之和相匹配。我一直在玩,但我无法得到它......有人可以帮助我吗?

谢谢!

【问题讨论】:

    标签: python matplotlib graph


    【解决方案1】:

    Matplotlib 表格没有“colspan”或“rowspan”的概念,其中单元格跨越多列或多行。人们可以认为一个单元格的宽度可以是其他单元格的三倍。但是,这会带来不必要的转变

    您可以选择将您通过.add_cell 手动添加的其他单元格的visible_edges 设置到表格顶部。

    可见边缘可以是"T":顶部、"B":底部、"L":左侧或"R":右侧。
    然后将文本设置为中间单元格,使整个内容看起来像一个单元格。

    import matplotlib.pyplot as plt
    
    data = [[1,2,3,4],[6,5,4,3],[1,3,5,1]]
    
    table = plt.table(cellText=data, colLabels=['A', 'B', 'C', 'D'], loc='center', 
                      cellLoc='center', colColours=['#FFFFFF', '#F3CC32', '#2769BD', '#DC3735'])
    table.auto_set_font_size(False)
    h = table.get_celld()[(0,0)].get_height()
    w = table.get_celld()[(0,0)].get_width()
    
    # Create an additional Header
    header = [table.add_cell(-1,pos, w, h, loc="center", facecolor="none") for pos in [1,2,3]]
    header[0].visible_edges = "TBL"
    header[1].visible_edges = "TB"
    header[2].visible_edges = "TBR"
    header[1].get_text().set_text("Header Header Header Header")
    
    plt.axis('off')
    plt.show()
    


    附录

    以上内容不允许为表格单元格的背景着色。为此,可以使用以下解决方法:

    import numpy as np
    import matplotlib.pyplot as plt
    import matplotlib.table
    from matplotlib.collections import LineCollection
    from matplotlib.path import Path
    
    class MyCell(matplotlib.table.CustomCell):
        def __init__(self, *args, visible_edges, **kwargs):
            super().__init__(*args, visible_edges=visible_edges, **kwargs)
            seg = np.array([[0.0, 0.0], [1.0, 0.0], [1.0, 1.0],
                            [0.0, 1.0], [0.0, 0.0]]).reshape(-1, 1, 2)
            segments = np.concatenate([seg[:-1], seg[1:]], axis=1)
            self.edgelines = LineCollection(segments, edgecolor=kwargs.get("edgecolor"))
            self._text.set_zorder(2)
            self.set_zorder(1)
    
        def set_transform(self, trans):
            self.edgelines.set_transform(trans)
            super().set_transform(trans)
    
        def draw(self, renderer):
            c = self.get_edgecolor()
            self.set_edgecolor((1,1,1,0))
            super().draw(renderer)
            self.update_segments(c)
            self.edgelines.draw(renderer)
            self.set_edgecolor(c)
    
        def update_segments(self, color):
            x, y = self.get_xy()
            w, h = self.get_width(), self.get_height()
            seg = np.array([[x, y], [x+w, y], [x+w, y+h],
                            [x, y+h], [x, y]]).reshape(-1, 1, 2)
            segments = np.concatenate([seg[:-1], seg[1:]], axis=1)
            self.edgelines.set_segments(segments)
            self.edgelines.set_linewidth(self.get_linewidth())
            colors = [color if edge in self._visible_edges else (1,1,1,0)
                        for edge in self._edges]
            self.edgelines.set_edgecolor(colors)
    
        def get_path(self):
            codes = [Path.MOVETO] + [Path.LINETO]*3 + [Path.CLOSEPOLY]
            return Path(
                [[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0], [0.0, 0.0]],
                codes, readonly=True)
    
    
    
    matplotlib.table.CustomCell = MyCell
    
    data = [[1,2,3,4],[6,5,4,3],[1,3,5,1]]
    
    table = plt.table(cellText=data, colLabels=['A', 'B', 'C', 'D'], loc='center', 
                      cellLoc='center', colColours=['#FFFFFF', '#F3CC32', '#2769BD', '#DC3735'])
    table.auto_set_font_size(False)
    h = table.get_celld()[(0,0)].get_height()
    w = table.get_celld()[(0,0)].get_width()
    
    # Create an additional Header
    header = [table.add_cell(-1,pos, w, h, loc="center", facecolor="limegreen") for pos in [1,2,3]]
    header[0].visible_edges = "TBL"
    header[1].visible_edges = "TB"
    header[2].visible_edges = "TBR"
    header[1].get_text().set_text("Header")
    
    plt.axis('off')
    plt.show()
    

    但是请注意,由于绘图顺序,如果标题文本比单元格长,这将失败。

    【讨论】:

    • 工作完美,谢谢!只有一件事,您说过“然后将文本设置到中间单元格会使整个内容看起来像一个单元格。”但如果我需要一个长标题文本,第二列的宽度会变大,这是不希望的。你知道怎么解决吗?
    • 如果我执行您的代码,添加行以自动调整宽度 (table.auto_set_column_width((-1, 0, 1, 2, 3))),如原始问题中所述,我得到以下信息: imgur.com/a/xUOOWxX。根据问题的要求,我需要 C 列的宽度在有和没有标题的情况下相同......
    • 不想自动调整宽度时不能自动调整宽度。
    • 好的,没关系。我已经在我的专栏中添加了合适的标题文本,谢谢!
    • 如何将多余的标题放在两列之间
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-27
    • 1970-01-01
    • 2018-06-20
    • 2021-04-22
    相关资源
    最近更新 更多