Place multiple plots into one big axis at specific coordinates

走远了吗. 提交于 2019-12-13 03:46:14

问题


I am trying to put multiple matplotlib subplots into a big axis, where tick labels on the big axis correspond to some parameter values for which the data in each subplot has been obtained. Here's an example,

import matplotlib.pyplot as plt
data = {}
data[(10, 10)] = [0.45, 0.30, 0.25]
data[(10, 20)] = [0.2, 0.5, 0.3]
data[(20, 10)] = [0.1, 0.3, 0.6]
data[(20, 20)] = [0.6, 0.15, 0.25]
data[(30, 10)] = [0.4, 0.35, 0.25]
data[(30, 20)] = [0.5, 0.1, 0.4]

# x and y coordinates for the big plot
x_coords = list(set([k[0] for k in data.keys()]))
y_coords = list(set([k[1] for k in data.keys()]))

labels = ['Frogs', 'Hogs', 'Dogs']
explode = (0.05, 0.05, 0.05)  #
colors = ['gold', 'beige', 'lightcoral']

fig, axes = plt.subplots(len(y_coords), len(x_coords))

for row_topToDown in range(len(y_coords)):
    row = (len(y_coords)-1) - row_topToDown
    for col in range(len(x_coords)):
        axes[row][col].pie(data[(x_coords[col], y_coords[row_topToDown])], explode=explode, colors = colors, \
        autopct=None, pctdistance = 1.4, \
        shadow=True, startangle=90, radius=0.7, \
        wedgeprops = {'linewidth':1, 'edgecolor':'Black'}
                                     )
        axes[row][col].axis('equal')  # Equal aspect ratio ensures that pie is drawn as a circle.
        axes[row][col].set_title('(' + str(x_coords[col]) + ', ' + str(y_coords[row_topToDown]) + ')')

fig.tight_layout()        
plt.show()

and here's how I'd like the output to look like:


回答1:


I see two options:

A. use a single axes

You may plot all pie charts to the same axes. Use the center and radius argument to scale the pies in data coordinates. This could look as follows.

import matplotlib.pyplot as plt
data = {}
data[(10, 10)] = [0.45, 0.30, 0.25]
data[(10, 20)] = [0.2, 0.5, 0.3]
data[(20, 10)] = [0.1, 0.3, 0.6]
data[(20, 20)] = [0.6, 0.15, 0.25]
data[(30, 10)] = [0.4, 0.35, 0.25]
data[(30, 20)] = [0.5, 0.1, 0.4]

labels = ['Frogs', 'Hogs', 'Dogs']
explode = [.2]*3
colors = ['gold', 'beige', 'lightcoral']
radius = 4
margin = 2

fig, ax = plt.subplots()

for x,y in data.keys():
    d = data[(x,y)]
    ax.pie(d, explode=explode, colors = colors, center=(x,y), 
            shadow=True, startangle=90, radius=radius, 
            wedgeprops = {'linewidth':1, 'edgecolor':'Black'})

    ax.annotate("({},{})".format(x,y), xy = (x, y+radius), 
                xytext = (0,5), textcoords="offset points", ha="center")

ax.set_frame_on(True)
xaxis = list(set([x for x,y in data.keys()]))
yaxis = list(set([y for x,y in data.keys()]))
ax.set(aspect="equal", 
       xlim=(min(xaxis)-radius-margin,max(xaxis)+radius+margin), 
       ylim=(min(yaxis)-radius-margin,max(yaxis)+radius+margin), 
       xticks=xaxis, yticks=yaxis)
fig.tight_layout()        
plt.show()

B. use inset axes

You can put each pie in its own axes and position the axes in data coordinates. This is facilitated by using mpl_toolkits.axes_grid1.inset_locator.inset_axes. The main difference to the above is that you may use a non-equal aspect of the parent axes, and that it's not possible to use tight_layout.

import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.inset_locator import inset_axes

data = {}
data[(10, 10)] = [0.45, 0.30, 0.25]
data[(10, 20)] = [0.2, 0.5, 0.3]
data[(20, 10)] = [0.1, 0.3, 0.6]
data[(20, 20)] = [0.6, 0.15, 0.25]
data[(30, 10)] = [0.4, 0.35, 0.25]
data[(30, 20)] = [0.5, 0.1, 0.4]


labels = ['Frogs', 'Hogs', 'Dogs']
explode = [.05]*3
colors = ['gold', 'beige', 'lightcoral']
radius = 4
margin = 2

fig, axes = plt.subplots()

for x,y in data.keys():
    d = data[(x,y)]
    ax = inset_axes(axes, "100%", "100%", 
                    bbox_to_anchor=(x-radius, y-radius, radius*2, radius*2),
                    bbox_transform=axes.transData, loc="center")
    ax.pie(d, explode=explode, colors = colors,
            shadow=True, startangle=90,
            wedgeprops = {'linewidth':1, 'edgecolor':'Black'})

    ax.set_title("({},{})".format(x,y))


xaxis = list(set([x for x,y in data.keys()]))
yaxis = list(set([y for x,y in data.keys()]))
axes.set(aspect="equal", 
       xlim=(min(xaxis)-radius-margin,max(xaxis)+radius+margin), 
       ylim=(min(yaxis)-radius-margin,max(yaxis)+radius+margin), 
       xticks=xaxis, yticks=yaxis)

plt.show()


For how to put a legend outside the plot, I would refer you to How to put the legend out of the plot. And for how to create a legend for a pie chart to How to add a legend to matplotlib pie chart?
Also Python - Legend overlaps with the pie chart may be of interest.



来源:https://stackoverflow.com/questions/53382914/place-multiple-plots-into-one-big-axis-at-specific-coordinates

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!