Issue with setting upper limit to y-xis on graph with matplotlib - python

The following code returns the nice graph provided here:
.
However, when I add a line code such as ax.set_ylim(ymax=14) I get the following graph:
.
Clearly there is something wrong. Could anyone help me figure out what?
Thanks!
fig, ax = plt.subplots(figsize=(15, 10))
# Set bins for histograms:
bins = np.arange(0, 40+0.5, 1)
# set interval on this bins for curve fitting:
xplot = np.linspace(min(bins), max(bins), 100)
# -- make a histogram
ax.grid(axis='y', zorder=0)
plt.axvline(x=af_farm_w_speedb.mean(), color='black', linestyle='dashed', linewidth=2, label = "Mean speed at control")
plt.axvline(x=af_farm_w_speedw.mean(), color='red', linestyle='dashed', linewidth=2, label = "Mean speed at treatment")
ax.hist([af_farm_w_speedb, af_farm_w_speedw], bins=bins, density=True, alpha = 1, align='left', zorder=1, rwidth=0.8, color=['lightsteelblue','grey'], label = ['Records at control', 'Records at treatment'])
ax.tick_params(axis='both', which='major', labelsize=30)
ax.set_yticklabels([0, 2, 4, 6, 8, 10, 12])
ax.set_title('Post-farm wind speed distribution', fontsize=35)
(scale, a, shape, c) = stats.exponweib.fit(af_farm_w_speedw, f0=1, floc=0)
ax.plot(xplot, stats.exponweib.pdf(xplot, *stats.exponweib.fit(af_farm_w_speedb, 1, 1, scale=1, loc=0)), zorder=3, color = "black", linewidth=1.6, label="Weibull fit at control")
ax.plot(xplot, stats.exponweib.pdf(xplot, *stats.exponweib.fit(af_farm_w_speedw, 1, 1, scale=1, loc=0)), zorder=3, color = "red", linewidth=1.6, label="Weibull fit at treatment")
fig.text(0.6, 0.55, "Mean speed at treatment: {:.4g}".format(af_farm_w_speedw.mean()), fontsize=18)
fig.text(0.6, 0.6, "Mean speed at control: {:.4g}".format(af_farm_w_speedb.mean()), fontsize=18)
ax.legend(prop=dict(size=18))

Related

How to change the font size of tick labels of a colorbar in Matplotlib?

I am creating a confusion matrix plot for my data. Next to the plot, I am placing a colorbar and want to change the font size of the colorbar tick labels. I search on the internet for a while but could not figure out how I can change the font size of the ticks of my colorbar since I am creating the colorbar using imshow. This could be because creating the colorbar this way is not the usual way as done/suggested in most places on the web (e.g. here and here). So I need your help for this. Here's how I'm creating my plot and add the colorbar next to it:
data=np.array([[0.83, 0.6, 0.76],[0.59, 0.46, 0.52],[0.62, 0.58, 0.88]])
xTicksMajor, yTicksMajor = [0.5, 1.5, 2.5], [0.5, 1.5, 2.5]
xTicksMinor, yTicksMinor = [0, 1, 2], [0, 1, 2]
fig, ax = plt.subplots()
cmapProp = {'drawedges': True, 'boundaries': np.linspace(0, 1, 13, endpoint=True).round(2)}
m = ax.imshow(data, cmap=plt.cm.get_cmap('Oranges'))
m.set_clim(0, 1)
ax.figure.colorbar(m, ax=ax, **cmapProp)
ax.set_xticks(xTicksMajor)
ax.set_yticks(yTicksMajor)
ax.set_xticks(xTicksMinor, minor=True)
ax.set_yticks(yTicksMinor, minor=True)
ax.yaxis.grid(True, color='black', linestyle='-', linewidth=0.5)
ax.xaxis.grid(True, color='black', linestyle='-', linewidth=0.5)
thresh = data.max() / 1.4
for i, j in itertools.product(range(data.shape[0]), range(data.shape[1])):
ax.text(j, i, format(data[i, j], '.2f'),
horizontalalignment="center",
verticalalignment='center',
color="black" if data[i, j] > thresh else "dimgrey",
fontsize=26)
fig.savefig('temp.png', dpi=200)
plt.close()
I tried changing the font size of the ticks as follow:
cmapProp = {'drawedges': True, 'boundaries': np.linspace(0, 1, 13, endpoint=True).round(2), 'fontsize': 14}
But this gives me the following error:
TypeError: init() got an unexpected keyword argument 'fontsize'
I wonder, how can I change the font size of the tick labels next to the colorbar? Feel free to make suggestions like creating the colorbar in a different way so that it is easy to change the fontsize.
Also, the above code results in the plot show below:
How about this:
...
fig, ax = plt.subplots()
cmapProp = {'drawedges': True, 'boundaries': np.linspace(0, 1, 13, endpoint=True).round(2)}
m = ax.imshow(data, cmap=plt.cm.get_cmap('Oranges'))
m.set_clim(0, 1)
# And here try this:
cbar = ax.figure.colorbar(m, ax=ax, **cmapProp)
cbar.ax.tick_params(labelsize=25) # set your label size here
...
Out:
bold labels:
...
cbar = ax.figure.colorbar(m, ax=ax, **cmapProp)
cbar.ax.tick_params(labelsize=25)
for tick in cbar.ax.yaxis.get_major_ticks():
tick.label2.set_fontweight('bold')
...
Out:

