Matplotlib表格格式化 - 改变行标签单元格的宽度

9
我有一个明显的问题,这个表格的行标签在图形外面,我不知道如何修复它。我知道我可以进入子艺术家并在那里更改高度和宽度等内容,但我已经尝试过了,没有起作用,所以也许你现在可以帮助我。
这是我用来创建它的代码,希望它不太难读.... :
ind1=np.arange(5)


figure()
axes([0.2, 0.45, 0.7, 0.45])

## define different bars
l1=bar((ind1-0.45),mean_morphing_cc[0:5],width=0.2,bottom=0,color='darkblue',yerr=[min_dif_morphing_cc[0:5],max_dif_morphing_cc[0:5]],error_kw=dict(elinewidth=2, ecolor='darkkhaki'))

l2=bar((ind1-0.25),mean_persistence_cc[0:5],width=0.2,bottom=0,color='darkred',yerr=[min_dif_persistence_cc[0:5],max_dif_persistence_cc[0:5]],error_kw=dict(elinewidth=2, ecolor='darkkhaki'))

l3=bar((ind1+0.05),mean_m_vs_p_cc[0:5],width=0.2,bottom=0,color='purple',yerr=[min_dif_m_vs_p_cc[0:5],max_dif_m_vs_p_cc[0:5]],error_kw=dict(elinewidth=2, ecolor='darkkhaki'))

## print grid and a horizontal line at "0"
grid(True, linestyle='-', which='major', color='lightgrey',alpha=0.5)

hlines(0, -0.5,(max(ind1)+0.5), colors='k', linestyles='solid')


ylabel('mean((cloud cover_forecast/cloud cover_observation)-1),\n mean("morphing" - "persistence")',horizontalalignment='right',multialignment='center',size='xx-small')

xlim(-0.5,(max(ind1)+0.5))

xticks(ind1,[])

## print a legend
legend((l1[0],l2[0],l3[0]),('mean morphing cloud cover','mean persistence cloud cover','mean morphing vs persistence error'),'lower center',ncol=2,bbox_to_anchor=(0.5,-0.92),borderpad=0.2,labelspacing=0.2,handlelength=1,handletextpad=0.2)

leg = plt.gca().get_legend()

ltext  = leg.get_texts()  # all the text.Text instance in the legend

llines = leg.get_lines()  # all the lines.Line2D instance in the legend

frame  = leg.get_frame()  # the patch.Rectangle instance surrounding the legend

frame.set_facecolor('0.90')      # set the frame face color to light gray

plt.setp(ltext, fontsize='x-small')    # the legend text fontsize

## print the title
title('cloud cover over- or underestimation\n morphing forecast compared to persistence',size='small')

## print the table
the_table=plt.table(cellText=[[str(i)[:4] for i in mean_morphing_cc[0:5]],max_morphing_cc[0:5],min_morphing_cc[0:5],mean_persistence_cc[0:5],max_persistence_cc[0:5],min_persistence_cc[0:5],mean_m_vs_p_cc[0:5],max_m_vs_p_cc[0:5],min_m_vs_p_cc[0:5]],
                    rowLabels=['morphing: mean','morphing: max','morphing: min','persistence: mean','persistence: max','persistence: min','morph vs per: mean','morph vs per: max','morph vs per: min'],
                    rowColours=['darkblue','darkblue','darkblue','darkred','darkred','darkred','purple','purple','purple'],colLabels=['t+1','t+2','t+3','t+4','t+5'],loc='bottom')

## change cell properties
table_props=the_table.properties()
table_cells=table_props['child_artists']
for cell in table_cells:
    cell.set_width(0.2)
    cell.set_height(0.065)
    cell.set_fontsize(12)

show()
3个回答

2
我还没有想出完美的答案,但是我找到了一个对我自己有用的解决方案。
调整colWidth和table width可以缩小rowLabel列的宽度。在源代码中,实际上有一个他们使用的变量rowLabelWidth,但他们不允许用户设置它。无论如何,首先我将重写你现有的代码,这样你就可以看到哪里进行了更改。这是原始的变量格式:
## setting properties to variables to make table function easier to read
data = [[str(i)[:4] for i in mean_morphing_cc[0:5]],max_morphing_cc[0:5],min_morphing_cc[0:5],mean_persistence_cc[0:5],max_persistence_cc[0:5],min_persistence_cc[0:5],mean_m_vs_p_cc[0:5],max_m_vs_p_cc[0:5],min_m_vs_p_cc[0:5]]
rowLabels = ['morphing: mean','morphing: max','morphing: min','persistence: mean','persistence: max','persistence: min','morph vs per: mean','morph vs per: max','morph vs per: min']
rowColours = ['darkblue','darkblue','darkblue','darkred','darkred','darkred','purple','purple','purple']
colLabels = ['t+1','t+2','t+3','t+4','t+5']
loc = 'bottom'

