Set up labels and legend using plt.subplots() - python

I am using plt.sublot to create a figure with 12 subplots that share the same data so I want to show the labels and legend for one of them. I am accessing and plotting the data from a dictionary that contains pandas dataframes each with 20 columns(labels). Here my code:
fig, axes = plt.subplots(nrows=3, ncols=4, sharex=True, sharey=True)
plt.subplots_adjust(left = 0.06, bottom = 0.1, right = 0.8, top=0.9,
wspace=0.15, hspace=0.15)
fig.suptitle('HMC Water Balance', fontsize = 20, y= 0.95, x=0.45)
axes[0,0].plot(HMC_hydrographs['outlet'])
axes[0,1].plot(HMC_hydrographs['Outlet00'])
axes[0,2].plot(HMC_hydrographs['Outlet01'])
axes[0,3].plot(HMC_hydrographs['Outlet02'], label =
'Q_total','Q_reset','Q_river_initial', ...'20th_column_name')
ax = axes[0,3]
ax.legend(loc=0, prop={'size':8})
axes[1,0].plot(HMC_hydrographs['Outlet03'])
ax = axes[1,0]
ax.set_ylabel('Flux (m$^3$/s)', labelpad=10, fontsize = 18)
axes[1,1].plot(HMC_hydrographs['Outlet04'])
axes[1,2].plot(HMC_hydrographs['Outlet05'])
axes[1,3].plot(HMC_hydrographs['Outlet06'])
axes[2,0].plot(HMC_hydrographs['Outlet07'])
axes[2,1].plot(HMC_hydrographs['Outlet08'])
ax = axes[2,1]
ax.set_xlabel('Time (days)', fontsize = 18)
ax.xaxis.set_label_coords(1.1,-0.2)
axes[2,2].plot(HMC_hydrographs['Outlet09'])
axes[2,3].plot(HMC_hydrographs['Outlet10'])
I get the error:
File "<ipython-input-249-7e4552c68d90>", line 8
axes[0,3].plot(HMC_hydrographs['Outlet02'], label =
'Q_total','Q_reset','Q_river_initial')
^
SyntaxError: positional argument follows keyword argument
For what I understand the label argument takes only one argument but I have more than one label!
Please help me understand how to call the labels so they show like when I plot a single graph like:
fig = plt.figure()
ax = HMC_hydrographs['Outlet01'].plot()
Individual plot showing the correct labels

Not sure of the reasoning behind it but the way I managed to get the legend to show was to specify the labels directly into the legend argument, not using the 'label' argument. Here is the code:
fig, axes = plt.subplots(nrows=3, ncols=4, sharex=True, sharey=True)
plt.subplots_adjust(left = 0.06, bottom = 0.1, right = 0.8, top=0.9,
wspace=0.15, hspace=0.15)
fig.suptitle('HMC Water Balance', fontsize = 20, y= 0.95, x=0.45)
axes[0,0].plot(HMC_hydrographs['outlet'])
axes[0,1].plot(HMC_hydrographs['Outlet00'])
axes[0,2].plot(HMC_hydrographs['Outlet01'])
axes[0,3].plot(HMC_hydrographs['Outlet02'])
ax = axes[0,3]
ax.legend(hydro_header, bbox_to_anchor=(1.05, 1), loc=2,
borderaxespad=0.)
axes[1,0].plot(HMC_hydrographs['Outlet03'])
ax = axes[1,0]
ax.set_ylabel('Flux (m$^3$/s)', labelpad=10, fontsize = 18)
axes[1,1].plot(HMC_hydrographs['Outlet04'])
axes[1,2].plot(HMC_hydrographs['Outlet05'])
axes[1,3].plot(HMC_hydrographs['Outlet06'])
axes[2,0].plot(HMC_hydrographs['Outlet07'])
axes[2,1].plot(HMC_hydrographs['Outlet08'])
ax = axes[2,1]
ax.set_xlabel('Time (days)', fontsize = 18)
ax.xaxis.set_label_coords(1.1,-0.2)
axes[2,2].plot(HMC_hydrographs['Outlet09'])
axes[2,3].plot(HMC_hydrographs['Outlet10'])
hydro_header contains a list with the column names(labels) for my plots that I got by using:
hydro_header = list(HMC_hydrographs['outlet'])
Final figure with the subplots and legend

