I have the following code:
import matplotlib.pyplot as plt
plt.style.use('ggplot')
import numpy as np
np.random.seed(123456)
import pandas as pd
df = pd.DataFrame(3 * np.random.rand(4, 4), index=['a', 'b', 'c', 'd'], columns=['x', 'y','z','w'])
f, axes = plt.subplots(1,4, figsize=(10,5))
for ax, col in zip(axes, df.columns):
df[col].plot(kind='pie', autopct='%.2f', ax=ax, title=col, fontsize=10)
ax.legend(loc=3)
plt.ylabel("")
plt.xlabel("")
plt.show()
Which makes the following plot:
How can I make the following:
MatPlotLib with Python Set the figure size and adjust the padding between and around the subplots. Make a list of labels, colors, and sizes. Use pie() method to get patches and texts with colors and sizes. Place a legend on the plot with patches and labels.
To avoid overlapping of labels and autopct in a matplotlib pie chart, we can follow label as a legend, using legend() method.
To change the position of a legend in Matplotlib, you can use the plt. legend() function. The default location is “best” – which is where Matplotlib automatically finds a location for the legend based on where it avoids covering any data points.
In my opinion, it's easier to plot things manually with matplotlib
than to use a pandas
dataframe plotting method, in this case. That way you have more control. You can add a legend to only the first axes after plotting all of your pie charts:
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(123456)
import pandas as pd
df = pd.DataFrame(3 * np.random.rand(4, 4), index=['a', 'b', 'c', 'd'],
columns=['x', 'y','z','w'])
plt.style.use('ggplot')
colors = plt.rcParams['axes.color_cycle']
fig, axes = plt.subplots(1,4, figsize=(10,5))
for ax, col in zip(axes, df.columns):
ax.pie(df[col], labels=df.index, autopct='%.2f', colors=colors)
ax.set(ylabel='', title=col, aspect='equal')
axes[0].legend(bbox_to_anchor=(0, 0.5))
fig.savefig('your_file.png') # Or whichever format you'd like
plt.show()
pandas
Plotting Methods InsteadHowever, if you'd prefer to use the plotting method:
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(123456)
import pandas as pd
df = pd.DataFrame(3 * np.random.rand(4, 4), index=['a', 'b', 'c', 'd'],
columns=['x', 'y','z','w'])
plt.style.use('ggplot')
colors = plt.rcParams['axes.color_cycle']
fig, axes = plt.subplots(1,4, figsize=(10,5))
for ax, col in zip(axes, df.columns):
df[col].plot(kind='pie', legend=False, ax=ax, autopct='%0.2f', title=col,
colors=colors)
ax.set(ylabel='', aspect='equal')
axes[0].legend(bbox_to_anchor=(0, 0.5))
fig.savefig('your_file.png')
plt.show()
Both produce identical results.
If you'd like to have a 2x2 or other grid arrangement of plots, plt.subplots
will return a 2D array of axes. Therefore, you'd need to iterate over axes.flat
instead of axes
directly.
For example:
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(123456)
import pandas as pd
df = pd.DataFrame(3 * np.random.rand(4, 4), index=['a', 'b', 'c', 'd'],
columns=['x', 'y','z','w'])
plt.style.use('ggplot')
colors = plt.rcParams['axes.color_cycle']
fig, axes = plt.subplots(nrows=2, ncols=2)
for ax, col in zip(axes.flat, df.columns):
ax.pie(df[col], labels=df.index, autopct='%.2f', colors=colors)
ax.set(ylabel='', title=col, aspect='equal')
axes[0, 0].legend(bbox_to_anchor=(0, 0.5))
fig.savefig('your_file.png') # Or whichever format you'd like
plt.show()
If you'd like a grid arrangement that has more axes than the amount of data you have, you'll need to hide any axes that you don't plot on. For example:
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(123456)
import pandas as pd
df = pd.DataFrame(3 * np.random.rand(4, 4), index=['a', 'b', 'c', 'd'],
columns=['x', 'y','z','w'])
plt.style.use('ggplot')
colors = plt.rcParams['axes.color_cycle']
fig, axes = plt.subplots(nrows=2, ncols=3)
for ax in axes.flat:
ax.axis('off')
for ax, col in zip(axes.flat, df.columns):
ax.pie(df[col], labels=df.index, autopct='%.2f', colors=colors)
ax.set(ylabel='', title=col, aspect='equal')
axes[0, 0].legend(bbox_to_anchor=(0, 0.5))
fig.savefig('your_file.png') # Or whichever format you'd like
plt.show()
If you don't want the labels around the outside, omit the labels
argument to pie
. However, when we do this, we'll need to build up the legend manually by passing in artists and labels for the artists. This is also a good time to demonstrate using fig.legend
to align the single legend relative to the figure. We'll place the legend in the center, in this case:
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(123456)
import pandas as pd
df = pd.DataFrame(3 * np.random.rand(4, 4), index=['a', 'b', 'c', 'd'],
columns=['x', 'y','z','w'])
plt.style.use('ggplot')
colors = plt.rcParams['axes.color_cycle']
fig, axes = plt.subplots(nrows=2, ncols=2)
for ax, col in zip(axes.flat, df.columns):
artists = ax.pie(df[col], autopct='%.2f', colors=colors)
ax.set(ylabel='', title=col, aspect='equal')
fig.legend(artists[0], df.index, loc='center')
plt.show()
Similarly, the radial position of the percentage labels is controlled by the pctdistance
kwarg. Values greater than 1 will move the percentage labels outside the pie. However, the default text alignment for the percentage labels (centered) assumes they're inside the pie. Once they're moved outside the pie, we'll need to use a different alignment convention.
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(123456)
import pandas as pd
def align_labels(labels):
for text in labels:
x, y = text.get_position()
h_align = 'left' if x > 0 else 'right'
v_align = 'bottom' if y > 0 else 'top'
text.set(ha=h_align, va=v_align)
df = pd.DataFrame(3 * np.random.rand(4, 4), index=['a', 'b', 'c', 'd'],
columns=['x', 'y','z','w'])
plt.style.use('ggplot')
colors = plt.rcParams['axes.color_cycle']
fig, axes = plt.subplots(nrows=2, ncols=2)
for ax, col in zip(axes.flat, df.columns):
artists = ax.pie(df[col], autopct='%.2f', pctdistance=1.05, colors=colors)
ax.set(ylabel='', title=col, aspect='equal')
align_labels(artists[-1])
fig.legend(artists[0], df.index, loc='center')
plt.show()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With