Removing axes and lining up a subplot

I have produced a graph with two subplots and am trying to add a histogram to the end of the residuals plot but am unable to remove the x-axis of the histogram plot and get it to line up with the end of the residual plot.
Here is a copy of my current code:
#graph with histogram and std error plot thing
fig1 = plt.figure(figsize =(9.6,7.2))
ax = fig1.add_axes((0.2,0.4,.75,.6))
ax.errorbar(xval, yval*1000, yerr=yerr*1000, xerr=xerr, marker='x', linestyle='None')
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.yaxis.set_ticks_position('left')
ax.xaxis.set_ticks_position('bottom')
# Axis labels
plt.xlabel('Height (m)', fontsize = 12)
plt.ylabel('dM/dt (g $s^{-1}$) × $10^{3}$', fontsize = 12)
# Generate best fit line using model function and best fit parameters, and add to plot
fit_line=model_funct(xval, [a_soln, b_soln])
plt.plot(xval, fit_line*1000)
# Set suitable axis limits: you will probably need to change these...
#pyplot.xlim(-1, 61)
#pyplot.ylim(65, 105)
# pyplot.show()
ax2 = fig1.add_axes((0.2,0.2,.75,.2)) #start frame1 at 0.2, 0.4
plt.xlabel("Height of Water (m)", fontsize = 12)
plt.ylabel("Normalised\nResiduals", fontsize = 12) #\n is used to start a new line
ax2.plot(h,normalised_residuals,"x", color = "green")
plt.axhline(0, linewidth=1, linestyle="--", color="black")
plt.savefig("Final Graph with added parts.png", dpi = 500)
ax2.axhspan(ymin = -np.std(normalised_residuals), ymax = np.std(normalised_residuals), color = 'gray', alpha =0.5)
ax3 = fig1.add_axes((1,0.2,0.2,0.2))
ax3.hist(normalised_residuals, bins=8, orientation="horizontal")
ax3.spines['right'].set_visible(False)
ax3.spines['top'].set_visible(False)
ax3.spines['left'].set_visible(False)
ax3.yaxis.set_ticks_position('left')
ax3.xaxis.set_ticks_position('bottom')
and here is a picture of my graph currently:
An example with random data. Using tick_params and manually setting both ylim and the histogram range, did the trick.
import matplotlib.pyplot as plt
import numpy as np
fig1 = plt.figure(figsize=(20, 15))
ax = fig1.add_axes((0.2, 0.4, .75, .6))
ax2 = fig1.add_axes((0.2, 0.2, .75, .2))
ax3 = fig1.add_axes((.95, 0.2, 0.2, 0.2))
xval = (np.linspace(0.02, 0.15, 20)
+ (np.random.default_rng(0).random(20) - 0.5) / 30)
yval = 2 * xval + 0.08
xerr = (np.random.default_rng(0).random(20) * 2 - 1) / 60
yerr = (np.random.default_rng(1).random(20) * 2 - 1) / 60
ax.errorbar(xval, yval, yerr=yerr, xerr=xerr, marker='x', linestyle='None')
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.tick_params(labelbottom=False)
ax.set_xlabel('Height (m)', fontsize=12)
ax.set_ylabel('dM/dt (g $s^{-1}$) × $10^{3}$', fontsize=12)
ax2.plot(xval, xerr, 'x', color='green')
ax2.axhline(0, linewidth=1, linestyle='--', color='black')
ax2.axhspan(ymin=-np.std(xerr), ymax=np.std(xerr), color='gray', alpha=0.5)
ax2.set_xlabel('Height of Water (m)', fontsize=12)
ax2.set_ylabel('Normalised\nResiduals', fontsize=12)
resLim = ax2.get_ylim()
ax3.hist(xerr, bins=8, orientation='horizontal', range=resLim, rwidth=0.9)
ax3.spines['right'].set_visible(False)
ax3.spines['top'].set_visible(False)
ax3.spines['left'].set_visible(False)
ax3.spines['bottom'].set_visible(False)
ax3.tick_params(labelbottom=False, labelleft=False, bottom=False, left=False)
ax3.set_ylim(resLim)
fig1.savefig('so.png', bbox_inches='tight')

