How to adjust the legend not to overlap in matplotlib? - matplotlib

I want to draw a line&bar chart by Matplotlib, it seems the legend of chart will overlap on upper left part.
plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']
plt.figure(figsize=(7,5), dpi=100)
x = ['1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20','21','22','23','24','25','26','27','28','29','30','>30']
y = [0.0964,0.1606,0.1651,0.1395,0.1105,0.0829,0.0603,0.0436,0.0328,0.0245,0.0183,0.0135,0.0105,0.0082,0.0061,0.0052,0.0041,0.0030,0.0024,0.0022,0.0013,0.0012,0.0010,0.0009,0.0009,0.0007,0.0006,0.0004,0.0005,0.0002,0.0023]
z = [11541,19234,19776,16704,13237,9931,7215,5218,3931,2936,2194,1619,1262,984,735,625,496,357,282,269,161,146,124,108,104,78,69,50,62,29,274]
plt.bar(x=x, height=z, label='Vehicles Num', color='Blue', alpha=0.7, width=0.5)
# plt.legend(loc="upper left")
plt.legend(loc="upper right")
plt.title("Frequency Distribution of Hood Ajar/Closed Events",size=18)
plt.xlabel("Frequency",size=15)
plt.ylabel("Number of Vehicles",size=15)
plt.yticks(size = 11)
plt.xticks(size = 11)
ax2 = plt.twinx()
ax2.set_ylabel("Percentage",size=15)
ax2.plot(y)
ax2.yaxis.set_major_formatter(ticker.PercentFormatter(xmax=1, decimals=1))
plt.plot(x, y, "r", marker='.', c='r', ms=8, linewidth='1', label="Percentage")
plt.legend(loc="upper right")
# for a, b in zip(x, y):
# plt.text(a, b, str(b*100)+'%', ha='center', va='bottom', fontsize=13)
#plt.savefig('cx483_2.jpg')
plt.show()
What can I do to make my legend more harmonious? Thanks a lot.

Related

constrained_layout=True moves one column deeper

I used constrained_layout= True multiple times and everything worked good... now I added a second Colorbar an i get somthing like that:
How I can fix this? I want the same hight and space between the bars and plots.
colorbar_shrink = 0.6
pad=-0.15
fig, axarr = plt.subplots(nrows=2, ncols=2, figsize=(15, 10), constrained_layout=True,
sharey=True, subplot_kw={'projection': crs})
# fig.tight_layout()
# fig.subplots_adjust(wspace=0.01)
# fig.set_constrained_layout_pads(w_pad=0.02, h_pad=0.02, hspace=-0.2,
# wspace=0.2)
fig.suptitle('Bla', y=1.01)
# fig.set_constrained_layout_pads(w_pad=0, h_pad=0.05,hspace=0.1, wspace=0.2)
axlist = axarr.flatten()
for ax in axlist:
plot_background(ax)
print('First .')
levels = np.linspace(0, 2, 10)
cf1 = axlist[0].contourf(lon_2d, lat_2d, aod_dust_550nm, cmap='Oranges',
transform=ccrs.PlateCarree(), zorder=0, levels=levels, extend='both')
cf2 = axlist[0].contourf(lon_2d, lat_2d, tq, cmap='Blues', vmin=0.0001, vmax=10 ,
levels=tq_lev, norm=matplotlib.colors.LogNorm(),
transform=ccrs.PlateCarree(), zorder=0, extend='max')
cb1 = fig.colorbar(cf1, ax=axlist[0], orientation='horizontal', format='%.1f',
shrink=colorbar_shrink, pad=pad)
cb2 = fig.colorbar(cf2, ax=axlist[0], orientation='vertical', #format='%.4f',
shrink=colorbar_shrink)
cb1.set_label('Dust optical depth #550nm',labelpad=-45, fontsize=12)
cb2.ax.set_ylabel('TQ in kg m$^{-2}$')
cb2.formatter = LogFormatter()
cb2.set_ticks([1e-4,1e-3, 1e-2, 1e-1, 1e0, 10])
cb2.update_ticks()
print('Second..')
# Upper right plot - Wind and Windspeed
levels = np.linspace(0.0, 50.0, 50)
cf2 = axlist[1].contourf(lon_2d, lat_2d, windspeed_900, levels=levels,
cmap='jet', transform=ccrs.PlateCarree() ,zorder=0, extend='max')
#Every n-th quiver
wind_slice = (slice(None, None, 15), slice(None, None, 15))
c2 = axlist[1].quiver(lon_2d[wind_slice], lat_2d[wind_slice] ,
u_300.values[wind_slice] , v_300.values[wind_slice],
color='black', transform=ccrs.PlateCarree())
cb2 = fig.colorbar(cf2, ax=axlist[1], orientation='horizontal',format='%i',
shrink=colorbar_shrink)#, pad=paddy)
cb2.set_label('Wind speed in m s-1 #900hPa',labelpad=-45, fontsize=12)
plt.quiverkey(c2, 0.99, -0.16, 10,'velocity (10 m s$^{-1}$)',
labelpos='W',transform=ccrs.PlateCarree(), color='r')
# plt.show()
THanks a lot.

