使用 matplotlib 沿图表绘制表格

Nés*_*tor 0 python graph matplotlib

目前我有这段代码:

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()
Run Code Online (Sandbox Code Playgroud)

将其作为输出生成:

在此处输入图片说明

我知道情节是空的,但我打算在那里添加一些数据,所以我需要记住这一点!我想在表格中再添加一行以有一个标题。这一行应该只在最后三列上,就像这样:

      +-----------------+
      |      Header     |
+-----+-----------------+
|  A  |  B  |  C  |  D  |
+-----+-----+-----+-----+
| ... | ... | ... | ... |
+-----+-----+-----+-----+
| ... | ... | ... | ... |
+-----+-----+-----+-----+
Run Code Online (Sandbox Code Playgroud)

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

谢谢!

Imp*_*est 7

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

在此处输入图片说明

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

可见边缘可以是"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()
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明


附录

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

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()
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

但是请注意,由于绘制顺序,对于标题文本比单元格长的情况,这将失败。