Related

How to create multiple legends?

fig, ax = plt.subplots(figsize = (10,7))
sns.lineplot(data = dearborn_1111_groupby,
x = 'Date',
y = 'Rent',
hue = 'generic_type',
palette = 'husl',
ax = ax).set_title('1111 Dearborn Median In Place Rents (2018 - 2022)')
sns.lineplot(data = dearborn_1111_groupby,
x = 'Date',
y = 'Rent_apartlist',
color = 'black',
ax = ax)
ax.legend(bbox_to_anchor = (1.15, 0.95), title = 'Unit Type')
plt.show()
line plot
I'm trying to add a legend containing the black line. However the black line is a separate lineplot. How Do I include the black line into the existing legend or a separate legend?
You can to add a label to the line, via sns.lineplot(..., label=...).
Note that when using bbox_to_anchor for the legend, you also need to set loc=.... By default, loc='best', which change the anchor point depending on small changes in the plot or its parameters. plt.tight_layout() fits the legend and the labels nicely into the plot figure.
Here is some example code using Seaborn's flights dataset.
import matplotlib.pyplot as plt
import seaborn as sns
flights = sns.load_dataset('flights')
fig, ax = plt.subplots(figsize=(12, 5))
sns.lineplot(data=flights,
x='year',
y='passengers',
hue='month',
palette='husl',
ax=ax)
sns.lineplot(data=flights,
x='year',
y='passengers',
color='black',
label='Black Line',
ax=ax)
ax.legend(bbox_to_anchor=(1.02, 0.95), loc="upper left", title='Unit Type')
ax.margins(x=0)
plt.tight_layout()
plt.show()

Matplotlib colorbar in multiple plots and it's placement

I am trying to plot 2 subplots and with colorbars for each of them. I have written the following code-
fig, ax = plt.subplots(nrows=1, ncols=2,figsize = (9,6))
fg1 = ax[0].scatter(no_trans["S1_ALL_DEM"].values, no_trans["Del_CAD"].values, c=no_trans["alpha"], cmap = "Set1", alpha=0.4 )
fg2 = ax[1].scatter(no_trans["S1_ALL_DEM"].values, no_trans["Del_CAD"].values, c=no_trans["alpha"], cmap = "Set1", alpha=0.4 )
cbar1 = plt.colorbar(fg1)
cbar1.ax.set_ylabel('alpha', labelpad=20, rotation =-90, fontsize = 12)
cbar2 = plt.colorbar(fg2)
cbar2.ax.set_ylabel('alpha', labelpad=20, rotation =-90, fontsize = 12)
ax[0].set_xlabel("DEM S1")
ax[0].set_ylabel("Del CAD")
ax[0].set_xlim(0,50)
ax[0].invert_yaxis()
ax[1].set_xlabel("DEM S1")
ax[1].set_ylabel("Del CAD")
ax[1].set_xlim(50,35000)
ax[1].invert_yaxis()
I need to fix the colorbars side by side with both of them, how can I do that?

How to Prevent Overlapping of Subplots in Python?