Simple line with annotations

Is there any simpler way to have this line (with two annotations) using matplotlib?
The idea is just draw a line showing a interval ([0,T]) and some points with annotations. This code is too big for such a small thing.
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
plt.ylim(-.3,.3)
plt.xlim(0, 1)
xmin, xmax = ax.get_xlim()
# removing the default axis on all sides:
for side in ['bottom','right','top','left']:
ax.spines[side].set_visible(False)
# removing the axis ticks
plt.xticks([])
plt.yticks([])
ax.xaxis.set_ticks_position('none')
ax.yaxis.set_ticks_position('none')
# draw x and y axis
ax.arrow(xmin, 0, xmax-xmin, 0, fc='k', ec='k',
length_includes_head= True, clip_on = False)
esp=0.05
ax.text(0.5, esp, r'$\Delta t$', ha='center')
ax.text(0.45, 0, r'$|$', ha='center')
ax.text(0.45, -esp, r'$t_i$', ha='center')
ax.text(0.55, 0, r'$|$', ha='center')
ax.text(0.55, -esp, r'$t_{i+1}$', ha='center')
ax.text(0, 0, r'$|$', ha='center')
ax.text(0, -esp, r'$0$', ha='center')
ax.text(1, 0, r'$|$', ha='center')
ax.text(1, -esp, r'$T$', ha='center')
plt.show()
One could use the xaxis as the line to draw the intervals. That would allow to use its ticks and ticklabels for the annotations.
import matplotlib.pyplot as plt
fig,ax = plt.subplots()
plt.subplots_adjust(bottom=0.5, top=0.7)
for side in ['right','top','left']:
ax.spines[side].set_visible(False)
ax.set_yticks([])
ticks=[0,.45,.55,1]
ticklabels=[0,r'$t_i$', r'$t_{i+1}$',r'$T$']
ax.set_xticks(ticks)
ax.set_xticklabels(ticklabels)
ax.tick_params(direction='inout', length=10,pad=7)
ax.text(0.5, 0.2, r'$\Delta t$', ha='center')
plt.show()
I found similar solution using the x-axis but it is a little more compact
plt.ylim(0,.3)
plt.xticks([0, 0.45, 0.55, 1],
('$0$', '$t_i$', '$t_{i+1}$', '$T$'),
size=20,
verticalalignment='top')
plt.tick_params(axis='x',
direction='inout',
length=20,
pad=15,
bottom=True,
top=False)
Another approach is drawing the ticks as scatterplot and annotating each, i.e.
for x, label in [(0, '$0$'), (0.45, '$t_i$'), (0.55, '$t_{i+1}$'), (1, '$T$')]:
plt.scatter(x, 0, s=50, marker='|')
plt.annotate(label, [x,-0.05], size=20)

How to show yticks on the plot/graph (not on y-axis). Show yticks near points

