Assign figure to correct subplot - python

I have a set of subplot's that display different information. For the example below, I can assign the scatter plot to the designated subplot but the two distplot occupy the last subplot created.
import matplotlib.pyplot as plt
import seaborn as sns
x = [1,4,5,6,7,8]
x2 = [3,4,8,2,8,8]
y = [1,2,4,8,1,9]
def L_plot(ax, fontsize=12):
ax.set_xlabel('x-label', fontsize=8)
ax.set_ylabel('y-label', fontsize=8)
ax.set_title('L', fontsize=10)
ax.grid(False)
ax.scatter(x, y)
def E_plot(ax2,pid, fontsize=12):
ax2.set_xlabel('x-label', fontsize=8)
ax2.set_ylabel('y-label', fontsize=8)
ax2.set_title('E', fontsize=10)
ax2.grid(False)
ax2 = sns.distplot(x, kde=False, norm_hist=True, color='b', bins = 10)
def D_plot(ax,pid, fontsize=12):
ax.set_xlabel('x-label', fontsize=8)
ax.set_ylabel('y-label', fontsize=8)
ax.set_title('D', fontsize=10)
ax.grid(False)
ax = sns.distplot(x2, kde=False, norm_hist=True, color='b', bins = 10)
ax1 = plt.subplot2grid((3,1), (0, 0))
ax2 = plt.subplot2grid((3,1), (1, 0))
ax3 = plt.subplot2grid((3,1), (2, 0))
L_plot(ax1,1)
E_plot(ax2,1)
D_plot(ax3,1)
plt.tight_layout()
plt.show()
I'm trying to assign E_plot to the subplot in the second row but both distplot's are located in the last subplot created.
I'm not sure if the seaboard packages can't be assigned or I'm not correctly assigning it?

The call signature for distplot is:
seaborn.distplot(a, bins=None, hist=True, kde=True, rug=False,
fit=None, hist_kws=None, kde_kws=None, rug_kws=None,
fit_kws=None, color=None, vertical=False,
norm_hist=False, axlabel=None, label=None,
ax=None)
Notice the last option. If you don't tell it which Axes object to use, it'll use the one returned by pyplot.gca() (gca = "get current Axes").
So you need to do, e.g.,
sns.distplot(x2, kde=False, norm_hist=True, color='b', bins=10, ax=ax2)

Related

How to create a single legend for subplots [duplicate]

