Label is Missing from matplotlib legend - matplotlib

I'm plotting subplots with matplotlib and the legend does not show up for some plots.
In this example, the scatter plot legend does not show up.
import numpy as np
import matplotlib
from matplotlib import pyplot as plt
from matplotlib.legend_handler import HandlerLine2D
from matplotlib.patches import Rectangle, Circle
fig = plt.figure()
plt.cla()
plt.clf()
x = np.arange(5) + 1
y = np.full(5, 10)
fig, subplots = plt.subplots(2, sharex=False, sharey=False)
subplots[0].bar(x, y, color='r', alpha=0.5, label='a')
scat = subplots[0].scatter(x, y-1, color='g', label='c')
subplots[0].set_yscale('log')
subplots[1].bar(x, y, color='r', alpha=0.5, label='a')
x = [2, 3]
y = [4, 4]
subplots[1].bar(x, y, color='b', alpha=1, label='b')
subplots[1].set_yscale('log')
plt.legend(loc='center left', bbox_to_anchor=(1, 0.5), handler_map={scat: HandlerLine2D(numpoints=4)})
plt.show()
Here is what I tried as a workaround:
p1 = Rectangle((0, 0), 1, 1, fc="r", alpha=0.5)
p2 = Rectangle((0, 0), 1, 1, fc="b")
p3 = Circle((0, 0), 1, fc="g")
legend([p1, p2, p3], ['a', 'b', 'c'], loc='center left', bbox_to_anchor=(1, 0.5))
I really prefer to fix this without the workaround so if anyone knows how to fix it please let me know.
Also, an issue with the workaround is that the Circle object still appears as a bar on the legend.

plt.legend starts with a gca() (which returns the current axes):
# from pyplot.py:
def legend(*args, **kwargs):
ret = gca().legend(*args, **kwargs)
So calling plt.legend will only get you a legend on your last subplot. But it is also possible to call e.g. ax.legend(), or in your case subplots[0].legend(). Adding that to the end of your code gives me a legend for both subplots.
Sample:
for subplot in subplots:
subplot.legend(loc='center left', bbox_to_anchor=(1, 0.5))

Related

Colorbar in plots with embedded plots

While I managed to put a plot inside a plot (see the question here), I am finding trouble putting a colorbar to the larger (outside) plot. The code below is as simple as it gets, but for some reason it places the colorbar in the wrong axis:
import numpy as np
from numpy import random
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
# Canvas
fig, ax1 = plt.subplots(figsize=(12, 10))
left, bottom, width, height = [0.65, 0.15, 0.32, 0.30]
ax2 = fig.add_axes([left, bottom, width, height])
# Labels
xlabel = 'x'
ylabel = 'y'
cbarlabel = 'Color'
cmap = plt.get_cmap('turbo')
# Data
x, y, z = np.random.rand(3,200)
# Plotting
sc = ax1.scatter(x, y, marker='o', c=z, cmap=cmap)
ax2.scatter(x, y, c=z, cmap=cmap)
#
ax1.set_xlabel(xlabel)
ax1.set_ylabel(ylabel)
ax1.legend(fontsize=12, loc='upper left')
plt.tight_layout()
# Colormap
ax1 = plt.gca()
divider = make_axes_locatable(plt.gca())
cax = divider.append_axes("right", "2%", pad="1%")
cbar = plt.colorbar(sc, cax=cax) # Colorbar
cbar.set_label(cbarlabel, rotation=270, labelpad=30)
sc.set_clim(vmin=min(z), vmax=max(z))
#
plt.show()
I have also tried inset_axes as in the documentation example, to no avail.
The trick is to actually set active axes with plt.sca(ax1) and then create colorbar. I also simplified a code little bit.
Here is modified code putting colormap to the large plot:
import matplotlib.pyplot as plt
import numpy as np
from numpy import random
# Canvas
fig, ax1 = plt.subplots(figsize=(12, 10))
left, bottom, width, height = [0.45, 0.15, 0.32, 0.30]
ax2 = fig.add_axes([left, bottom, width, height])
# Labels
xlabel = 'x'
ylabel = 'y'
cbarlabel = 'Color'
cmap = plt.get_cmap('turbo')
# Data
x, y, z = np.random.rand(3,200)
# Plotting
sc = ax1.scatter(x, y, marker='o', c=z, cmap=cmap)
ax2.scatter(x, y, c=z, cmap=cmap)
# Set active axes
plt.sca(ax1)
cbar = plt.colorbar(sc) # Colorbar
cbar.set_label(cbarlabel, rotation=270, labelpad=30)
sc.set_clim(vmin=min(z), vmax=max(z))
#
ax1.set_xlabel(xlabel)
ax1.set_ylabel(ylabel)
ax1.legend(fontsize=12, loc='upper left')
plt.tight_layout()
plt.show()
Resulting in:

PyPlot: hide axes but keep axis labels

I have the following code:
import matplotlib.pyplot as plt
fig, axs = plt.subplots(1, 4)
for n, ax in enumerate(axs):
ax.plot([1, 2], [1, 2])
ax.set_xticks([])
ax.set_yticks([])
ax.set_xlabel(n)
plt.show()
...which displays this:
What I want is to hide the black boxes but keep the labels. I've tried adding ax.set_axis_off() but that removes the labels as well:
How can I do this?
Just change the color of spines to None:
fig, axs = plt.subplots(1, 4)
for n, ax in enumerate(axs):
ax.plot([1, 2], [1, 2])
ax.set_xticks([])
ax.set_yticks([])
ax.set_xlabel(n)
plt.setp(ax.spines.values(), color=None)
plt.show()

Matplotlib inconvenient "reset to original view" while previously zoomed

Updated:
After having zoomed to a region of interest, I would like to add a scatter point without having a reset to the original view.
It occurs when I double click after having zoomed to rectangle.
Of course this is a simplification of a problem encountered as I wanted to add markers to a large image after having properly zoomed to a region of interest.
Any help welcomed
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=1, figsize=(4,4))
plt.plot([0, 1, 2, 3], [10, 20, 30, 40])
def onclick(event):
if event.dblclick:
plt.scatter(event.xdata, event.ydata, c='r')
fig.canvas.mpl_connect('button_press_event', onclick)
plt.get_current_fig_manager().toolbar.zoom()
plt.show()
Answer:
import numpy as np
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=1, figsize=(4,4))
ax.imshow([[1, 2], [5, 6]])
ax.autoscale(False) # disable autoscaling for all future plotting functions.
def onclick(event):
if event.dblclick:
plt.scatter(event.xdata, event.ydata, c='r')
fig.canvas.mpl_connect('button_press_event', onclick)
plt.get_current_fig_manager().toolbar.zoom()
plt.show()
I believe the problem comes from the autoscale features that kicks in whenever you call plt.scatter(). The solution is simply to disable autoscale (but draw the initial plot beforehand):
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=1, figsize=(4, 4))
plt.plot([0, 1, 2, 3], [10, 20, 30, 40])
fig.canvas.draw() # force draw so that the axes are autoscaled here
ax.autoscale(False) # disable autoscaling for all future plotting functions.
def onclick(event):
if event.inaxes and event.dblclick:
plt.scatter(event.xdata, event.ydata, marker='o', s=10, c='r')
fig.canvas.mpl_connect('button_press_event', onclick)
plt.show()

Three plot in one figure using Matplotlib

I want my plot to look like the image below, how can I achieve that using Matplotlib?
And thanks
You can use GridSpec similar to this tutorial. Possibly there will be not enough space for the y tick labels, which can be mitigated by increasing the default wspace.
import matplotlib.pyplot as plt
fig, axs = plt.subplots(ncols=4, nrows=2, figsize=(12, 7), gridspec_kw={'wspace': 0.4})
gs = axs[0, 0].get_gridspec()
for ax in axs.ravel():
ax.remove()
ax1 = fig.add_subplot(gs[0, :2])
ax1.set_ylabel('A')
ax2 = fig.add_subplot(gs[0, 2:])
ax2.set_ylabel('B')
ax3 = fig.add_subplot(gs[1, 1:3])
ax3.set_ylabel('C')
for ax in (ax1, ax2, ax3):
ax.set_xlabel('D')
ax.legend(handles=[], title='legend', loc='upper right', frameon=False)
plt.show()

matplotlib xticks labels overlap

I am not able to get nicer spaces between the xticks with the following code:
import random
import matplotlib.pyplot as plt
coverages = [random.randint(1,10)*2] * 100
contig_names = ['AAB0008r'] * len(coverages)
fig = plt.figure()
fig.clf()
ax = fig.add_subplot(111)
ax.yaxis.grid(True, linestyle='-', which='major', color='grey', alpha=0.5)
ind = range(len(coverages))
rects = ax.bar(ind, coverages, width=0.2, align='center', color='thistle')
ax.set_xticks(ind)
ax.set_xticklabels(contig_names)
#function to auto-rotate the x axis labels
fig.autofmt_xdate()
plt.show()
How to get more space between the xticks so they do not look like overlapped anymore?
Thank you in advance.
You can try changing the figure size, the size of the xticklabels, their angle of rotation, etc.
# Set the figure size
fig = plt.figure(1, [20, 8])
# Set the x-axis limit
ax.set_xlim(-1,100)
# Change of fontsize and angle of xticklabels
plt.setp(ax.get_xticklabels(), fontsize=10, rotation='vertical')