I've a pandas
DataFrame
plotted as a table using matplotlib
(from this answer).
Now I want to set the bottom edge color of a given row and I've this code:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
import sixdf = pd.DataFrame()
df['date'] = ['2016-04-01', '2016-04-02', '2016-04-03', '2016-04-04']
df['calories'] = [2200, 2100, 1500, 1800]
df['sleep hours'] = [2200, 2100, 1500, 1500]
df['gym'] = [True, False, False, True]def render_mpl_table(data, col_width=3.0, row_height=0.625, font_size=14,header_color='#40466e', row_colors=['#f1f1f2', 'w'], edge_color='w',bbox=[0, 0, 1, 1], header_columns=0,ax=None, **kwargs):if ax is None:size = (np.array(data.shape[::-1]) + np.array([0, 1])) * np.array([col_width, row_height])fig, ax = plt.subplots(figsize=size)ax.axis('off')mpl_table = ax.table(cellText=data.values, bbox=bbox, colLabels=data.columns, **kwargs)mpl_table.auto_set_font_size(False)mpl_table.set_fontsize(font_size)for k, cell in six.iteritems(mpl_table._cells):cell.set_edgecolor(edge_color)if k[0] == 0 or k[1] < header_columns:cell.set_text_props(weight='bold', color='w')cell.set_facecolor(header_color)else:cell.set_facecolor(row_colors[k[0]%len(row_colors) ])return axdef get_table(ax):table = Nonefor child in ax.get_children():if isinstance(child, matplotlib.table.Table):table = childreturn tablereturn tabledef set_row_edge_color(ax, row, color):table = get_table(ax)for k, cell in six.iteritems(table._cells):if (k[0] == row):cell.set_edgecolor(color)ax = render_mpl_table(df, header_columns=0, col_width=2.0)
set_row_edge_color(ax, 2, 'k')
plt.show()
I'm unable to set only the color of row bottom and it gets set like this:
Is there a way to set only the row bottom color like this?
Or is there a way to locate row in the figure/plot and draw a horizontal line?
There is no general way to make lines of different thickness or color on individual sides of cells (Rectangle
s) in matplotlib. In the case of the question, the solution is however quite easily obtained via ax.axhline()
(as commented by @GAnderson) due to the table filling the entire bounding box of the axes.
You would first need to set the data range of the axes to range between -1 and the number of rows in the table. Then you can just plot an axhline
at the position of choice.
There are only two line changed (which I marked with a comment) and it seems you can completely get rid of the get_table
function.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
import sixdf = pd.DataFrame()
df['date'] = ['2016-04-01', '2016-04-02', '2016-04-03', '2016-04-04']
df['calories'] = [2200, 2100, 1500, 1800]
df['sleep hours'] = [2200, 2100, 1500, 1500]
df['gym'] = [True, False, False, True]def render_mpl_table(data, col_width=3.0, row_height=0.625, font_size=14,header_color='#40466e', row_colors=['#f1f1f2', 'w'], edge_color='w',bbox=[0, 0, 1, 1], header_columns=0,ax=None, **kwargs):if ax is None:size = (np.array(data.shape[::-1]) + np.array([0, 1])) * np.array([col_width, row_height])fig, ax = plt.subplots(figsize=size)ax.axis('off')ax.axis([0,1,data.shape[0],-1]) ## <---------- Change herempl_table = ax.table(cellText=data.values, bbox=bbox, colLabels=data.columns, **kwargs)mpl_table.auto_set_font_size(False)mpl_table.set_fontsize(font_size)for k, cell in six.iteritems(mpl_table._cells):cell.set_edgecolor(edge_color)if k[0] == 0 or k[1] < header_columns:cell.set_text_props(weight='bold', color='w')cell.set_facecolor(header_color)else:cell.set_facecolor(row_colors[k[0]%len(row_colors) ])return axdef set_row_edge_color(ax, row, color):ax.axhline(y=row, color=color) ## <---------- Change hereax = render_mpl_table(df, header_columns=0, col_width=2.0)
set_row_edge_color(ax, 2, 'k')
plt.show()