## without changing anything, this is what your table function would look like
the_table=plt.table(cellText = data,
                rowLabels = rowLabels, rowColours = rowColours,
                colLabels = colLabels, loc = loc)

以下是rowLabelWidth源代码的内容,我们将使用它来帮助确定width和colWidth的设置。
# Do row labels
if rowLabels is not None:
    for row in xrange(rows):
        table.add_cell(row + offset, -1,
                       width=rowLabelWidth or 1e-15, height=height,
                       text=rowLabels[row], facecolor=rowColours[row],
                       loc=rowLoc)
    if rowLabelWidth == 0:
        table.auto_set_column_width(-1)

看起来您已经将图表的宽度设置为axes([0.2, 0.45, 0.7, 0.45])中的0.7,因此我们将其设置为一个变量tb_width。
tb_width = 0.7

rowLabelWidth会自动调整大小,这并没有真正帮助我们。但是如果您尝试以下三个colWidths选项,您可以开始找出如何使其按照您想要的方式工作。添加bbox属性以明确指定表格应该放置在哪里。需要注意的重要事项是,似乎rowLabelWidth未包含在总表宽度中。
## standard - essentially what happens when you don't specify colWidths. Takes the table width, divides it by the number of columns, giving each column an equal width.
colWidths = [tb_width/n_cols] * n_cols
## rowLabels stick out on the left

## similar to the above, but the '+1' attempts to account for the fact that another column's width, rowLabels, should fit inside the overall table width
colWidths=[( tb_width / (n_cols + 1) )] * n_cols  

## set your own width. this will start messing with the width of the rowLabelsWidth as now the colWidths aren't perfectly proportioned within the table width
tb_colWidth = 0.08
colWidths = [tb_colWidth] * n_cols

为确保行标签恰好位于图表下方而不突出左侧,请使用bbox坐标。以表格的左下角作为参考点,定位表格:bbox = [x_coordinate,y_coordinate,width,height]。如果将x_coordinate设置为考虑tb_colWidth,则它将精确移动表格,使得行标签列的最左侧直接位于上面图表的左上角下方。
bbox = [tb_colWidth, y_coordinate, tb_width, tb_height]

如果现在导致最右边的列突出图表之外,则将宽度缩小一个列的大小:
bbox = [tb_colWidth, y_coordinate, tb_width - tb_colWidth, tb_height]

现在把它们放在一起:
the_table=plt.table(cellText = data,
            rowLabels = rowLabels, rowColours = rowColours,
            colLabels = colLabels, loc = 'bottom',
            colWidths = colWidths, bbox = bbox)

你不应该再进行最终表格单元格宽度的调整循环,而是可以使用上述工具来控制它。

1

虽然这个问题已经很久以前被问过了,但我找到了一个适合我的解决方案,可以帮助其他人。

注意:目前我正在使用matplotlib的版本3.5.3

你在代码的这一部分已经接近解决方案了。你只需要修改正确的单元格即可。

## print the table
the_table=plt.table(cellText=[[str(i)[:4] for i in mean_morphing_cc[0:5]],max_morphing_cc[0:5],min_morphing_cc[0:5],mean_persistence_cc[0:5],max_persistence_cc[0:5],min_persistence_cc[0:5],mean_m_vs_p_cc[0:5],max_m_vs_p_cc[0:5],min_m_vs_p_cc[0:5]],
                    rowLabels=['morphing: mean','morphing: max','morphing: min','persistence: mean','persistence: max','persistence: min','morph vs per: mean','morph vs per: max','morph vs per: min'],
                    rowColours=['darkblue','darkblue','darkblue','darkred','darkred','darkred','purple','purple','purple'],colLabels=['t+1','t+2','t+3','t+4','t+5'],loc='bottom')