I have a plot with a simple line. For the moment, I set yticks as invisible.
Here is the code for the graph:
import matplotlib.pyplot as plt
x = [1, 2, 3, 4, 5]
y = [1, 1.5, 2, 2.5, 3]
fig, ax = plt.subplots(figsize=(15,10))
plt.plot(x, y, 'ko-')
plt.xlabel('X', fontsize=15)
plt.ylabel('Y', fontsize=15)
plt.xticks(x, fontsize=13)
plt.yticks(y, visible=False)
plt.margins(0.1, 0.1)
plt.title('Graph', color='black', fontsize=17)
ax.axis('scaled')
ax.grid()
plt.show()
I need to show/print yticks right on the graph itself (not on the left side). So, yticks are alongside with datapoints.
Desired output:
How to do it with Matplotlib?
You can use plt.text() to annotate text onto an axis. By iterating over your x,y points you can place a label at each marker. For example:
import matplotlib.pyplot as plt
x = [1, 2, 3, 4, 5]
y = [1, 1.5, 2, 2.5, 3]
fig, ax = plt.subplots(figsize=(15,10))
plt.plot(x, y, 'ko-')
plt.xlabel('X', fontsize=15)
plt.ylabel('Y', fontsize=15)
plt.xticks(x, fontsize=13)
plt.yticks(y, visible=False)
offset = 0.05
for xp, yp in zip(x,y):
label = "%s" % yp
plt.text(xp-offset, yp+offset, label, fontsize=12, horizontalalignment='right')
plt.margins(0.1, 0.1)
plt.title('Graph', color='black', fontsize=17)
ax.axis('scaled')
ax.grid()
plt.show()
Gives the following figure:

Python: "Squeeze" a particular plot in subplot

Below, I plot the following Figure in Python:
As you can see the plot on the right is much more "smooth" than the one on the left. That's because the scaling of x-axis on both plot is different. More observations on the left than on the right (about three times more). Hence how can I "squeeze" horizontally the right plot such that I get somewhat an approximative look to the one of the left? Below is my code (I use Pandas):
fig, axes = plt.subplots(1, 2, sharey=True, figsize=(30, 15))
# plot the same data on both axes
#gs = gridspec.GridSpec(1, 2, width_ratios=[3, 1])
ax1 = df1.plot(ax=axes[0], grid='off', legend=False,
xticks=[-250, -200, -150, -100, -50,
0, 25], lw=2, colormap='jet',
fontsize=20)
ax2 = df2.plot(ax=axes[1], grid='off', legend=False,
xticks=[-5, 0, 20, 40, 60, 80], lw=2,
colormap='jet', fontsize=20)
# zoom-in / limit the view to different portions of the data
# hide the spines between ax and ax2
ax1.set_ylabel('Treatment-Control Ratio', fontsize=20)
ax1.axhline(y=1, color='r', linewidth=1.5)
ax2.axhline(y=1, color='r', linewidth=1.5)
ax1.axvline(x=0, color='r', linewidth=1.5, linestyle='--')
ax2.axvline(x=0, color='r', linewidth=1.5, linestyle='--')
ax1.set_xlabel('Event Time - 1 Minute', fontsize=20)
ax2.set_xlabel('Event Time - 1 Minute', fontsize=20)
ax1.spines['right'].set_visible(False)
ax2.spines['left'].set_visible(False)
ax1.yaxis.tick_left()
ax2.yaxis.set_major_locator(plt.NullLocator())
ax1.tick_params(labeltop='off') # don't put tick labels at the top
plt.subplots_adjust(wspace=0.11)
plt.tight_layout()
With the help of #cphlewis and #gboffi I fixed the issue with the code below:
fig, axes = plt.subplots(figsize=(30, 15))
# plot the same data on both axes
gs = gridspec.GridSpec(1, 2, width_ratios=[3, 1.2])
ax1 = plt.subplot(gs[0])
ax2 = plt.subplot(gs[1], sharey=ax1)
df_wpc.loc[-260:25].plot(ax=ax1, grid='off', legend=False,
xticks=[-250, -200, -150, -100, -50,
0, 25], lw=2, colormap='jet',
fontsize=20)
df_pc_et.loc[-5:91].plot(ax=ax2, grid='off', legend=False,
xticks=[-5, 0, 20, 40, 60, 80], lw=2,
colormap='jet', fontsize=20)
ax1.set_ylabel('Treatment-Control Ratio', fontsize=20)
ax1.axhline(y=1, color='r', linewidth=1.8)
ax2.axhline(y=1, color='r', linewidth=1.8)
ax1.axvline(x=0, color='r', linewidth=1.8, linestyle='--')
ax2.axvline(x=0, color='r', linewidth=1.8, linestyle='--')
ax1.set_xlabel('Event Time - 1 Minute', fontsize=20)
ax2.set_xlabel('Event Time - 1 Minute', fontsize=20)
ax1.spines['right'].set_visible(False)
ax2.spines['left'].set_visible(False)
ax1.yaxis.tick_left()
ax2.yaxis.set_major_locator(plt.NullLocator())
ax1.tick_params(labeltop='off') # don't put tick labels at the top
plt.subplots_adjust(wspace=0.7)
plt.tight_layout()

Categories

Resources