16

I'm trying to make a table using matplotlib and I've managed to get my data in but I'm struggling with the final formatting. I need to edit the size of the figure to include all my data as some is getting chopped off. Here is my current code:

for struct, energy, density in clust_data:
    fig=plt.figure()
    ax = plt.gca()
    ax.xaxis.set_visible(False)
    ax.yaxis.set_visible(False)
    colLabels=("Structure", "Energy", "Density")
    rows=len(clust_data)
    cellText=[]
    for row in clust_data:
        cellText.append(row)
    the_table = ax.table(cellText=cellText,
              colLabels=colLabels,
              loc='center')
    plt.savefig("table.png")

Which creates a table like so (I'm not completely sure how to get ride of the lines through certain rows either): enter image description here

Any help is greatly appreciated!

1
  • 1
    [This is not an answer] You're doing a double loop over the same list (clust_data) and the outer loop does nothing more than creating and saving len(clust_data): is the first for loop a typo? Commented Jun 21, 2013 at 14:09

2 Answers 2

14

You should be able to solve your problems doing the following:

  • Figure size (edit):

    • Measure how high and wide is a cell (e.g. hcell=0.3, wcell=1)
    • Get/know the number of rows and columns (in your case len(clust_data)+1 and 3)
    • create the figure with the correct size (you might want some extra padding)

      fig = plt.figure(figsize=(3*wcell+wpad, nrows*hcell+hpad))
      
  • The lines within the two rows are the axes spines.

    ax.xaxis.set_visible(False)
    ax.yaxis.set_visible(False)
    

    just hide the axis labels and ticks, not the axes spines. You have to hide them or colour them in white

see full solution below


In any case: it looks to me that you are doing a whole lot of useless operations. From your piece of code it seems to me that clust_data is already a list of lists with the correct shape and that cellText after being filled is going to be the same of clust_data.
Furthermore, try not to mix the OO and pyplot interface of matplotlib.

The following code should be equivalent to yours

fig=plt.figure()
ax = fig.add_subplot(111)
ax.xaxis.set_visible(False)
ax.yaxis.set_visible(False)
colLabels=("Structure", "Energy", "Density")
the_table = ax.table(cellText=clust_data,
          colLabels=colLabels,
          loc='center')
plt.savefig("table.png")

Edit: full solution

Convoluted way

You have to hide the axes spines (e.g. setting their color white) and give them low zorder then add the table with higher zorder

colLabels=("Structure", "Energy", "Density")
nrows, ncols = len(clust_data)+1, len(colLabels)
hcell, wcell = 0.3, 1.
hpad, wpad = 0, 0    

fig=plt.figure(figsize=(ncols*wcell+wpad, nrows*hcell+hpad))
ax = fig.add_subplot(111)
#remove axis ticks and labels
ax.xaxis.set_visible(False)
ax.yaxis.set_visible(False)
#hide the spines
for sp in ax.spines.itervalues():
    sp.set_color('w')
    sp.set_zorder(0)
#do the table
the_table = ax.table(cellText=clust_data,
          colLabels=colLabels,
          loc='center')
#put the table in front of the axes spines 
#for some reason zorder is not a keyword in ax.table
the_table.set_zorder(10)
plt.savefig("table.png")

Simple way (credit @JoeKington)

Just switch off the axis

colLabels=("Structure", "Energy", "Density")
nrows, ncols = len(clust_data)+1, len(colLabels)
hcell, wcell = 0.3, 1.
hpad, wpad = 0, 0    
fig=plt.figure(figsize=(ncols*wcell+wpad, nrows*hcell+hpad))
ax = fig.add_subplot(111)
ax.axis('off')
#do the table
the_table = ax.table(cellText=clust_data,
          colLabels=colLabels,
          loc='center')
plt.savefig("table.png")
Sign up to request clarification or add additional context in comments.

8 Comments

Thanks for the extensive help! This solves the problem with the spines but still doesn't include my entire data set, there should be rows both above and below the limits of the table EDIT Also clust_data is just one list that contains 3 values per item (x,y,z)
@FrancescoMontesano - You don't need to jump through so many hoops to hide things. Half of your example code could be replaced with ax.axis('off'). You can leave out all of the set_visible(False), set_color('w') and set_zorder(...).
So above and below the table is a lot of whitespace, I have to zoom in to make out any details
@Jsg91 - Try using fig.savefig('table.png', bbox_inches='tight', bbox_extra_artists=[table]) to remove the whitespace. (This will also crop "out" of the figure. If the table extends beyond the figure boundaries, the whole table will be shown in the saved image, rather than just what you'd see if you did plt.show().)
@FrancescoMontesano - thanks! Just so you know, there is a typo in the Simple Way code: len(colLables) should be len(colLabels)
|
6

It is just a curiosity. You can print your table from latex. If you try this code,

import matplotlib.pyplot as plt
import numpy as np

table = r'\begin{table} \begin{tabular}{|l|l|l|}  \hline  $\alpha$      & $\beta$        & $\gamma$      \\ \hline   32     & $\alpha$ & 123    \\ \hline   200 & 321    & 50 \\  \hline  \end{tabular} \end{table}'
plt.plot(np.arange(100))
plt.text(10,80,table, size=50)
plt.show()

you will see a beatifull table in the top left of the plot. Now, it is almost straight-forward to write a function to transform your data into a string like the previous latex table.

3 Comments

the tiniest of quibbles -- I think you need to add the lines import matplotlib as mpl; mpl.rc('text', usetex=True) to be sure the latex renders. Nice solution however!
yes, that's right. Although I encourage to modify those lines in the matplotlibrc file.
Unfortunately, I often find myself in the situation where I am sending single code files to users who need them to "just work" when they run them. (so in my code, also a switch to entirely not use latex if their machine doesn't have it). Such is life I suppose...

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.