简体   繁体   中英

How to fit subplot and table into figure area matplotlib

What is the "best" way to preset or adjust the pyplot figure area to fit a subplot and table? I'm trying to generate a bar plot, that has a table directly beneath it. However, if there are more than a certain number of rows in the table, they exceed the figure limits and aren't visible. What is the correct way to ensure the subplot and table will fit within the bounds.

In the provided example, so far all I've found is to adjust the subplot using plt.subplot_adjust(left = 0.2, bottom = 0.2) but the '0.2' adjustment is arbitrary and will need to be changed each time there is a table with more or fewer rows.

import csv
import numpy as np
import matplotlib.pyplot as plt
import matplotlib

dataset = [
    [
        "29%",
        "40%",
        "51%",
        "63%",
        "69%",
        "71%",
        "74%",
        "77%",
        "80%",
        "83%",
        "86%",
        "89%",
        "91%",
        "94%",
        "97%",
        "100%",
    ],
    [
        6524.0,
        8749.0,
        10470.0,
        13096.0,
        13126.0,
        12965.0,
        13493.0,
        13717.0,
        14351.0,
        14993.0,
        15308.0,
        14320.0,
        13179.0,
        9809.0,
        10168.0,
        10621.0,
    ],
    [
        6524.0,
        8749.0,
        10470.0,
        13096.0,
        6827.0,
        5586.0,
        7697.0,
        13717.0,
        14351.0,
        14993.0,
        15308.0,
        14320.0,
        13179.0,
        9809.0,
        10168.0,
        10621.0,
    ],
    [
        6827.0,
        5586.0,
        7697.0,
        13717.0,
        6827.0,
        5586.0,
        7697.0,
        8205.0,
        8298.0,
        8733.0,
        8887.0,
        9278.0,
        9659.0,
        9809.0,
        10168.0,
        10621.0,
    ],
]

fig = plt.figure()
ax = fig.add_subplot(111)

order = np.arange(len(dataset[0]))
print(order)

this = dataset[0]
that = dataset[1]
the_other = dataset[2]


## Create Masks to define which bar chart is shown in front (depending on values)

# Always align = center charts
bar1 = ax.bar(x=order, height=that, width=0.5, bottom=0, align="center", alpha=0.5)
bar2 = ax.bar(x=order, height=the_other, width=0.5, bottom=0, align="center", alpha=0.5)


# Set axes limits and labels *the xlim should number of columns +/- half a unit*
ax.set_xlim(-0.5, len(dataset[0]) - 0.5)
# ax.xaxis.set(ticks=order, ticklabels=elev)

# add the table *The table width is set by 1/ncol by default, plays into what the figures xlim should be*
the_table = plt.table(cellText=dataset, cellLoc="center")
plt.xticks([])
# plt.subplots_adjust(left=0.2, bottom=0.2)

plt.show()

In order to make an automatic adjustment you need to provide bbox argument to a table() constructor, where left bottom corner and the height of bounding box would be automatically calculated form axis bottom and height position. Below is a code where I place axes in a specific location on a figure, and then calculate bbox coordinate out of the axis coordinates.

In this example I set fig_height=3 with purpose to show how the table adjusts at the bottom of the figure.

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.table import table


dataset = [
    [
        "29%", "40%", "51%", "63%", "69%", "71%", "74%", "77%", "80%", "83%", "86%", "89%", "91%", "94%", "97%", "100%",
    ], [
        6524.0, 8749.0, 10470.0, 13096.0, 13126.0, 12965.0, 13493.0, 13717.0, 14351.0, 14993.0, 15308.0, 14320.0,
        13179.0, 9809.0, 10168.0, 10621.0,
    ], [
        6524.0, 8749.0, 10470.0, 13096.0, 6827.0, 5586.0, 7697.0, 13717.0, 14351.0, 14993.0, 15308.0, 14320.0,
        13179.0, 9809.0, 10168.0, 10621.0,
    ], [
        6827.0, 5586.0, 7697.0, 13717.0, 6827.0, 5586.0, 7697.0, 8205.0, 8298.0, 8733.0, 8887.0, 9278.0,
        9659.0, 9809.0, 10168.0, 10621.0,
    ],
]

# Figure size
fig_width, fig_height = 13, 3

# Axes location
ax_left, ax_bottom, ax_width, ax_height = 0.1, 0.3, 0.8, 0.65

# Create a figure
fig = plt.figure(figsize=(fig_width, fig_height))

# Create axes
ax = plt.axes([ax_left, ax_bottom, ax_width, ax_height])

order = np.arange(len(dataset[0]))

this = dataset[0]
that = dataset[1]
the_other = dataset[2]

# Create Masks to define which bar chart is shown in front (depending on values)

# Always align = center charts
bar1 = ax.bar(x=order, height=that, width=0.5, bottom=0, align="center", alpha=0.5)
bar2 = ax.bar(x=order, height=the_other, width=0.5, bottom=0, align="center", alpha=0.5)


# Set axes limits and labels *the xlim should number of columns +/- half a unit*
ax.set_xlim(-0.5, len(dataset[0]) - 0.5)

# add the table *The table width is set by 1/ncol by default, plays into what the figures xlim should be*
# the_table = plt.table(cellText=dataset, cellLoc="center")

#
# Draw a table in a bounding box in relative axes coordinates
# If set bbox to (0, 0, 1, 1) then the table will be drawn perfectly on top of the chart. This means that
# bbox=(0, 0, 1 1) in axes coordinates is equivalent to (ax_left, ax_bottom, ax_width, ax_height) in figure coordinates.
# So, to place the table in the bottom area we just need to scale axes coordinates to figure coordinates.
#
the_table = table(ax, cellText=dataset, cellLoc="center", bbox=(0, -ax_bottom / ax_height, 1, ax_bottom / ax_height))

plt.xticks([])
plt.show()

You should get something like this: 回避的图像

If you set fig_height=7 , then the chart will look more normal: 正常图像

In order to increase or decrease the height occupied by a table just change the ax_bottom parameter. I would keep it between 0.1 and 0.35. Also, adjustment of ax_bottom parameter will change the location of a chart on figure, and it may look shifted a bit. To keep it look nice just make sure that ax_bottom + ax_height is less than 1 but not too small. I prefer to keep ax_bottom + ax_height = 0.95 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM