Двойной заголовок в таблице Matplotlib - PullRequest
0 голосов
/ 14 декабря 2018

Мне нужно построить таблицу в matplotlib.Проблема в том, что некоторые столбцы имеют одноуровневые заголовки, некоторые столбцы имеют двухуровневые заголовки.

Вот что мне нужно:

Table needed

Вот простой пример одноуровневых заголовков:

df = pd.DataFrame()
df['Animal'] = ['Cow', 'Bear']
df['Weight'] = [250, 450]
df['Favorite'] = ['Grass', 'Honey']
df['Least Favorite'] = ['Meat', 'Leaves']
df

enter image description here

fig = plt.figure(figsize=(9,2))
ax=plt.subplot(111)
ax.axis('off') 
table = ax.table(cellText=df.values, colColours=['grey']*df.shape[1], bbox=[0, 0, 1, 1], colLabels=df.columns)
plt.savefig('Table.jpg')

Последний фрагмент кода создает следующую картинку:

enter image description here

Какие изменения делаютМне нужно, чтобы у меня был стол?

Ответы [ 3 ]

0 голосов
/ 17 декабря 2018

Еще одним вариантом будет использование matplotlib.gridspec.GridSpec для построения значений и столбцов с использованием пользовательского макета:

def format_axes(fig):
    for i, ax in enumerate(fig.axes):
        ax.tick_params(labelbottom=False, labelleft=False, labelright=False)
        ax.get_xaxis().set_ticks([])
        ax.get_yaxis().set_ticks([])


df = pd.DataFrame()
df['Animal'] = ['Cow', 'Bear']
df['Weight'] = [250, 450]
df['Favorite'] = ['Grass', 'Honey']
df['Least Favorite'] = ['Meat', 'Leaves']

fig = plt.figure(figsize=(9, 2))


gs = GridSpec(3, 4, figure=fig, wspace=0.0, hspace=0.0,height_ratios=[1, 1, 4])
# plot table header
ax1 = fig.add_subplot(gs[:-1, 0])
ax1.text(0.5, 0.5, df.columns[0], va="center", ha="center")
ax2 = fig.add_subplot(gs[:-1, 1])
ax2.text(0.5, 0.5, df.columns[1], va="center", ha="center")
ax3 = fig.add_subplot(gs[0, -2:])
ax3.text(0.5, 0.5, "Food", va="center", ha="center")
ax4 = fig.add_subplot(gs[1, -2])
ax4.text(0.5, 0.5, df.columns[2], va="center", ha="center")
ax5 = fig.add_subplot(gs[1, -1])
ax5.text(0.5, 0.5, df.columns[3], va="center", ha="center")
# plot table data
ax6 = fig.add_subplot(gs[-1, :])
table = ax6.table(cellText=df.values, cellLoc='center', bbox=[0, 0, 1, 1])

format_axes(fig)

plt.show()

Результат

enter image description here

0 голосов
/ 17 декабря 2018

Решение для слияния ячеек

Вы можете объединить ячейки, созданные с помощью ax.table, как функция слияния ячеек в электронной таблице Excel.Это позволяет полностью автоматизировать решение, в котором вам не нужно возиться с какими-либо координатами (за исключением индексов ячейки, которую вы хотите объединить):

import matplotlib.pyplot as plt
import pandas as pd

df = pd.DataFrame()
df['Animal'] = ['Cow', 'Bear']
df['Weight'] = [250, 450]
df['Favorite'] = ['Grass', 'Honey']
df['Least Favorite'] = ['Meat', 'Leaves']

fig = plt.figure(figsize=(9,2))
ax=fig.gca()
ax.axis('off')
r,c = df.shape

# ensure consistent background color
ax.table(cellColours=[['lightgray']] + [['none']], bbox=[0,0,1,1])

# plot the real table
table = ax.table(cellText=np.vstack([['', '', 'Food', ''], df.columns, df.values]), 
                 cellColours=[['none']*c]*(2 + r), bbox=[0, 0, 1, 1])

# need to draw here so the text positions are calculated
fig.canvas.draw()

# do the 3 cell merges needed
mergecells(table, (1,0), (0,0))
mergecells(table, (1,1), (0,1))
mergecells(table, (0,2), (0,3))

Вывод:

enter image description here

Вот код для функции mergecells, использованной выше:

import matplotlib as mpl

def mergecells(table, ix0, ix1):
    ix0,ix1 = np.asarray(ix0), np.asarray(ix1)
    d = ix1 - ix0
    if not (0 in d and 1 in np.abs(d)):
        raise ValueError("ix0 and ix1 should be the indices of adjacent cells. ix0: %s, ix1: %s" % (ix0, ix1))

    if d[0]==-1:
        edges = ('BRL', 'TRL')
    elif d[0]==1:
        edges = ('TRL', 'BRL')
    elif d[1]==-1:
        edges = ('BTR', 'BTL')
    else:
        edges = ('BTL', 'BTR')

    # hide the merged edges
    for ix,e in zip((ix0, ix1), edges):
        table[ix[0], ix[1]].visible_edges = e

    txts = [table[ix[0], ix[1]].get_text() for ix in (ix0, ix1)]
    tpos = [np.array(t.get_position()) for t in txts]

    # center the text of the 0th cell between the two merged cells
    trans = (tpos[1] - tpos[0])/2
    if trans[0] > 0 and txts[0].get_ha() == 'right':
        # reduce the transform distance in order to center the text
        trans[0] /= 2
    elif trans[0] < 0 and txts[0].get_ha() == 'right':
        # increase the transform distance...
        trans[0] *= 2

    txts[0].set_transform(mpl.transforms.Affine2D().translate(*trans))

    # hide the text in the 1st cell
    txts[1].set_visible(False)
0 голосов
/ 17 декабря 2018

Полагаю, что единственный способ - добавить заголовки вручную.Вы можете контролировать их точное положение и размер с помощью аргумента bbox.Смотрите мой пример ниже.Вы можете получить более подробную информацию из этого ответа: https://stackoverflow.com/a/37440236/2912478

#!/usr/bin/env python

import pandas as pd
import matplotlib.pyplot as plt

df = pd.DataFrame()
df['Animal'] = ['Cow', 'Bear']
df['Weight'] = [250, 450]
df['Favorite'] = ['Grass', 'Honey']
df['Least Favorite'] = ['Meat', 'Leaves']
df

fig = plt.figure(figsize=(9,2))
ax=plt.subplot(111)
ax.axis('off') 

plt.table(cellText=[['Animal', 'Weight']],
                     loc='bottom',
                     bbox=[0, 0.6, 0.5, 0.3]
                     )

plt.table(cellText=[['Food']],
                     loc='bottom',
                     bbox=[0.5, 0.75, 0.5, 0.15]
                     )

plt.table(cellText=[['Favorite', 'Least favorite']],
                     loc='bottom',
                     bbox=[0.5, 0.6, 0.5, 0.15]
                     )

plt.table(cellText=df.values,
                     loc='bottom',
                     bbox=[0, 0, 1, 0.6]
                     )

plt.show()

Вот вывод, который я получаю:

enter image description here

...