Organizing text on pie charts at matplotlib - python

I've learned the basics of plotting pie charts (through the tutorial and examples here), but I don't manage to put the suptitle above the chart (I need maybe to reduce the pie chart size, but how do I do it?). I also want to place the extra text box that I added in the bottom right or left side of the pie chart. If someone can give a hint it would be great!
(The function takes a string which is the name of the channel, then a list with 4 percentages, an int for the mass and a flag save_figures if I want to save the figure)
def plot_channel(channel,percentages, mass, save_figures):
# build a rectangle in axes coords
left, width = .25, .5
bottom, height = .25, .5
right = left + width
top = bottom + height
channel = ''.join(i for i in channel if i in 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
nu_energy , d_plus_p_energy, e_energy, gamma_energy = percentages
# The slices will be ordered and plotted counter-clockwise.
labels = [r'$E_{\nu} / E_{tot}$ = %.3f'%nu_energy,
r'$E_{d+p} / E_{tot}$ = %.3f'%d_plus_p_energy,
r'$E_{e} / E_{tot}$ = %.3f'%e_energy,
r'$E_{\gamma} / E_{tot}$ = %.3f'%gamma_energy]
sizes = [nu_energy , d_plus_p_energy, e_energy, gamma_energy]
colors = ['gold','red','green', 'lightskyblue']
explode = (0.1, 0,0,0)
patches, texts = plt.pie(sizes, colors=colors)#, startangle=90) ** not working for some reason
plt.legend(patches, labels, loc = "best")
E_gamma_e = e_energy + gamma_energy
plt.text(right, bottom,
r'$E_{\gamma + e} / E_{tot}$ = %.3f'%E_gamma_e,
horizontalalignment='left',
verticalalignment='bottom',
bbox=dict(facecolor='white', alpha=0.5), fontsize=30)
#plt.pie(sizes, explode=explode, labels=labels, colors=colors,
#autopct='%1.1f%%', shadow=True)
# Set aspect ratio to be equal so that pie is drawn as a circle.
plt.axis('equal')
plt.suptitle(r'DM DM $\rightarrow$ $%s$ + $%s$'%(channel,channel),position=(left,top),
bbox=dict(facecolor='0.8',), fontsize=30)
plt.tight_layout()
if save_figures:
plt.savefig("./figures/energy_distribution_for_channel_{}.png".format(channel))
else:
plt.show()
plt.close()

Try this:
import matplotlib.pyplot as plt
channel,percentages, mass = "ab",[0.2,0.2,0.1,0.5], 10
# build a rectangle in axes coords
left, width = .25, .5
bottom, height = .25, .5
right = left + width
top = bottom + height
channel = ''.join(i for i in channel if i in 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
nu_energy , d_plus_p_energy, e_energy, gamma_energy = percentages
# The slices will be ordered and plotted counter-clockwise.
labels = [r'$E_{\nu} / E_{tot}$ = %.3f' % nu_energy,
r'$E_{d+p} / E_{tot}$ = %.3f' % d_plus_p_energy,
r'$E_{e} / E_{tot}$ = %.3f' % e_energy,
r'$E_{\gamma} / E_{tot}$ = %.3f' %gamma_energy]
sizes = [nu_energy , d_plus_p_energy, e_energy, gamma_energy]
colors = ['gold','red','green', 'lightskyblue']
explode = (0.1, 0,0,0)
patches, texts = plt.pie(sizes, colors=colors)#, startangle=90) ** not working for some reason
plt.legend(patches, labels, loc = "best")
E_gamma_e = e_energy + gamma_energy
#plt.pie(sizes, explode=explode, labels=labels, colors=colors,
#autopct='%1.1f%%', shadow=True)
# Set aspect ratio to be equal so that pie is drawn as a circle.
plt.axis('equal')
plt.title(r'DM DM $\rightarrow$ $%s$ + $%s$'%(channel,channel),position=(0.5,1),bbox=dict(facecolor='0.8',), fontsize=30)
plt.text(-1,-0.98, r'$E_{\gamma + e} / E_{tot}$ = %.3f'%E_gamma_e, bbox=dict(facecolor='white', alpha=0.5), fontsize=14)
plt.tight_layout()
plt.show()

Related

Want to plot graph side by side

I wan to two plots side by side instead of this vertically, right now it's showing one by one
def scatter_plot(surrogate, building, actual, pred,index):
#calculating max and min x axis range
min_range=pred.min()-10
max_range=pred.max()+10
min_domain=actual.min()-10
max_domain=actual.max()+10
#scaling and creating scatter plot
plt.axes([0, 0, 2, 2])
plt.scatter(x=actual,y=pred, marker="o") #(y = predicted)
#plt.gca().set_aspect('equal', adjustable='box')
plt.grid()
plt.xlabel('Actual Values', fontsize = 20)
plt.ylabel('Predicted Values', fontsize = 20)
plt.title(f'{building.idf}_{building.epw}_{variable} Scatter Plot of NN vs E+', fontsize= 25)
#adding regression line
plt.plot([min_domain, max_domain], [min_range, max_range], color='g', linestyle='-', linewidth=1,label='regression')
#adding line passing minimum and maximum actual points
plt.plot([min_domain, max_domain],[min_domain, max_domain],color='r',linestyle='-',linewidth=1,label='actual point line')
#adding legend
plt.legend(loc='lower right')
#calculating error metrics
location = building.metadata['building_attributes']['Location']
building_type = building.idf
df = csv.loc[(csv['id'] == surrogate.surrogate_id) &
(csv['Location'] == location) & (csv['Building Type'] == building_type)]
rmse = df[f'{variable} RMSE'].values[0]
r2 = df[f'{variable} R2'].values[0]
#Adding Error metric annotations
textstr = '\n'.join((r'Total Error Metrics', r'$RMSE=%.2f$' % (rmse, ),r'$R2=%.2f$' % (r2, )))
props = dict(boxstyle='round', facecolor='ivory', alpha=0.5)
plt.text(max_range, max_domain, textstr, fontsize=20, verticalalignment='top', bbox=props)
#calculating x and y range
axes = plt.gca()
y_min, y_max = axes.get_ylim()
x_min, x_max = axes.get_xlim()
#Coordinates of interested area
percentile = 10
nth_percentile = np.percentile(actual,percentile)
bottom, left, width, height = 0, 0, nth_percentile,nth_percentile
try:
x_hist = x_min +(x_max - x_min)/9 #may have to change value 9
#calculating lines for selected area
x1, y1 = [left, x_hist], [bottom+height, (y_max + y_min)/2]
x2, y2 = [left + width, x_hist], [bottom + height, (y_max + y_min)/2]
L_act = []
L_pred = []
for x, y in zip(actual, pred):
if left <= x <= width+left:
if bottom<= y <= height + bottom:
L_act.append(x)
L_pred.append(y)
#adding rectangle for selected area
rect=mpatches.Rectangle((left, bottom),width, height, fill = False, color = "black",linewidth = 2)
plt.gca().add_patch(rect)
#calculating error metrics for selected area
rmse = RMSE(L_act, L_pred)
r2 = R2(L_act, L_pred)
#adding lines to indicated the selected area
plt.plot(x1, y1, x2, y2, color = 'black', linewidth = 2)
#adding histogram
plt.axes([0.2, 1, .6, .6], facecolor='w')
plt.hist(L_act, 30)
plt.xticks([])
plt.yticks([])
textstr = '\n'.join((r'Selected Section Error Metrics', r'$RMSE=%.2f$' % (rmse, ),r'$R2=%.2f$' % (r2, )))
props = dict(boxstyle='round', facecolor='ivory', alpha=0.8)
#adding error metrics annotations for selected area
axes = plt.gca()
y_min, y_max = axes.get_ylim()
x_min, x_max = axes.get_xlim()
plt.text(x_min + x_min/10, y_max - y_max/30, textstr, fontsize=10, verticalalignment='top', bbox=props)
except ValueError:
print("Selected section doesn't contain any data points")
plt.show()
I tried using a subplot but that didn't work
def s_plot(surrogate,building):
figure, axis = plt.subplots(1, 2)
actual, pred = np.array(surrogate.test_samples[variable].values[:]), np.array(surrogate.training_samples[variable].values[:])
actual_train, pred_train = np.array(surrogate.train_actual[variable].values[:]), np.array(surrogate.train_pred[variable].values[:])
data =[[actual,pred],[actual_train, pred_train]
for ax,i in zip(axes.flatten(),data):
scatter_plot(surrogate,building,i[0],i[1],ax)
Here I am using axes instead of plt but there are so many parameters that axes doesn't have such as gca, scaling using axes, etc. and I am not able to plot histogram by subplot use
Is there any way to plot this side by side
here is a simple example of using histogram with subplots:
def func(ax):
# example data
mu = 100 # mean of distribution
sigma = 15 # standard deviation of distribution
x = mu + sigma * np.random.randn(437)
num_bins = 50
# the histogram of the data
n, bins, patches = ax.hist(x, num_bins, density=True)
# add a 'best fit' line
y = ((1 / (np.sqrt(2 * np.pi) * sigma)) *
np.exp(-0.5 * (1 / sigma * (bins - mu))**2))
ax.plot(bins, y, '--')
ax.set_xlabel('Smarts')
ax.set_ylabel('Probability density')
ax.set_title(r'Histogram of IQ: $\mu=100$, $\sigma=15$')
fig, (ax1, ax2) = plt.subplots(1, 2)
func(ax1)
func(ax2)

How can I adapt the autolabel function in matplotlib so that it displays negative values correctly?

I have been playing around with Python for the last couple of days and found a lot of good resources about labelling, but I am failing to make it properly display negative values. Because the autolabel() function takes the height of the bar, which seems to always be a positive value, the labels are displayed way up in the graph and are of course not displayed as negative values. Can I somehow get the values that make up these bars or how do I get these labels down where they belong and show them as negative?
import pandas as pd
import matplotlib.pyplot as plt
from builtins import list
import matplotlib
matplotlib.style.use('ggplot')
import numpy as np
n_groups = 2
# create plot
fig, ax = plt.subplots()
fig.canvas.set_window_title('Mindestlohn Bundesweit')
index = np.arange(n_groups)
bar_width = 0.20
opacity = 0.8
list_reallohn_week_vollzeit = [-8.159698443426123, 11.395025597733763]
list_reallohn_week_teilzeit = [-1.048913873322391, 28.99318154295449]
list_reallohn_week_mini = [-7.552596893170488, 7.959096278017519]
rects1 = plt.bar(index + 0.00, list_reallohn_week_vollzeit, bar_width,
alpha=opacity,
color='b',
label='Vollzeit')
rects2 = plt.bar(index + bar_width, list_reallohn_week_teilzeit, bar_width,
alpha=opacity,
color='g',
label='Teilzeit')
rects3 = plt.bar(index + bar_width * 2,list_reallohn_week_mini, bar_width,
alpha = opacity,
color='c',
label='Mini Job')
label_week_lists = ('2014 vor MdL', '2015 Nicht MdL berechtigt', '2015 mit MdL')
plt.ylabel('EUR')
plt.title('Reallöhne pro Woche')
plt.xticks(index + bar_width, label_week_lists)
plt.legend(bbox_to_anchor=(1, 1),
bbox_transform=plt.gcf().transFigure)
def autolabel(rects, ax):
# Get y-axis height to calculate label position from.
(y_bottom, y_top) = ax.get_ylim()
y_height = y_top - y_bottom
for rect in rects:
height = rect.get_height()
# Fraction of axis height taken up by this rectangle
p_height = (height / y_height)
# If we can fit the label above the column, do that;
# otherwise, put it inside the column.
if p_height > 0.95: # arbitrary; 95% looked good to me.
label_position = height - (y_height * 0.05)
else:
label_position = height + (y_height * 0.01)
ax.text(rect.get_x() + rect.get_width() / 2., label_position,
'%d' % int(height),
ha='center', va='bottom')
autolabel(rects1, ax)
autolabel(rects2, ax)
autolabel(rects3, ax)
plt.show()
mathplotlib is not very well documented in that department. Try using the dir() function to reveal the available options you have on the container you're working on. i found there is a .get_y() function which retuns negative numbers in that case
try this code instead
import pandas as pd
import matplotlib.pyplot as plt
from builtins import list
import matplotlib
matplotlib.style.use('ggplot')
import numpy as np
n_groups = 2
# create plot
fig, ax = plt.subplots()
fig.canvas.set_window_title('Mindestlohn Bundesweit')
index = np.arange(n_groups)
bar_width = 0.20
opacity = 0.8
list_reallohn_week_vollzeit = [-8.159698443426123, 11.395025597733763]
list_reallohn_week_teilzeit = [-1.048913873322391, 28.99318154295449]
list_reallohn_week_mini = [-7.552596893170488, 7.959096278017519]
rects1 = plt.bar(index + 0.00, list_reallohn_week_vollzeit, bar_width,
alpha=opacity,
color='b',
label='Vollzeit')
rects2 = plt.bar(index + bar_width, list_reallohn_week_teilzeit, bar_width,
alpha=opacity,
color='g',
label='Teilzeit')
rects3 = plt.bar(index + bar_width * 2,list_reallohn_week_mini, bar_width,
alpha = opacity,
color='c',
label='Mini Job')
label_week_lists = ('2015 Nicht MdL berechtigt', '2015 mit MdL')
plt.ylabel('EUR')
plt.title('Reallöhne pro Woche')
plt.xticks(index + bar_width, label_week_lists)
plt.legend(bbox_to_anchor=(1, 1),
bbox_transform=plt.gcf().transFigure)
def autolabel(rects, ax):
# Get y-axis height to calculate label position from.
(y_bottom, y_top) = ax.get_ylim()
y_height = y_top - y_bottom
for rect in rects:
# print(dir(rect))
height = 0
if rect.get_y() < 0:
height = rect.get_y()
else:
height = rect.get_height()
print(rect.get_height())
print( str(rect.get_y()) )
# Fraction of axis height taken up by this rectangle
p_height = (height / y_height)
# If we can fit the label above the column, do that;
# otherwise, put it inside the column.
if p_height > 0.95: # arbitrary; 95% looked good to me.
label_position = height - (y_height * 0.05)
else:
label_position = height + (y_height * 0.01)
ax.text(rect.get_x() + rect.get_width() / 2., label_position,
'%d' % int(height),
ha='center', va='bottom')
autolabel(rects1, ax)
autolabel(rects2, ax)
autolabel(rects3, ax)
plt.show()
If you print rect.get_height() values you get something like:
-8.159698443426123
11.395025597733763
-1.048913873322391
28.99318154295449
-7.552596893170488
7.959096278017519
Therefore height of a bar maybe a negative.
To mark negative bars modify if statement in auto label function as follow:
if p_height > 0.95: # arbitrary; 95% looked good to me.
label_position = height - (y_height * 0.05) if (height > 0) else height + (y_height * 0.05)
else:
label_position = height + (y_height * 0.01) if (height > 0) else height - (y_height * 0.05)
You have to ajust coefficients in else branch (0.05) manually because position of a below label depends on a font size of a label. (Position of a label for positive bar does not affected by font size because a label is above the bar).
Finale for my font settings:

matplotlib getting labels to show decimal

So for the life of me i can't figure out how to get the labels to show decimal places and not just 0,1,2
i need them to be in decimal form below is my code in python 3
#ROE and Growth
Tax_Burden = stock.loc['Net Income']/stock.loc['Pre-Tax Income']
Interest_Burden= stock.loc['Pre-Tax Income']/stock.loc['Operating Income']
Operating_Margin= stock.loc['Operating Income']/stock.loc['Revenue']
Asset_Turnover= stock.loc['Revenue']/stock.loc['Total Assets Average']
Leverage_Ratio= stock.loc['Total Assets Average']/stock.loc['Total Equity Average']
roe=Tax_Burden*Interest_Burden*Operating_Margin*Asset_Turnover*Leverage_Ratio
Growth = roe * (1-stock.loc['Dividend Payout Ratio'])
astart = 21
aend = 31
annual = [Operating_Margin[astart:aend],Tax_Burden[astart:aend],Interest_Burden[astart:aend],Asset_Turnover[astart:aend],Leverage_Ratio[astart:aend],roe[astart:aend],Growth[astart:aend]]
N = len(annual[0])
ind = np.arange(N) # the x locations for the groups
width = .12 # the width of the bars
fig, ax = plt.subplots(figsize=(20,10))
rects1 = ax.bar(ind, annual[0], width, color='y')
rects2 = ax.bar(ind+width, annual[1], width, color='r')
rects3 = ax.bar(ind+width*2, annual[2], width, color='b')
rects4 = ax.bar(ind+width*3, annual[3], width, color='k')
rects5 = ax.bar(ind+width*4, annual[4], width, color='c')
rects6 = ax.bar(ind+width*5, annual[5], width, color='k')
rects7 = ax.bar(ind+width*6, annual[6], width, color='r')
# add some text for labels, title and axes ticks
ax.set_ylabel('Percentage')
ax.set_title('ROE Annual')
ax.set_xticks(ind + width / 2)
ax.set_xticklabels(list(stock.loc['Fiscal Period'][astart:aend]))
#ax.legend((rects1[0], rects2[0]), ('workinprogress'))
def autolabel(rects, ax):
# Get y-axis height to calculate label position from.
(y_bottom, y_top) = ax.get_ylim()
y_height = y_top - y_bottom
for rect in rects:
height = rect.get_height()
# Fraction of axis height taken up by this rectangle
p_height = (height / y_height)
# If we can fit the label above the column, do that;
# otherwise, put it inside the column.
if p_height > 0.95: # arbitrary; 95% looked good to me.
label_position = height - (y_height * 0.05)
else:
label_position = height + (y_height * 0.01)
ax.text(rect.get_x() + rect.get_width()/2, label_position,
'%d' % int(height),
ha='center', va='bottom')
autolabel(rects1,ax)
autolabel(rects2,ax)
autolabel(rects3,ax)
autolabel(rects4,ax)
autolabel(rects5,ax)
autolabel(rects6,ax)
autolabel(rects7,ax)
plt.show()
i am aware it is not pretty as of now and not lazy need to make sore more functions but can't seem to get past this issue. thanks for looking at.
EDIT: For those looking in the future the issue was the S operator here matplotlib documentation. Jay helped clarify below. i am attaching my code and new chart so can be copied for ease. still needs a little tweaking but that is personal preference.
astart = 21
aend = 31
annual = [Operating_Margin[astart:aend],Tax_Burden[astart:aend],Interest_Burden[astart:aend],Asset_Turnover[astart:aend],Leverage_Ratio[astart:aend],roe[astart:aend],Growth[astart:aend]]
N = len(annual[0])
ind = np.arange(N) # the x locations for the groups
width = .12 # the width of the bars
fig, ax = plt.subplots(figsize=(20,10),facecolor='#c8f2e5')
rects1 = ax.bar(ind, annual[0], width, color='#f29ca2')
rects2 = ax.bar(ind+width, annual[1], width, color='#61eaf2')
rects3 = ax.bar(ind+width*2, annual[2], width, color='#6da4d9')
rects4 = ax.bar(ind+width*3, annual[3], width, color='#f2bb12')
rects5 = ax.bar(ind+width*4, annual[4], width, color='c')
rects6 = ax.bar(ind+width*5, annual[5], width, color='#ce44f2')
rects7 = ax.bar(ind+width*6, annual[6], width, color='r')
ax.set_facecolor('#a7cff2')
# add some text for labels, title and axes ticks
ax.set_ylabel('Percentage',size=20)
ax.set_title('ROE Annual',size=30)
ax.set_xticks(ind + width / 2)
ax.set_xticklabels(list(stock.loc['Fiscal Period'][astart:aend]),size=14)
vals = ax.get_yticks()
ax.set_yticklabels(['{:3.2f}%'.format(x*100) for x in vals])
ax.legend((rects1[0], rects2[0], rects3[0], rects4[0], rects5[0], rects6[0], rects7[0]),('Operating Margin', 'Tax Burden','Interest Burden','Asset Turnover', 'Leverage Ratio','ROE','Growth'))
def autolabel(rects, ax):
# Get y-axis height to calculate label position from.
(y_bottom, y_top) = ax.get_ylim()
y_height = y_top - y_bottom
for rect in rects:
height = rect.get_height()
# Fraction of axis height taken up by this rectangle
p_height = (height / y_height)
# If we can fit the label above the column, do that;
# otherwise, put it inside the column.
if p_height > 0.95: # arbitrary; 95% looked good to me.
label_position = height - (y_height * 0.05)
else:
label_position = height + (y_height * 0.01)
ax.text(rect.get_x() + rect.get_width()/2, label_position,
'%.2f' % float(height),
ha='center', va='bottom',color='k',fontsize=12)
#
autolabel(rects1,ax)
autolabel(rects2,ax)
autolabel(rects3,ax)
autolabel(rects4,ax)
autolabel(rects5,ax)
autolabel(rects6,ax)
autolabel(rects7,ax)
plt.show()
I think problem is with below statement. Instead of int, use float
ax.text(rect.get_x() + rect.get_width()/2, label_position,
'%.2f' % float(height),
ha='center', va='bottom')
The solution by Jay did not work for me, but this did:
for p in ax.patches:
ax.annotate(str(p.get_height()), (p.get_x() * 1.005, p.get_height() * 1.002))

Bar graph doesn't fill the Axis

I'm trying to make a stacked bar chart of a list of a variable number of "Accumulators", which have a person's name and three percentages which always add up to 100. But when I have a large number of entries in the list, all the bars are crowded to the left side of the graph.
Here's the code:
per_unreviewed = np.array([p.accum_per_unreviewed for p in accumulators])
per_reviewed = np.array([p.accum_per_reviewed for p in accumulators])
per_signed_off = np.array([p.accum_per_signed_off for p in accumulators])
fig = Figure(facecolor="w", figsize=(15, 7))
ax = fig.add_subplot(111)
ind = np.arange(len(accumulators))
logger.debug("len(acc) = %d, ind = %s", len(accumulators), ind)
width = 0.45
p1 = ax.bar(ind, per_signed_off, width, color="g")
p2 = ax.bar(ind, per_reviewed, width, color="b", bottom=per_signed_off)
p3 = ax.bar(ind, per_unreviewed, width, color="r",
bottom=per_signed_off + per_reviewed)
ax.set_title(title)
ax.set_ylabel("Percent by status")
ax.set_yticks(np.arange(0, 101, 20))
ax.set_xticks(ind + width / 2.0)
ax.set_xticklabels(
[p.person for p in accumulators],
rotation='vertical', clip_on=False)
fig.tight_layout()
box = ax.get_position()
ax.set_position([box.x0, box.y0, box.width * 0.7, box.height])
if (len(p1) > 0 or len(p2) > 0 or len(p3) > 0):
ax.legend(
(p1[0], p2[0], p3[0]),
('Signed Off', 'Reviewed', 'Unreviewed'),
loc="upper left", bbox_to_anchor=(1.05, 1), borderaxespad=0
)
canvas = FigureCanvas(fig)
outstr = StringIO.StringIO()
canvas.print_png(outstr)
And the result
Have you tried playing with the x axis range? You have the ticks and a figure size, but nothing that tells the plot the range of x.
I don't use subplots myself, but is there something like ax.set_xlim([]) or ax.xlim() that does this?
Update from Paul Tomblin: I tried those suggestions and they didn't help, but they did point me to the right idea:
ax.set_xbound(lower=0, upper=len(accumulators))

Why is there extra space at the bottom of this plot?

I just created a horizontal stacked bar chart using matplotlib, and I can't figure out why there is extra space between the x axis and the first bar (code and picture below). Any suggestions or questions? Thanks!
Code:
fig = figure(facecolor="white")
ax1 = fig.add_subplot(111, axisbg="white")
heights = .43
data = np.array([source['loan1'],source['loan2'],source['loan3']])
dat2 = np.array(source2)
ind=np.arange(N)
left = np.vstack((np.zeros((data.shape[1],), dtype=data.dtype), np.cumsum(data, axis=0) [:-1]))
colors = ( '#27A545', '#7D3CBD', '#C72121')
for dat, col, lefts, pname2 in zip(data, colors, left, pname):
ax1.barh(ind+(heights/2), dat, color=col, left=lefts, height = heights, align='center', alpha = .5)
p4 = ax1.barh(ind-(heights/2), dat2, height=heights, color = "#C6C6C6", align='center', alpha = .7)
ax1.spines['right'].set_visible(False)
ax1.yaxis.set_ticks_position('left')
ax1.spines['top'].set_visible(False)
ax1.xaxis.set_ticks_position('bottom')
yticks([z for z in range(N)], namelist)
#mostly for the legend
params = {'legend.fontsize': 8}
rcParams.update(params)
box = ax1.get_position()
ax1.set_position([box.x0, box.y0 + box.height * 0.1, box.width, box.height * 0.9])
l = ax1.legend(loc = 'upper center', bbox_to_anchor=(0.5,-0.05), fancybox=True, shadow = True, ncol = 4)
show()
This is because matplotlib tries to intelligently choose minimum and maximum limits for the plot (i.e. "round-ish" numbers) by default.
This makes a lot of sense for some plots, but not for others.
To disable it, just do ax.axis('tight') to snap the data limits to the strict extents of the data.
If you want a bit of padding despite the "tight" bounds on the axes limits, use ax.margins.
In your case, you'd probably want something like:
# 5% padding on the y-axis and none on the x-axis
ax.margins(0, 0.05)
# Snap to data limits (with padding specified above)
ax.axis('tight')
Also, if you want to set the extents manually, you can just do
ax.axis([xmin, xmax, ymin, ymax])`
or use set_xlim, set_ylim, or even
ax.set(xlim=[xmin, xmax], ylim=[ymin, ymax], title='blah', xlabel='etc')

Categories