在图中移动图形位置(matplotlib)

2 投票
2 回答
10083 浏览
提问于 2025-04-18 05:57

我正在尝试用matplotlib创建一个横向条形图,并且想在旁边放一个表格。我快完成了,但就是没法把表格和图对齐。到目前为止我做的代码是:

import matplotlib
matplotlib.use('Agg')
import numpy as np
import matplotlib.pyplot as plt


# Example data
appsol = ['llolLl', 'nnM', 'lllld bbbblnl', 'x2x', 'foobar', 'EXZ', 'Flups', 'Flaps', 'Foobar Barfooment', 'ABC', 'FABAS', 'common', 'AQT', 'Faberjak', 'simsalsa', 'LESS', 'Wermut']
y_pos = np.arange(len(appsol)) - .3
y_pos_2 = np.arange(len(appsol)) - .1
y_pos_3 = np.arange(len(appsol)) + .1
y_pos_4 = np.arange(len(appsol)) + .3
num_tickets = [4, 4,3,2,6,7,8,1,4,4,3,2,6,7,8,1,9]
num_tickets_2 = [7,6,5,4,3,4,2,1,2,4,1,0,3,0,2,1,0]
num_tickets_3 = [1,2,1,1,1,2,2,3,1,1,2,1,3,1,1,2,3]
num_tickets_4 = [8,7,6,2,13,6,8,9,7,6,5,4,3,6,8,9,12]

bar_width = .2

fig = plt.figure(figsize=(20,20))
ax = fig.add_subplot(111)

# correct yticks
plt.yticks(y_pos_2, appsol)

plt.barh(y_pos, num_tickets, bar_width,  align='center', alpha=0.4, color='r')
plt.barh(y_pos_2, num_tickets_2, bar_width,  align='center', alpha=0.4, color='b')
plt.barh(y_pos_3, num_tickets_3, bar_width,  align='center', alpha=0.4, color='y')
plt.barh(y_pos_4, num_tickets_4, bar_width,  align='center', alpha=0.4, color='g')
plt.yticks(y_pos, appsol)
plt.xlabel('Numbers')
plt.title('Horizontal Bar Chart with table')

# Table

empty_labels = ['' for a in appsol ]
plt.yticks(y_pos_2, empty_labels)
plt.tick_params(\
    axis='y',          # changes apply to the x-axis
    which='both',      # both major and minor ticks are affected
    left='off',      # ticks along the bottom edge are off
    right='off',         # ticks along the top edge are off
    labelbottom='off')

# Adjust layout to make room for the table:
plt.subplots_adjust(left=0.4, bottom=0.2)

cell_text = []
i = len(num_tickets) - 1
for j in num_tickets:
    cell_text.append([num_tickets[i], num_tickets_2[i], num_tickets_3[i], num_tickets_4[i]])
    i -= 1

row_lables = appsol
column_labels = ['So Huge\nMice', 'Elephants', 'Reptiles', 'Germs']

the_table = ax.table(cellText=cell_text,
        rowLabels=row_lables,
        colLabels=column_labels,
        loc='left')
the_table.set_fontsize(15)
the_table.scale(.5,5.0)
plt.savefig('barh_graph.png')
plt.close('all')

运行这个代码后,得到了上面的图片,基本上是我想要的效果,但表格的行和图表的条形没有对齐。所以我需要找到一种方法,要么把图表向下移动半个表格的高度,要么把表格向上移动半个表格的高度。我该怎么做呢?

2 个回答

1

我找到了一种解决方法:我调整了图表的y轴范围:

ax.set_ylim([-.5,17.5])

当然,这些数字只适用于这些数据的维度。所以,如果有人有更好的解决方案,我很想看看。为了完整起见,这里是增强版(我还改变了字体大小并添加了图例):

import matplotlib
matplotlib.use('Agg')
import numpy as np
import matplotlib.pyplot as plt

# set font and size
font = {'family' : 'Bitstream Vera Sans',
        'size'   : 18}
matplotlib.rc('font', **font)

# Example data
appsol = ['llolLl', 'nnM', 'lllld bbbblnl', 'x2x', 'foobar', 'EXZ', 'Flups', 'Flaps', 'Foobar Barfooment', 'ABC', 'FABAS', 'common', 'AQT', 'Faberjak', 'simsalsa', 'LESS', 'Wermut']
y_pos = np.arange(len(appsol)) - .3
y_pos_2 = np.arange(len(appsol)) - .1
y_pos_3 = np.arange(len(appsol)) + .1
y_pos_4 = np.arange(len(appsol)) + .3
num_tickets = [4, 4,3,2,6,7,8,1,4,4,3,2,6,7,8,1,9]
num_tickets_2 = [7,6,5,4,3,4,2,1,2,4,1,0,3,0,2,1,0]
num_tickets_3 = [1,2,1,1,1,2,2,3,1,1,2,1,3,1,1,2,3]
num_tickets_4 = [8,7,6,2,13,6,8,9,7,6,5,4,3,6,8,9,12]