Remove padding in Matplotlib

I use plt.subplots to plot a list of images.
Here is my code:
m, n, c = output.shape
fig, ax = plt.subplots(nrows=4, ncols=1)
fig.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=None, hspace=None)
for i in range(4):
ax[i].imshow(output[:,:,i].reshape(m, n, 1), cmap='gray', vmin=0, vmax=1)
ax[i].axes.get_xaxis().set_visible(False)
ax[i].axes.get_yaxis().set_visible(False)
fig.set_facecolor('red')
plt.show()
And this is the result:
How can I remove the red space on the left and right of the figure?

Not getting legend in figure/plot

I am sharing Y-axis in two subplots, with the following codes but both shared plots are missing legends in them.
projectDir = r'/media/DATA/banikr_D_drive/model/2021-04-28-01-18-15_5_fold_114sub'
logPath = os.path.join(projectDir, '2021-04-28-01-18-15_fold_1_Mixed_loss_dice.bin')
with open(logPath, 'rb') as pfile:
h = pickle.load(pfile)
print(h.keys())
fig, ax = plt.subplots(2, figsize=(20, 20), dpi=100)
ax[0].plot(h['dice_sub_train'], color='tab:cyan', linewidth=2.0, label="Train")
ax[0].plot(smooth_curve(h['dice_sub_train']), color='tab:purple')
ax[0].set_xlabel('Epoch/iterations', fontsize=20)
ax[0].set_ylabel('Dice Score', fontsize=20)
ax[0].legend(loc='lower right', fontsize=20)#, frameon=False)
ax1 = ax[0].twiny()
ax1.plot(h['dice_sub_valid'], color='tab:orange', linewidth=2.0, alpha=0.9, label="Validation" )
ax1.plot(smooth_curve(h['dice_sub_valid']), color='tab:red')
# , bbox_to_anchor = (0.816, 0.85)
ax[1].plot(h['loss_sub_train'], color='tab:cyan', linewidth=2.0, label="Train")
ax[1].plot(smooth_curve(h['loss_sub_train']), color='tab:purple')
ax2 = ax[1].twiny()
ax2.plot(h['loss_sub_valid'], color='tab:orange', linewidth=2.0, label="Validation", alpha=0.6)
ax2.plot(smooth_curve(h['loss_sub_valid']), color='tab:red')
ax[1].set_xlabel('Epoch/iterations', fontsize=20)
ax[1].set_ylabel('loss(a.u.)', fontsize=20)
ax[1].legend(loc='upper right', fontsize=20)
# ,bbox_to_anchor = (0.8, 0.9)
plt.suptitle('Subject wise dice score and loss', fontsize=30)
plt.setp(ax[0].get_xticklabels(), fontsize=20, fontweight="normal", horizontalalignment="center") #fontweight="bold"
plt.setp(ax[0].get_yticklabels(), fontsize=20, fontweight='normal', horizontalalignment="right")
plt.setp(ax[1].get_xticklabels(), fontsize=20, fontweight="normal", horizontalalignment="center")
plt.setp(ax[1].get_yticklabels(), fontsize=20, fontweight="normal", horizontalalignment="right")
plt.show()
Any idea how to solve the issue?
[1]: https://i.stack.imgur.com/kg7PY.png
ax1 has a twin y-axis with ax[0], but they are two separate axes. That's why ax[0].legend() does not know about the Validation line of ax1.
To have Train and Validation on the same legend, plot empty lines on the main axes ax[0] and ax[1] with the desired color and label. This will generate dummy Validation entries on the main legend:
...
ax[0].plot([], [], color='tab:orange', label="Validation")
ax[0].legend(loc='lower right', fontsize=20)
...
ax[1].plot([], [], color='tab:orange', label="Validation")
ax[1].legend(loc='upper right', fontsize=20)
...