I am plotting various parameters in three different subplots. My second and third subplots are overlapping and I'm not understanding what is causing it. I have specified ax1, ax2, and ax3 and I'm thinking the issue may be from fig.add_subplot() but I'm not sure how to fix it. See my code below for reference. I only included the portions for the set up of the figure and the final plot since all three plots are generated practically in the same manner. I also included an image of what the plot is looking like that I wish to fix.
# Convert dataframe to 2D maps
lon_grid, lat_grid = np.meshgrid(data.lon.unique(), data.lat.unique())
L_grid = data.L.values.reshape(len(data.lat.unique()), len(data.lon.unique()))
Lam_grid = data.lam.values.reshape(len(data.lat.unique()), len(data.lon.unique()))
R_grid = data.R2.values.reshape(len(data.lat.unique()), len(data.lon.unique()))
# Make figures
fig = plt.figure(figsize= (10, 30), facecolor='white')
ax1 = fig.add_subplot(1,1,1,projection=ccrs.PlateCarree())
ax2 = fig.add_subplot(2,1,2,projection=ccrs.PlateCarree())
ax3 = fig.add_subplot(3,1,3,projection=ccrs.PlateCarree())
# Draw coastlines, states and countries for plot 3
ax3.coastlines()
ax3.add_feature(cfeature.BORDERS)
ax3.add_feature(cfeature.STATES)
# Draw parallels and meridians for plot 3
parallels = np.arange(-90,91,30)
meridians = np.arange(-180,181,60)
gl = ax3.gridlines(crs=ccrs.PlateCarree(), draw_labels=False,
linewidth=2, color='gray', alpha=0.5, linestyle='--')
gl.xlocator = mticker.FixedLocator(meridians)
gl.ylocator = mticker.FixedLocator(parallels)
ax3.set_xticks(np.arange(-180,181,30), crs=ccrs.PlateCarree())
ax3.set_yticks(parallels, crs=ccrs.PlateCarree())
lon_formatter = LongitudeFormatter(zero_direction_label=True)
lat_formatter = LatitudeFormatter()
ax3.xaxis.set_major_formatter(lon_formatter)
ax3.yaxis.set_major_formatter(lat_formatter)
# Add Longitude wrap-around points at 0/360 for plot 3
cyclic_R_grid, cyclic_lons = cutil.add_cyclic_point(R_grid, coord=data.lon.unique())
c3 = ax3.contourf(cyclic_lons, data.lat.unique(), cyclic_R_grid, alpha = 1.0,
transform=ccrs.PlateCarree(), levels = np.arange(0,100), \
vmin = 0.0, vmax = 100.0)
# Overplot rigidity
c3_ = ax3.imshow(np.flip(R_grid, axis=1), interpolation = 'gaussian', alpha = 0.6, extent = (-180,180,-90,90))
cbar = plt.colorbar(c3, ax=ax3, fraction=0.025)
cbar.set_label('R')
plt.show()
You are adding your subplots wrong. fig.add_subplot expects n_rows,n_cols, index in that order. So the correct definition would be
fig = plt.figure(figsize= (10, 30), facecolor='white')
ax1 = fig.add_subplot(3,1,1,projection=ccrs.PlateCarree())
ax2 = fig.add_subplot(3,1,2,projection=ccrs.PlateCarree())
ax3 = fig.add_subplot(3,1,3,projection=ccrs.PlateCarree())

How to plot to subplots during a loop

How can I create one plot for this loop?
I want to create some subplots according to i values taken from the loop. Do I need to create a new For/Loop which goes to each subplot? How can I do it?. This is my code:
fig, axes = plt.subplots(nrows=4, ncols=3)
fig.subplots_adjust(hspace=0.5)
fig.suptitle('Main plots')
for i in range(1,13):
month = [i]
DF_sub = DF[DF['months'].isin(month)]
out = pd.cut(DF_sub['new'], bins=[0, 0.25, 0.5, 0.75, 1], include_lowest=True)
out_norm = out.value_counts(sort=False, normalize=True)
ax = out_norm.plot.bar(rot=0, color="b", figsize=(6,4))
plt.title('Subplot -' + str(i))
Up to now, I just get the last one, but I am missing the previos i-s values from the loop
You need to pass the ax parameter to plot.bar to specify on which of your axes, returned from plt.subplots, the bar chart should be plotted, i.e.:
fig, axes = plt.subplots(nrows=4, ncols=3)
fig.subplots_adjust(hspace=0.5)
fig.suptitle('Main plots')
for i in range(1,13):
month = [i]
ax = axes[i - 1]
DF_sub = DF[DF['months'].isin(month)]
out = pd.cut(DF_sub['new'], bins=[0, 0.25, 0.5, 0.75, 1], include_lowest=True)
out_norm = out.value_counts(sort=False, normalize=True)
out_norm.plot.bar(rot=0, color="b", figsize=(6,4), ax=ax)
plt.title('Subplot -' + str(i))
If you don't pass the ax parameter, the bar chart will automatically be plotted on the currently active axis, which is the one most recently created unless set otherwise.