fig = plt.figure(figsize=(20,20))
ax = fig.add_subplot(111)

# correct yticks
plt.yticks(y_pos_2, appsol)
# this aligns table and graph!!!
ax.set_ylim([-.5,17.5])

labels = ['So Huge Mice', 'Elephants', 'Reptiles', 'Germs']
bar_width = .2

plt.barh(y_pos, num_tickets, bar_width,  align='center', alpha=0.4, color='r', label=labels[0])
plt.barh(y_pos_2, num_tickets_2, bar_width,  align='center', alpha=0.4, color='b', label=labels[1])
plt.barh(y_pos_3, num_tickets_3, bar_width,  align='center', alpha=0.4, color='y', label=labels[2])
plt.barh(y_pos_4, num_tickets_4, bar_width,  align='center', alpha=0.4, color='g', label=labels[3])
plt.yticks(y_pos, appsol)
plt.xlabel('Numbers')
plt.title('Horizontal Bar Chart with table')

# Legend
plt.legend(loc='lower center', shadow=True)
num_plots = 4
x_legend = 0.3
y_legend = -0.1
ax.legend(loc='lower center',
    bbox_to_anchor=(x_legend, y_legend),
    ncol=num_plots, # we want the legend on just one line
    shadow=True)
# Table

empty_labels = ['' for a in appsol ]
plt.yticks(y_pos_2, empty_labels)
plt.tick_params(\
    axis='y',          # changes apply to the x-axis
    which='both',      # both major and minor ticks are affected
    left='off',      # ticks along the bottom edge are off
    right='off',         # ticks along the top edge are off
    labelbottom='off')

# Adjust layout to make room for the table:
plt.subplots_adjust(left=0.4, bottom=0.1)

cell_text = []
i = len(num_tickets) - 1
for j in num_tickets:
    cell_text.append([num_tickets[i], num_tickets_2[i], num_tickets_3[i], num_tickets_4[i]])
    i -= 1

row_lables = appsol
column_labels = ['So Huge\nMice', 'Elephants', 'Reptiles', 'Germs']

the_table = ax.table(cellText=cell_text,
        rowLabels=row_lables,
        colLabels=column_labels,
        loc='left')
the_table.set_fontsize(18)
the_table.scale(.5,5.34)

plt.savefig('barh_graph.png')
plt.close('all')

这是它的样子:在这里输入图片描述

5

我觉得如果你创建两个子图,把表格放在左边的子图里会更简单,而不是从现在的单个子图中派生出一个新的子图。如果你把表格加到现有的子图中,可以使用 bbox 来把它在y方向上拉伸到0到1(也就是完全填满)。因为表格有一个标题,所以把右边图的 ylim 设置为(0, n_items),这样两个图就能对齐得很好。同时,因为柱状图也有0.4的偏移(外部柱的偏移加上半个柱宽),所以可以稍微调整一下。这应该能自动适应元素数量的变化。

bar_width = .2

fig, axs = plt.subplots(1,2, figsize=(12,6))
fig.subplots_adjust(wspace=0, top=1, right=1, left=0, bottom=0)

axs[1].barh(y_pos[::-1], num_tickets[::-1], bar_width,  align='center', alpha=0.4, color='r')
axs[1].barh(y_pos_2[::-1], num_tickets_2[::-1], bar_width,  align='center', alpha=0.4, color='b')
axs[1].barh(y_pos_3[::-1], num_tickets_3[::-1], bar_width,  align='center', alpha=0.4, color='y')
axs[1].barh(y_pos_4[::-1], num_tickets_4[::-1], bar_width,  align='center', alpha=0.4, color='g')


axs[1].set_yticks([])
axs[1].set_xlabel('Numbers')
axs[1].set_title('Horizontal Bar Chart with table')
axs[1].set_ylim(0 - .4, (len(appsol)) + .4)

cell_text = list(zip(num_tickets, num_tickets_2, num_tickets_3, num_tickets_4))

row_lables = appsol
column_labels = ['So Huge\nMice', 'Elephants', 'Reptiles', 'Germs']

axs[0].axis('off')

the_table = axs[0].table(cellText=cell_text,
                     rowLabels=row_lables,
                     colLabels=column_labels,
                     bbox=[0.4, 0.0, 0.6, 1.0])

the_table.set_fontsize(15)

plt.savefig('barh_graph.png')
plt.close('all')

enter image description here

如果你仔细看,可能会注意到柱状图是从表格的顶部延伸到底部的,你可以稍微调整一下,让它们从表格上方和下方单元格的中心开始。

撰写回答