'How to make Matplotlib table cell colors work with invisible cell edges?
I am trying to create a table with matplotlib that has some columns that should be visually joined by not sharing borders, and also be colored. Now I can do one or the other, but I can't seem to do both as the setting border edges invisible screws up the colors.
The way it should look with the colors:

The way it should look with the edges:

The way it now looks when I combine both:
This is my example code producing the borked result. You can create the correct colors by commenting out the for loop above plt.show(). If I set all edges to BTLR (= full edges) the colors are fine again.
It would also work for me if I could set the lines from the first image as bolder than the others, but I did not find a way to do that either.
Any help would be appreciated. Seems like a bug in matplotlib to me? Is there a workaround? Maybe I need to do it in plotly or some other tool, but I have never used plotly before and there seems to be a lot less uncomplicated help around for it as compared to matplotlib...
import math
import matplotlib
import matplotlib.pyplot as plt
matplotlib.use('TkAgg')
dpi_value = 100
picture_size_x = 1200
picture_size_y = 600
fig, axs = plt.subplots(figsize=(picture_size_x / dpi_value, picture_size_y / dpi_value), dpi=dpi_value)
axs.axis('tight')
axs.axis('off')
data = [[ 66386, 174296, 75131, 577908, 32015, 49682, 76314],
[ 58230, 381139, 78045, 99308, 160454, 74674, 64311],
[ 89135, 80552, 152558, 497981, 603535, 75312, 25687],
[ 78415, 81858, 150656, 193263, 69638, 14566, 48753],
[ 139361, 331509, 343164, 781380, 52269, 54378, 64745]]
cellcolours_array = [['green', 'green', 'green', 'orange', 'orange', 'orange', 'cyan'],
['green', 'green', 'green', 'orange', 'orange', 'orange', 'cyan'],
['green', 'green', 'green', 'orange', 'orange', 'orange', 'cyan'],
['green', 'green', 'green', 'orange', 'orange', 'orange', 'cyan'],
['green', 'green', 'green', 'orange', 'orange', 'orange', 'cyan']]
columns = ('Freeze', 'Wind', 'Fire', 'Flood', 'Quake', 'Drought', 'Hail')
rows = ['%d year' % x for x in (100, 50, 20, 10, 5)]
the_table = plt.table(cellText=data,
cellColours=cellcolours_array,
rowLabels=rows,
colLabels=columns,
cellLoc='center',
bbox=[0.0, 0.0, 1.0, 1.0]
)
# this here doesnt work right
for row_idx in range(len(data)+1):
for col_idx in range(len(data[0])):
edges = 'horizontal'
if col_idx == 0:
edges = 'BTL'
if (col_idx+1) % 3 == 0:
edges = 'BTR'
ccolor = 'silver'
if (col_idx+1) == len(data[0]):
edges = 'BTR'
the_table[row_idx, col_idx].visible_edges = edges
plt.show()
I tried experimenting with color, facecolor, fill and other things to no avail. I know I can set linewidth to 0 globally, but that won't help me as I need some lines...
Solution 1:[1]
After some deep thinking, I came up with a bandaid solution that works:
I am now creating two tables, one with the edges visible like I want and transparent cells, and one with the colored cells and no edges. Both with the same bbox, the edges-table on top with the higher zorder value. Et voila, I get the desired result:
Here is the code:
import math
import matplotlib
import matplotlib.pyplot as plt
matplotlib.use('TkAgg')
dpi_value = 100
picture_size_x = 1200
picture_size_y = 600
fig, axs = plt.subplots(figsize=(picture_size_x / dpi_value, picture_size_y / dpi_value), dpi=dpi_value)
axs.axis('tight')
axs.axis('off')
data = [[ 66386, 174296, 75131, 577908, 32015, 49682, 76314],
[ 58230, 381139, 78045, 99308, 160454, 74674, 64311],
[ 89135, 80552, 152558, 497981, 603535, 75312, 25687],
[ 78415, 81858, 150656, 193263, 69638, 14566, 48753],
[ 139361, 331509, 343164, 781380, 52269, 54378, 64745]]
columns = ('Freeze', 'Wind', 'Fire', 'Flood', 'Quake', 'Drought', 'Hail')
rows = ['%d year' % x for x in (100, 50, 20, 10, 5)]
edges_table = plt.table(cellText=data,
rowLabels=rows,
colLabels=columns,
cellLoc='center',
bbox=[0.0, 0.0, 1.0, 1.0],
zorder=10
)
for row_idx in range(len(data)+1):
for col_idx in range(len(data[0])):
edges = 'horizontal'
if col_idx == 0:
edges = 'BTL'
if (col_idx+1) % 3 == 0:
edges = 'BTR'
if (col_idx+1) == len(data[0]):
edges = 'BTR'
edges_table[row_idx, col_idx].visible_edges = edges
cellcolours_array = [['green', 'green', 'green', 'orange', 'orange', 'orange', 'cyan'],
['green', 'green', 'green', 'orange', 'orange', 'orange', 'cyan'],
['green', 'green', 'green', 'orange', 'orange', 'orange', 'cyan'],
['green', 'green', 'green', 'orange', 'orange', 'orange', 'cyan'],
['green', 'green', 'green', 'orange', 'orange', 'orange', 'cyan']]
colors_table = plt.table(cellText=data,
cellColours=cellcolours_array,
rowLabels=rows,
colLabels=columns,
cellLoc='center',
bbox=[0.0, 0.0, 1.0, 1.0],
zorder=1
)
for child in edges_table.get_children():
child.set(facecolor=(1.0, 1.0, 1.0, 0.0))
child.set_text_props(color=(1.0, 1.0, 1.0, 0.0))
for child in colors_table.get_children():
child.set(linewidth=0)
plt.show()
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Krusenstern |