how to perform subplot in loop for seaborn charts

I have code that generates four subplots, but i want to generate those charts through loops , Currently i am following this piece of code to generate the chart
Code:
plt.figure(figsize=(20, 12))
plt.subplot(221)
sns.barplot(x = 'Category', y = 'POG_Added', data = df)
xticks(rotation = 90)
plt.xticks(size = 11)
plt.yticks(size = 11)
plt.xlabel("Category",size = 13)
plt.ylabel("POG_Added",size = 13)
plt.subplot(222)
sns.barplot(x = 'Category', y = 'Live_POG', data = df)
xticks(rotation = 90)
plt.xticks(size = 11)
plt.yticks(size = 11)
plt.xlabel("Category",size = 13)
plt.ylabel("Live_POG",size = 13)
plt.subplot(223)
sns.lineplot(x = 'Category', y = 'D01_CVR', data = df)
#sns.barplot(x = 'Category', y = 'D2-08-Visits', data = df,label='D2-08_Visits')
xticks(rotation = 90)
plt.xticks(size = 11)
plt.yticks(size = 11)
plt.xlabel("Category",size = 13)
plt.ylabel("D01_CVR",size = 13)
plt.subplot(224)
plt.xticks(rotation='vertical')
ax = sns.barplot(x='Category',y='D2-08-Units',data=df)
ax2 = ax.twinx()
ax2.plot(ax.get_xticks(), df["D01_CVR"], alpha = .75, color = 'r')
plt.subplots_adjust(hspace=0.55,wspace=0.55)
plt.show()
Here's how I do things like that:
import numpy as np
import matplotlib.pyplot as plt
data = [np.random.random((10, 10)) for _ in range(6)]
fig, axs = plt.subplots(ncols=3, nrows=2, figsize=(9, 6))
for ax, dat in zip(axs.ravel(), data):
ax.imshow(dat)
This produces:
The idea is that plt.subplots() produces an array of Axes objects, so you can loop over it and make your plots in the loop. In this case I need ndarray.ravel() because axs is a 2D array.
Consider tightening up repetitive code by:
Set unchanging aesthetics like all x-ticks and y-ticks font sizes in one call with plt.rc calls.
Build plt.subplots() and use its array of Axes objects.
Use ax argument of seaborn's barplot and lineplot to loop above Axes array.
While not completely DRY given the special two plots, below is adjustment:
# AXES AND TICKS FONT SIZES
plt.rc('xtick', labelsize=11)
plt.rc('ytick', labelsize=11)
plt.rc('axes', labelsize=13)
# FIGURE AND SUBPLOTS SETUP
fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(20, 12))
# BAR PLOTS (FIRST ROW)
for i, col in enumerate(['POG_Added', 'Live_POG']):
sns.barplot(x='Category', y=col, data=df, ax=axes[0,i])
axes[0,i].tick_params(axis='x', labelrotation=90)
# LINE PLOT
sns.lineplot(x='Category', y='D01_CVR', data=df, ax=axes[1,0])
axes[1,0].tick_params(axis='x', labelrotation=90)
# BAR + LINE DUAL PLOT
sns.barplot(x='Category', y='D2-08-Units', data=df, ax=axes[1,1])
ax2 = axes[1,1].twinx()
ax2.plot(axes[1,1].get_xticks(), df["D01_CVR"], alpha = .75, color = 'r')
axes[1,1].tick_params(axis='x', labelrotation=90)

Categories

Resources