Search code examples
pythonmatplotlibchartsaxis-labels

Matplotlib table and chart overwrites next chart


I started with this issue chart and table and the solution does put the table under the chart.

However the second part of the question is to use this with multiple charts on the same (printed) page. Taking the answer from the previous question and adding another subplot shows that the table overwrites the following chart.

tight_layout does not help (in fact makes it worse).

I did try reserving a row (so total rows are 3 first starts at 0 and next starts at 2) but that leaves a big ugly blank space as the table doesn't even come close to filling up an entire row.

GridSpec doesn't seem to help either, or at least i don't know how to make it solve this problem.

months = [1,2,3,4,5,6,7,8,9,10,11,12]

by_year = [
(2012,  (8,6,8,9,1,2,8,9,4,3,2,6)),
(2013,  (5,6,2,9,6,2,8,9,4,3,2,6)),
(2014,  (7,6,3,9,4,2,8,9,4,3,2,6)),
]

colors = ['r','g','b','y']
import pylab as plt
fig = plt.figure()
ax = plt.subplot2grid((2,1), (0,0))
ax2 = plt.subplot2grid((2,1), (1,0))

#0.9  to leave a small space between groups of bars
import numpy as NP
N = 0.95 / (len(by_year))

cell_text = []
for i, (year, row) in enumerate(by_year):
    print i, year, row
    idx = NP.arange(0, len(months)) + N * i
    # * 0.8 to put a small gap between bars
    ax.bar(idx, row, color=colors[i], width=N * 0.8, label=year)
    cell_text.append(row)

tbl = ax.table(cellText=cell_text, rowLabels=[x[0] for x in by_year], loc='bottom', colLabels=months)
prop = tbl.properties()
ax.set_xticks([])
lgd = ax.legend(loc='upper left', bbox_to_anchor=(1, 1.0))
fig.show()

Solution

  • Well I got this solved. There are two parts to the solution both involve using get and set position.

    The first part is adding the following right after creating the subplot

    current_bbox = ax.get_position()
    current_bbox.y0 = .45
    ax.set_position(current_bbox)
    

    That code will move the bottom up very nicely. The original y0 was at .3629 and i had to play with the numbers to get it right. No way that i can do that programmatically (or at least i don't understand the relationships). But by eyeball and trial and error the value works.

    That fix causes the table now to scrunch up so that each of the rows in the table are too close together. The following code at table creation fixes that (added bbox)

    tbl = ax.table(cellText=cell_text, 
       rowLabels=[x[0] for x in by_year], loc='bottom', 
       bbox[0, -0.2, 1, 0.175],
       colLabels=months)
    

    Again the numbers are eyeballed into place. I'm sure at some point in time someone can add how to calculate these numbers without going through the eyeball adjustments.

    The result now looks like thisenter image description here