I'm trying to create a barchart that keeps always a fixed distance between outer and inner position, regardless of the labels length. I would like to see bar and bar_long in the same position as bar_long and bar_perfect do. I've tried to work with axes.set_position(), but in vain. Thanks in advance for appreciated help!
import matplotlib.pyplot as plt
def createBar(figx, figy, labels):
fig, ax = plt.subplots(figsize=(figx, figy)
performance = [10, 70, 120]
ax.barh(labels, performance)
return fig
bar = createBar(2, 1, ('Tom', 'Dick', 'Fred'))
bar_long = createBar(2, 1, ('Tom Cruise', 'Dick & Doof', 'Fred Astaire'))
bar_perfect = createBar(2, 1, (' Tom', 'Dick', 'Fred'))
I would not call it a proper solution, and I feel a bit ashamed to even post it, but if you really need something working in the meanwhile...
import matplotlib.pyplot as plt
def createBar(figx, figy, labels):
fig, (ax0, ax) = plt.subplots(1, 2, figsize=(figx, figy),
gridspec_kw={'width_ratios': [1, 2]})
performance = [10, 70, 120]
ax.barh(labels, performance)
ax0.set_axis_off()
return fig
bar = createBar(3, 1, ('Tom', 'Dick', 'Fred'))
bar_long = createBar(3, 1, ('Tom Cruise', 'Dick & Doof', 'Fred Astaire'))
bar_perfect = createBar(3, 1, (' Tom', 'Dick', 'Fred'))
plt.show()
To get all plots the same, you need the same margins for all of them. So, you'll need to set them all to some fixed value. plt.subplots_adjust(...) does this. The numbers are fractions from 0 to 1, where 0 is the left bottom of the figure, and 1 the top right.
For your 2x1 example, the following would work:
import matplotlib.pyplot as plt
def createBar(figx, figy, labels):
fig, ax = plt.subplots(figsize=(figx, figy))
performance = [10, 70, 120]
ax.barh(labels, performance)
plt.subplots_adjust(left=0.4, right=0.95, top=0.97, bottom=0.25)
return fig
bar = createBar(2, 1, ('Tom', 'Dick', 'Fred'))
bar_long = createBar(2, 1, ('Tom Cruise', 'Dick & Doof', 'Fred Astaire'))
bar_perfect = createBar(2, 1, (' Tom', 'Dick', 'Fred'))
plt.show()
Related
Assume that we are plotting bar plots in matplotlib.
When the values are in the same range we can see all bars.
However, when some values are too high we can not see the bars with very low values.
Is there a way to know which bars are shown (visible) or not after the call of ax.bar()
using its returned object of type class 'matplotlib.container.BarContainer'?
import numpy as np
import matplotlib.pyplot as plt
N = 5
# menMeans = (20, 35, 30, 35, 27) # All 5 bars are shown
menMeans = (20, 35000, 30, 35, 27) # Only 2nd bar is shown
menStd = (2, 3, 4, 1, 2)
ind = np.arange(N)
width = 0.35
fig = plt.figure()
ax = fig.add_subplot(111)
rects1 = ax.bar(ind, menMeans, width, color='royalblue', yerr=menStd)
ax.set_ylabel('Scores')
ax.set_title('Scores')
ax.set_xticks(ind)
ax.set_xticklabels( ('a1', 'a2', 'a3', 'a4', 'a5') )
plt.show()
These commands write that all bars are plotted.
However, they aren't shown in the final plot.
for i in rects1.patches:
print(i.get_height(),i.get_bbox(), i.get_visible())
I have the following plot:
The subplots are created as:
import matplotlib.pyplot as plt
fig, axs = plt.subplots(4, 3, figsize=(8,10), sharey='col')
And after code for populating the bars, I have the following code:
for ax in axs.flat:
ax.set_xticks([0, 1, 2, 3, 4, 5])
ax.set_xticklabels(['50', '10', '0', '50', '10', '0'])
ax.grid(True, axis='y', color='lightgray', which='both')
handles, labels = axs.flat[-1].get_legend_handles_labels()
fig.legend(handles, labels, loc='upper left', prop={'size': 9}, bbox_to_anchor=(0.088, 0.97))
plt.tight_layout()
plt.savefig('test.png')
My problem is that the number of yticklabels in the first column of subplots is different compared to the number of yticklabels in the other two columns. I would prefer to have the subplots in other two columns also have as much yticklabels as the subplots in the first column. How do I do this?
You need set_ylim, for example
import matplotlib.pyplot as plt
fig, axs = plt.subplots(4, 3, figsize=(8,10), sharey='col')
data = np.random.rand(12,5) * 12
for ind,ax in enumerate(axs.flat):
ax.set_xticks([0, 1, 2, 3, 4, 5])
ax.set_xticklabels(['50', '10', '0', '50', '10', '0'])
ax.set_yticks(list(range(0,14,2)))
ax.set_yticklabels(list(range(0,14,2)))
ax.set_ylim(0,14)
dat = data[ind]
if ind % 3 != 0: dat /= 5
ax.plot(data[ind])
ax.grid(True, axis='y', color='lightgray', which='both')
I am using subplot to display some figures, however the labels are mixed with the last subplot, so the plots don't have equal size. and the previous 5 are not perfectly round circle.
Here's my code:
for i in range(6):
plt.subplot(231 + i)
plt.title("Department " + depts[i])
labels = ['Male', 'Female']
colors = ['#3498DB', '#E74C3C']
sizes = [male_accept_rates[i] / (male_accept_rates[i] + female_accept_rates[i]),
female_accept_rates[i] / (male_accept_rates[i] + female_accept_rates[i])]
patches, texts = plt.pie(sizes, colors=colors, startangle=90)
plt.axis('equal')
plt.tight_layout()
plt.legend(labels, loc="best")
plt.show()
And here's the output:
can anyone give me some advise? Much appreciated.
It appears plt.axis('equal') only applies to the last subplot. So your fix is to put that line of code in the loop.
So:
import numpy as np
import matplotlib.pyplot as plt
depts = 'abcdefg'
male_accept_rates = np.array([ 2, 3, 2, 3, 4, 5], float)
female_accept_rates= np.array([ 3, 3, 4, 3, 2, 4], float)
for i in range(6):
plt.subplot(231 + i)
plt.title("Department " + depts[i])
labels = ['Male', 'Female']
colors = ['#3498DB', '#E74C3C']
sizes = [male_accept_rates[i] / (male_accept_rates[i] + female_accept_rates[i]),
female_accept_rates[i] / (male_accept_rates[i] + female_accept_rates[i])]
patches, texts = plt.pie(sizes, colors=colors, startangle=90)
plt.axis('equal')
plt.tight_layout()
plt.legend(labels, loc="best")
plt.show()
Produces this now:
I have a pyplot code.
Since I want to group multiple bars, I am trying to write text in the graph using plt.annotate.
However, as you can see in the picture, the word 'Something' in left bottom gets cropped. Does anyone know How I can fix this?
Here is my code
#!/usr/bin/python
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import operator as o
import numpy as np
n_groups = 5
means_men = (20, 35, 30, 35, 27)
std_men = (2, 3, 4, 1, 2)
means_women = (25, 32, 34, 20, 25)
std_women = (3, 5, 2, 3, 3)
fig, ax = plt.subplots()
index = np.arange(n_groups)
bar_width = 0.35
opacity = 0.4
error_config = {'ecolor': '0.3'}
rects1 = plt.bar(index, means_men, bar_width, alpha=opacity, color='b', yerr=std_men, error_kw=error_config, label='Men')
rects2 = plt.bar(index + bar_width, means_women, bar_width,
alpha=opacity,
color='r',
yerr=std_women,
error_kw=error_config,
label='Women')
#plt.xlabel('Group')
plt.ylabel('Scores')
plt.title('Scores by group and gender')
plt.annotate('Something', (0,0), (50,-40), xycoords = 'axes fraction', textcoords='offset points', va='top');
plt.annotate('Something', (0,0), (200,-20), xycoords = 'axes fraction', textcoords='offset points', va='top');
plt.xticks(index + bar_width, ('A', 'B', 'C', 'D', 'E'))
plt.legend()
plt.savefig('barchart_3.png')
For some reason, matplotlib sometimes clips too aggressively. If you add bbox_inches='tight' to save fig this should include the figure correctly,
plt.savefig('barchart_3.png', bbox_inches='tight')
More generally, you can adjust your main figure with something like,
plt.subplots_adjust(bottom=0.1)
I have a following code which produces a graph -
# imports specific to the plots in this example
import sys
import numpy as np
from matplotlib import cm
import matplotlib.pyplot as plt
resultsDirectory='results'
outputFile=resultsDirectory+".pdf"
axisLabelFontSize=16
borderWidth=0.0
# Twice as wide as it is tall.
fig = plt.figure(figsize=plt.figaspect(0.5))
ax = fig.add_subplot(111)
# Set up the Grid
[i.set_linewidth(borderWidth) for i in ax.spines.itervalues()]
unsatX=[680,2775,3821,680,4073,941,1202,1463]
unsatY=[1,1,1,4,1,2,2,2]
paretoX=[680, 1203, 1726, 4870]
paretoY=[10,7, 4,1]
satX=[4870,680,1727,1726,1203,680]
satY=[1,13,7,4,7,10]
typeX=[680, 1727]
typeY=[13, 7]
leftX=[680]
leftY=[12]
c = np.rec.fromarrays([paretoX, paretoY], names='x,y')
c.sort()
paretoX=c.x
paretoY=c.y
markrsz=8
l4, = plt.plot(paretoX, paretoY, '#000000', lw=2, label='Pareto Curve(unfolding, period locality)',markersize=markrsz,zorder = 10)
l1, = plt.plot(satX, satY, 'bo', label='Sat Points',markersize=markrsz,zorder = 10)
l2, = plt.plot(unsatX, unsatY, 'ro',marker='s',label='Unsat Points',markersize=markrsz,zorder = 10)
l5, = plt.plot(leftX, leftY, 'gp',label='Proc. count pareto points',markersize=markrsz)
l6, = plt.plot(typeX, typeY, 'w*',label='Modulo pareto points',markersize=markrsz,zorder=10)
leg=plt.legend(bbox_to_anchor=(0.,-0.200, 1., 1.102), loc=3, numpoints=1,
ncol=3, mode="expand", borderaxespad=0., fancybox=True, shadow=True,prop={'size':axisLabelFontSize})
rect = leg.get_frame()
rect.set_facecolor('#cccccc') # a grayscale intensity
#leg.set_frame_on(False)
latency=[680,2775,4870, 680,3821,4868, 680,1727,4341,4864, 680,1203,1726,1203, 680,4073,4334,4595,4856, 941,1202,1463,1724]
processor=[1, 1, 1,13, 1, 1, 7, 7, 1, 1, 4, 4, 4, 7,10,1, 1, 1, 1, 2, 2, 2, 2]
ax.set_xlabel('Period',size=axisLabelFontSize,labelpad=10)
ax.set_ylabel('Processors',size=axisLabelFontSize,labelpad=10)
ax.set_xlim(0, max(latency)+100)
ax.set_ylim(0, max(processor)+1)
# Set Border width zero
[i.set_linewidth(0) for i in ax.spines.itervalues()]
gridLineWidth=0.1
ax.set_axisbelow(False)
gridlines = ax.get_xgridlines()+ax.get_ygridlines()
#ax.set_axisbelow(True)
plt.setp(gridlines, 'zorder', 5)
ax.yaxis.grid(True, linewidth=gridLineWidth, linestyle='-', color='0.6',alpha='0.3')
ax.xaxis.grid(False)
ax.xaxis.set_ticks_position('none')
ax.yaxis.set_ticks_position('none')
fig.savefig(outputFile, format="pdf", bbox_inches='tight')
The legends in the plot get messed up.
Could someone tell me how do i fix a long legend entry which overwrites into area of other entry? What would be ideal if, I could do 3 legend entries in first row and two legend entries in the second row.
Besides the workaround found by the question author, a possibility is to add new lines for long labels:
...
l4, = plt.plot(paretoX, paretoY, '#000000', lw=2,
label='Pareto Curve \n(unfolding, period locality)',markersize=markrsz,zorder = 10)
...
The following modification to the code also solved my problem -
leg=plt.legend(bbox_to_anchor=(0.,-0.350, 1., 1.102), loc=3, numpoints=1, ncol=2 , borderaxespad=0., fancybox=True, shadow=True,prop={'size':axisLabelFontSize})