Is there a way to label each wedge of pie chart in this grid?

I want to have multiple pie charts in a grid.
Each pie chart will have a different number of wedges, values, and labels.
The code below shows multiple labels in one pie chart.
Is there a way to label each wedge of pie-charts in this grid?
import matplotlib.pyplot as plt
import numpy as np
def heatmap_with_circles(data_array,row_labels,column_labels,ax=None, cmap=None, norm=None, cbar_kw={}, cbarlabel="", **kwargs):
for row_index, row in enumerate(row_labels,0):
for column_index, column in enumerate(column_labels,0):
print('row_index: %d column_index: %d' %(row_index,column_index))
if row_index==0 and column_index==0:
colors=['indianred','orange','gray']
values=[10,20,30]
else:
values=[45,20,38]
colors=['pink','violet','green']
wedges, text = plt.pie(values,labels=['0', '2', '3'],labeldistance = 0.25,colors=colors)
print('len(wedges):%d wedges: %s, text: %s' %(len(wedges), wedges, text))
radius = 0.45
[w.set_center((column_index,row_index)) for w in wedges]
[w.set_radius(radius) for w in wedges]
# We want to show all ticks...
ax.set_xticks(np.arange(data_array.shape[1]))
ax.set_yticks(np.arange(data_array.shape[0]))
fontsize=10
ax.set_xticklabels(column_labels, fontsize=fontsize)
ax.set_yticklabels(row_labels, fontsize=fontsize)
#X axis labels at top
ax.tick_params(top=True, bottom=False,labeltop=True, labelbottom=False,pad=5)
plt.setp(ax.get_xticklabels(), rotation=55, ha="left", rotation_mode="anchor")
# We want to show all ticks...
ax.set_xticks(np.arange(data_array.shape[1]+1)-.5, minor=True)
ax.set_yticks(np.arange(data_array.shape[0]+1)-.5, minor=True)
ax.grid(which="minor", color="black", linestyle='-', linewidth=2)
ax.tick_params(which="minor", bottom=False, left=False)
data_array=np.random.rand(3,4)
row_labels=['Row1', 'Row2', 'Row3']
column_labels=['Column1', 'Column2', 'Column3','Column4']
fig, ax = plt.subplots(figsize=(1.9*len(column_labels),1.2*len(row_labels)))
ax.set_aspect(1.0)
ax.set_facecolor('white')
heatmap_with_circles(data_array,row_labels,column_labels, ax=ax)
plt.tight_layout()
plt.show()
After updating heatmap_with_circles
def heatmap_with_circles(data_array,row_labels,column_labels,ax=None, cmap=None, norm=None, cbar_kw={}, cbarlabel="", **kwargs):
labels = ['x', 'y', 'z']
for row_index, row in enumerate(row_labels,0):
for column_index, column in enumerate(column_labels,0):
print('row_index: %d column_index: %d' %(row_index,column_index))
if row_index==0 and column_index==0:
colors=['indianred','orange','gray']
values=[10,20,30]
else:
values=[45,20,38]
colors=['pink','violet','green']
# wedges, texts = plt.pie(values,labels=['0', '2', '3'],labeldistance = 0.45,colors=colors)
wedges, texts = plt.pie(values,labeldistance = 0.25,colors=colors)
print('text:%s len(wedges):%d wedges: %s' %(texts, len(wedges), wedges))
radius = 0.45
[w.set_center((column_index,row_index)) for w in wedges]
[w.set_radius(radius) for w in wedges]
[text.set_position((text.get_position()[0]+column_index,text.get_position()[1]+row_index)) for text in texts]
[text.set_text(labels[text_index]) for text_index, text in enumerate(texts,0)]
I got the following image :)
You could loop through the texts of each pie, get its xy position, add column_index and row_index, and set that as new position.
Some small changes to the existing code:
ax.grid(which="minor", ..., clip_on=False) to make sure the thick lines are shown completely, also near the border
ax.set_xlim(xmin=-0.5) to set the limits
import matplotlib.pyplot as plt
import numpy as np
def heatmap_with_circles(data_array, row_labels, column_labels, ax=None):
ax = ax or plt.gca()
for row_index, row in enumerate(row_labels, 0):
for column_index, column in enumerate(column_labels, 0):
colors = np.random.choice(['indianred', 'orange', 'gray', 'pink', 'violet', 'green'], 3, replace=False)
values = np.random.randint(10, 41, 3)
wedges, text = plt.pie(values, labels=['1', '2', '3'], labeldistance=0.25, colors=colors)
radius = 0.45
for w in wedges:
w.set_center((column_index, row_index))
w.set_radius(radius)
w.set_edgecolor('white')
# w.set_linewidth(1)
for t in text:
x, y = t.get_position()
t.set_position((x + column_index, y + row_index))
# We want to show all ticks...
ax.set_xticks(np.arange(data_array.shape[1]))
ax.set_yticks(np.arange(data_array.shape[0]))
fontsize = 10
ax.set_xticklabels(column_labels, fontsize=fontsize)
ax.set_yticklabels(row_labels, fontsize=fontsize)
# X axis labels at top
ax.tick_params(top=True, bottom=False, labeltop=True, labelbottom=False, pad=5)
plt.setp(ax.get_xticklabels(), rotation=55, ha="left", rotation_mode="anchor")
# We want to show all minor ticks...
ax.set_xticks(np.arange(data_array.shape[1] + 1) - .5, minor=True)
ax.set_yticks(np.arange(data_array.shape[0] + 1) - .5, minor=True)
ax.set_xlim(xmin=-.5)
ax.set_ylim(ymin=-.5)
ax.grid(which="minor", color="black", linestyle='-', linewidth=2, clip_on=False)
ax.tick_params(axis="both", which="both", length=0) # hide tick marks
data_array = np.random.rand(3, 4)
row_labels = ['Row1', 'Row2', 'Row3']
column_labels = ['Column1', 'Column2', 'Column3', 'Column4']
fig, ax = plt.subplots(figsize=(1.9 * len(column_labels), 1.2 * len(row_labels)))
ax.set_aspect(1.0)
ax.set_facecolor('white')
heatmap_with_circles(data_array, row_labels, column_labels, ax=ax)
plt.tight_layout()
plt.show()