This question already has answers here:
How do I make a single legend for many subplots?
(10 answers)
Closed 6 months ago.
I am trying to replicate the following plot but with a different set of data:
My current plot has everything you see except the legend in the top right corner. I am having a hard time figuring out how I am supposed to add this in with my current code:
fig = plt.figure()
plt.subplot(3, 1, 1)
plt.title('Task Switches and Avg Task Switches by Timestep', fontsize=10)
plt.ylabel('Task Switches', fontsize=9)
plt.xlim(-35, timestep_num + 35)
plt.xticks(np.arange(0, timestep_num+1, 50), fontsize=-1, color='white')
plt.yticks(np.arange(0, 61, 20), fontsize=6)
plt.plot([stepsum_list[i][6] for i in range(len(stepsum_list))], color='royalblue',
linewidth=0.7, linestyle='', marker='.', markersize=1)
plt.plot([stepsum_list[i][6]/(i+1) for i in range(len(stepsum_list))], color='limegreen',
linewidth=0.6,)
plt.subplot(3, 1, 2)
plt.title('Task Demand per Timestep by Task', fontsize=10)
plt.ylabel('Task Demand', fontsize=9)
plt.xlim(-35, timestep_num + 35)
plt.xticks(np.arange(0, timestep_num+1, 50), fontsize=-1, color='white')
plt.yticks(np.arange(0, 6, 1), fontsize=6)
plt.plot([stepdem_list[i][1] for i in range(len(stepdem_list))], color='darkorange',
linewidth=0.7, linestyle='', marker='.', markersize=1)
plt.plot([stepdem_list[i][2] for i in range(len(stepdem_list))], color='yellowgreen',
linewidth=0.7, linestyle='', marker='.', markersize=1)
plt.plot([stepdem_list[i][3] for i in range(len(stepdem_list))], color='purple',
linewidth=0.7, linestyle='', marker='.', markersize=1)
plt.plot([stepdem_list[i][4] for i in range(len(stepdem_list))], color='blue', linewidth=0.7,
linestyle='', marker='.', markersize=1)
plt.subplot(3, 1, 3)
plt.title('Target and Tracker Movement',fontsize=10)
plt.ylabel('Movement', fontsize=9)
plt.xlabel('Timesteps', fontsize=9)
plt.xlim(-35, timestep_num + 35)
plt.xticks(np.arange(0, timestep_num+1, 50), fontsize=8)
plt.yticks(np.arange(-10, 11, 10), fontsize=6)
plt.plot([stepsum_list[i][4] for i in range(len(stepsum_list))], color='blue', linewidth=.5)
plt.plot([stepsum_list[i][2] for i in range(len(stepsum_list))], color='red', linewidth=.5)
fig.align_labels()
plt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=0.4, hspace=0.4)
plt.savefig('prog02_output.png')
plt.show
I apologize for all of the repetitive code, I'm brand new to Python and this is my first time making a plot so I don't know all of the tricks just yet. I have found the function figlegend(), but I'm confused if this is what I am going to want to use, and if so how the parameters are working. Placing the legend in the correct spot (aligned with the top subplot) is also something I am trying to do, but can't seem to figure out.
I'm not asking anyone to write any code or rewrite what I have. Just for someone to point me in the right direction, whether that be explaining a function and what parameters it can take, or what might need to be changed in my current code to use figlegend().
The way I plot legends with my plots in Matplotlib is via the Axes.legend() function, shown below:
The source code is
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([0,1,2],[2,1,0], c='r', label='Plot 1')
ax.plot([0,1,2],[0,1,2], c='b', label='Plot 2')
ax.legend()
plt.show()
After you add labels to each of the data traces in your plot via the label keyword argument, then you can add a legend to the figure with
plt.gca().legend()
If your try to put more 3 variables, you can do this:
lns1 = plt.plot(x,y)
lns2 = plt.plot(x2,y)
lns3 = plt.plot(x3,y)
lns = lns1+lns2+lns3+lns4
labs = [l.get_label() for l in lns]
plt.figure()
When you go to plot, use this:
ax.legend(lns,labs,loc='lower center')

matplotlib subplots empty when attempting to change font size of axes ticks

I had a script for plotting a single plot and adapted it for 2 subplots. When attempting to change the font size of the axes ticks via tick_params, all I get is a single empty plot. I've isolated this issue to the calling of this function. The following MWE runs fine with the tick_params calls commented out, but produces an incorrect figure if they're used. How can I modify this code to work with the subplots?
x = np.linspace(0.0, 1.0, 100)
y = x
fig = plt.figure()
plt.subplot(1,2,1)
plt.plot(x, y)
plt.xlabel('x', fontsize=16)
plt.ylabel('y', fontsize=16)
mystr = 'Some plot 1'
plt.title(mystr, fontsize=16)
# plt.axes().tick_params(axis='both', which='major', labelsize=16)
# plt.axes().tick_params(axis='both', which='minor', labelsize=16)
plt.grid()
plt.subplot(1,2,2)
plt.plot(x, y)
plt.xlabel('x', fontsize=16)
plt.ylabel('y', fontsize=16)
mystr = 'Some plot 2'
plt.title(mystr, fontsize=16)
# plt.axes().tick_params(axis='both', which='major', labelsize=16)
# plt.axes().tick_params(axis='both', which='minor', labelsize=16)
plt.grid()
plt.show()
Instead of accessing the subplot by plt.subplot(), access the axes._subplots.AxesSubplot individually.
I would try something like this:
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0.0, 1.0, 100)
y = x
fig, ax = plt.subplots(1, 2)
ax[0].plot(x, y)
ax[0].set_title('Some plot 1', fontsize=16)
ax[0].set_xlabel('x', fontsize=16)
ax[0].set_ylabel('y', fontsize=16)
ax[0].tick_params(axis="x", labelsize=16)
ax[0].tick_params(axis="y", labelsize=16)
ax[0].grid()
ax[1].plot(x, y)
ax[1].set_title('Some plot 2', fontsize=16)
ax[1].set_xlabel('x', fontsize=16)
ax[1].set_ylabel('y', fontsize=16)
ax[1].tick_params(axis="x", labelsize=16)
ax[1].tick_params(axis="y", labelsize=16)
ax[1].grid()
A very similar question was actually asked on the official matplotlib GitHub repository. So if you like to have a more detailed look on why subplots work this way, you might want to read this issue.
Also, I would like to add: in your example, the figures slightly overlap. This could be solved by calling fig.tight_layout() after you defined your subplots.

