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!

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Jsg91
  • 465
  • 2
  • 6
  • 12
  • 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? – Francesco Montesano Jun 21 '13 at 14:09

2 Answers2

13

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")
Francesco Montesano
  • 8,485
  • 2
  • 40
  • 64
  • 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) – Jsg91 Jun 21 '13 at 15:07
  • 6
    @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(...)`. – Joe Kington Jun 21 '13 at 15:16
  • Awesome Thanks a lot! How would I remove the whitespace at the top and bottom of the table? – Jsg91 Jun 21 '13 at 15:24
  • @JoeKington: thanks. I didn't know about that. I'll update my answer (again) – Francesco Montesano Jun 21 '13 at 15:31
  • 1
    So above and below the table is a lot of whitespace, I have to zoom in to make out any details – Jsg91 Jun 21 '13 at 15:44
  • 3
    @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()`.) – Joe Kington Jun 21 '13 at 15:51
  • @FrancescoMontesano I've tried all of this and for some reason my table is still really small, and there's a ton of whitespace above the table. The whitespace above the table also seems to increase with the numbe of rows. This results in a table with lots of whitespace above it, then a title which looks very separated from the table. Also, the text looks really small. Any clues? – xheyhenry Nov 02 '16 at 00:14
  • 1
    @FrancescoMontesano - thanks! Just so you know, there is a typo in the Simple Way code: `len(colLables)` should be `len(colLabels)` – Roberto Sep 12 '17 at 19:04
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.

Alejandro
  • 3,263
  • 2
  • 22
  • 38
  • 4
    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! – CompEcon Sep 14 '15 at 12:34
  • yes, that's right. Although I encourage to modify those lines in the matplotlibrc file. – Alejandro Sep 16 '15 at 17:32
  • 2
    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... – CompEcon Sep 18 '15 at 15:00