interactive legend with twinx - matplotlib

i want to create a plot with two y-axis and interactive legend. I made a minimal "working" example based on: https://matplotlib.org/3.1.1/gallery/event_handling/legend_picking.html
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0.0, 5, 0.01)
y1 = 2*np.sin(2*np.pi*t)
y2 = 4*np.sin(2*np.pi*2*t)+1
fig, ax = plt.subplots()
ax.set_title('Click on legend line to toggle line on/off')
line1, = ax.plot(t, y1, lw=2, label='1 HZ')
ax2 = ax.twinx()
line2, = ax2.plot(t, y2, lw=2, label='2 HZ')
lines_twinx=[line1,line2]
lbl = [l.get_label() for l in lines_twinx]
leg=ax.legend(lines_twinx, lbl, loc="upper left",fontsize='xx-small', shadow=True)
leg.get_frame().set_alpha(0.4)
lined = dict()
for legline, origline in zip(leg.get_lines(), lines_twinx):
legline.set_picker(5) # 5 pts tolerance
lined[legline] = origline
def onpick(event):
# on the pick event, find the orig line corresponding to the
# legend proxy line, and toggle the visibility
legline = event.artist
origline = lined[legline]
vis = not origline.get_visible()
origline.set_visible(vis)
# Change the alpha on the line in the legend so we can see what lines
# have been toggled
if vis:
legline.set_alpha(1.0)
else:
legline.set_alpha(0.2)
fig.canvas.draw()
fig.canvas.mpl_connect('pick_event', onpick)
plt.show()
plot-figure
Somehow the legend is not clickable. Anybody knows what to do?
Using fig.legend() instead of ax.legend() helped me
leg=fig.legend(lines_twinx, lbl, loc="upper left",fontsize='xx-small', shadow=True)
view here