X-axis minor gridlines still not showing even after trying all solutions

My x-axis minor gridlines are not showing, this is my code
ax = plt.gca()
ax.minorticks_on()
plt.semilogx(data_x1,data_y1,"red")
plt.semilogx(data_x2,data_y2,"blue")
ax.grid(b=True, which='major',axis="both", color='k', linestyle='-', linewidth=0.5)
ax.grid(b=True, which='minor',axis="both", color='k', linestyle='-', linewidth=0.2)
plt.xlabel("frequency(Hz)")
plt.ylabel("Iramp(dB)")
plt.show()
enter image description here
Either I'm not sure of what you want, or your code is actually working correctly. The minor grid lines are those between the powers of 10. I made a little example to show a comparison of your plot with the minor grid lines on and off.
import numpy as np
import matplotlib.pyplot as plt
data_x1 = np.linspace(0,2,10)
data_x2 = np.linspace(0,4,10)
data_y1 = np.random.rand(10)
data_y2 = np.random.rand(10)
fig, axall =plt.subplots(1,2, figsize=(10,5))
# your code with some changes
ax = axall[0]
ax.minorticks_on()
ax.semilogx(data_x1,data_y1,"red")
ax.semilogx(data_x2,data_y2,"blue")
ax.grid(b=True, which='major',axis="both", color='k', linestyle='-', linewidth=0.5)
ax.grid(b=True, which='minor',axis="both", color='k', linestyle='-', linewidth=0.2)
ax.set_xlabel("frequency(Hz)")
ax.set_ylabel("Iramp(dB)")
# code to make the plot on the right.
ax = axall[1]
ax.minorticks_on()
ax.semilogx(data_x1,data_y1,"red")
ax.semilogx(data_x2,data_y2,"blue")
ax.grid(b=True, which='major',axis="both", color='k', linestyle='-', linewidth=0.5)
# ax.grid(b=True, which='minor',axis="both", color='k', linestyle='-', linewidth=0.2)
ax.set_xlabel("frequency(Hz)")
ax.set_ylabel("Iramp(dB)")
plt.show()
Note how I commented out your minor grid lines.

Subplot problem: how to plot for each plot a histogram by categorical values?