## change cell properties
table_props=the_table.properties()table_cells=table_props['child_artists']
for cell in table_cells:
    cell.set_width(0.2)
    cell.set_height(0.065)
    cell.set_fontsize(12)

如果我们打印属性的键,我们会得到下面的列表:

for property in table.properties():
    print(property)

agg_filter
alpha
animated
celld
children
clip_box
clip_on
clip_path
figure
gid
in_layout
label
path_effects
picker
rasterized
sketch_params
snap
transform
transformed_clip_path_and_affine
url
visible
zorder

我们需要集中关注celld和children的内容。 celld是每个单元格的坐标列表,包括行标签。
for cell in table.properties()["celld"]:
     print(cell)
(coord_x, coord_y)
(1, 0)
(1, 1)
(2, 0)
(2, 1)
(3, 0)
(3, 1)
(4, 0)
(4, 1)
(0, 0)
(0, 1)
(1, -1)
(2, -1)
(3, -1)
(4, -1)

注意:列表中的项目数量在每种情况下都会有所变化。

行标签单元格是y_coord为-1且x_coord从1开始的单元格。我们需要修改这些单元格。

Children属性与相同的列表,但填充了矩形对象。

for cell in table.properties()["children"]:
     print(cell)
Rectangle(xy=(0, 0), width=0.7, height=0.04329, angle=0)
Rectangle(xy=(0, 0), width=0.7, height=0.04329, angle=0)
Rectangle(xy=(0, 0), width=0.7, height=0.04329, angle=0)
Rectangle(xy=(0, 0), width=0.7, height=0.04329, angle=0)
Rectangle(xy=(0, 0), width=0.7, height=0.04329, angle=0)
Rectangle(xy=(0, 0), width=0.7, height=0.04329, angle=0)
Rectangle(xy=(0, 0), width=0.7, height=0.04329, angle=0)
Rectangle(xy=(0, 0), width=0.7, height=0.04329, angle=0)
Rectangle(xy=(0, 0), width=0.7, height=0.04329, angle=0)
Rectangle(xy=(0, 0), width=0.7, height=0.04329, angle=0)
Rectangle(xy=(0, 0), width=0.7, height=0.04329, angle=0)
Rectangle(xy=(0, 0), width=0.7, height=0.04329, angle=0)
Rectangle(xy=(0, 0), width=0.7, height=0.04329, angle=0)
Rectangle(xy=(0, 0), width=0.7, height=0.04329, angle=0)

我们可以看到,每个矩形都没有指定坐标。但我发现它们在列表中的位置就像单元格列表一样。

--- 解决方案 ---

虽然我构建了一个饼图,但这个表格代码也适用于其他图表。

import matplotlib.pyplot as plt

columns_name = ["Column 1", "Column2"]
data = [data1, data2, data3, data4]
rows = [[data1, "value1"], [data2, value2], [data3, "value3"], 
["data4", "value4"]]

fig, ax = plt.subplots(figsize=(13.5, 7), subplot_kw=dict(aspect="equal"))
ax.pie(data, radius=1)
        
# get default colors
colors = plt.rcParams["axes.prop_cycle"].by_key()["color"]

table = plt.table(cellText=rows, rowColours=colors, colLabels=columns_name,
colLoc='center', cellLoc='left')
table.scale(1.4, 1.4)


for cell in table.properties()["children"]:
     print(cell)

# RowLabelCell width modification
for i in range(len(data)):
     table.properties()["children"][(i*-1)-1].set_width(0.10)

plt.tight_layout()
plt.show()

在for循环的范围内,您必须放置与表格参数cellText或数据列表中使用的相同列表以构建图表。

我建议在函数set_width()中使用非常低的值。

--- 结果 ---

我会给您展示我的结果图片。

图表和表格结果


0

我曾经遇到过这个问题,通过将行标签的对齐方式从“左”改为“右”,我部分地解决了它。

cellDict = the_table.get_celld()
for x in range(1, len(row_labels)+1):
    cellDict[(x,-1)]._loc = 'right'

get_celld() 返回一个单元格字典,cellDict[(x,-1)] 选择第 x 行和第 -1 列的单元格,即行标签列。

这不会改变行标签列的宽度,因此您可能仍然在标签左侧有空白。我的标签向左越过了屏幕,但至少我现在可以看到行标签中的所有文本。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接