I have a DataFrame with three numerical variables Porosity, Perm and AI. I would like to make a subplot and in each plot, I would like the histogram of the three variables, by a categorical variable 'Facies'. Facies can take only two values: Sand and Shale.
In summary, each subplot needs a histogram and each histogram must be drawn based in the categorical variable Facies, to make a comparison between facies.
So far, I can make it work, but I cannot add the axis title to each subplot.
plt.subplot(311)
plt.hist(df_sd['Porosity'].values, label='Sand', bins=30, alpha=0.6)
plt.hist(df_sh['Porosity'].values, label='Shale', bins=30, alpha=0.6)
ax.set(xlabel='Porosity (fraction)', ylabel='Density', title='Porosity
Histogram')
plt.legend()
plt.subplot(312)
plt.hist(df_sd['log10Perm'].values, label='Sand', bins=30, alpha=0.6,)
plt.hist(df_sh['log10Perm'].values, label='Shale', bins=30, alpha=0.6)
ax.set(xlabel='Permeability (mD)', ylabel='Density', title='Permeability
Histogram')
plt.legend()
plt.subplot(313)
plt.hist(df_sd['AI'].values, label='Sand', bins=30, alpha=0.6)
plt.hist(df_sh['AI'].values, label='Shale', bins=30, alpha=0.6)
ax.set(xlabel='AI (units)', ylabel='Density', title='Acoustic Impedance
Histogram')
plt.legend()
plt.subplots_adjust(left=0.0, bottom=0.0, right=1.5, top=3.5, wspace=0.1,
hspace=0.2);
#I have tried with:
fig, axs = plt.subplots(2, 1)
but when I code
axs[0].hist(df_sd['Porosity'].values, label='Sand', bins=30, alpha=0.6)
axs[0].hist(df_sd['Porosity'].values, label='Shale', bins=30, alpha=0.6)
#But the histogram for shale overrides the histogram for Sand.
I would like to have this result but with both x and y axis with label names. Furthermore, it would be helpful to have a title for each subplot.
I just did a subplot with contours, but I think the framework will be very similar:
fig, axs = plt.subplots(2, 2, constrained_layout=True)
for ax, extend in zip(axs.ravel(), extends):
cs = ax.contourf(X, Y, Z, levels, cmap=cmap, extend=extend, origin=origin)
fig.colorbar(cs, ax=ax, shrink=0.9)
ax.set_title("extend = %s" % extend)
ax.locator_params(nbins=4)
plt.show()
I think the main point to note (and this I learned from the link below) is their use of zip(axs.ravel()) in the for loop to establish each ax and then plot what you wish on that ax. I'm fairly certain you can adapt this for your uses.
The full example is available at: https://matplotlib.org/gallery/images_contours_and_fields/contourf_demo.html#sphx-glr-gallery-images-contours-and-fields-contourf-demo-py
I have found an answer:
fig = plt.figure()
ax = fig.add_subplot(111)
ax1 = fig.add_subplot(311)
ax2 = fig.add_subplot(312)
ax2 = fig.add_subplot(313)
plt.subplot(311)
ax1.hist(df_sd['Porosity'].values, label='Sand', bins=30, alpha=0.6)
ax1.hist(df_sh['Porosity'].values, label='Shale', bins=30, alpha=0.6)
ax1.set(xlabel='Porosity (fraction)', ylabel='Density', title='Porosity Histogram')
ax1.legend()

Matplotlib: how to set a tick label above a plot

This is the sine and cosine plot I draw using matplotlib. But the tick labels are below the plot and can hardly seen.
My python code is:
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(8,6), dpi=96)
plt.subplot(111)
X = np.linspace(-np.pi, np.pi, 256, endpoint=True)
C,S = np.cos(X), np.sin(X)
plt.plot(X, C, color="blue", linewidth=2.5, linestyle="-", label="consine")
plt.plot(X, S, color="red", linewidth=2.5, linestyle="-", label="sine")
plt.xlim(X.min()*1.1, X.max()*1.1)
plt.ylim(C.min()*1.1, C.max()*1.1)
plt.xticks([-np.pi, -np.pi/2, 0, np.pi/2, np.pi],
[r'$-\pi$', r'$-\frac{\pi}{2}$', r'$0$', r'$+\frac{\pi}{2}$', r'$+\pi$'])
plt.yticks([-1, 1],
[r'$-1$', r'$+1$'])
ax = plt.gca()
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('data',0))
ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data',0))
plt.legend(loc='upper left', frameon=False)
for label in ax.get_xticklabels()+ax.get_yticklabels():
label.set_fontsize(16)
label.set_bbox(dict(facecolor='green', edgecolor='None', alpha=0.2))
plt.savefig("figures/exercise10.png", dpi=120)
plt.show()
So, how should I set a tick label above a plot?
Thank you!
Possibly you want to set the labels and the axes spines on top of the lines. This can easily be achieved with the "axes.axisbelow" rcParam.
plt.rcParams["axes.axisbelow"] = False

Categories

Resources