jupyter notebook matplotlib show plot and then plot on the origin figure - matplotlib

I want to plot a white plot with two axes, show it to the user, then add a line to the white plot with two axes, show it to the user, then add some dot to the line, then show it to the user. How can I do this without copying the code again and again?
What I'm doing now is in the first code chunk
import math
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
fig = plt.figure(figsize=(5,5))
ax = plt.axes()
ax.set_xlabel('cat')
ax.set_ylabel('dog')
plt.title("Set of 2 animals")
plt.show()
then in the second code chunk
fig = plt.figure(figsize=(5,5))
ax = plt.axes()
x = np.linspace(0, 1.0, 1000)
ax.plot(x, 1.0-x,zorder = 0)
ax.set_xlabel('cat')
ax.set_ylabel('dog')
plt.title("Set of 2 animals")
plt.show()
then in the third code chunk
fig = plt.figure(figsize=(5,5))
ax = plt.axes()
x = np.linspace(0, 1.0, 1000)
ax.plot(x, 1.0-x,zorder = 0)
ax.set_xlabel('cat')
ax.set_ylabel('dog')
plt.title("Set of 2 animals")
p0 = 0.5
p1 = 0.5
color = "blue"
textd =0.05
ax.scatter([p0],[p1], color = color,zorder=1)
ax.text(p0+textd, p1+textd, 'tiger',color = color,zorder =2)
plt.show()
What I'm looking for is things like in the first code chunk
import math
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
fig = plt.figure(figsize=(5,5))
ax = plt.axes()
ax.set_xlabel('cat')
ax.set_ylabel('dog')
plt.title("Set of 2 animals")
plt.show()
then in the second code chunk
add line directly without duplicating the code for making axes
plt.show()
then in the third code chunk
add point directly without duplicating the code for making axes and lines
plt.show()

Update: I actually figured out the answer.
def plot(step):
fig = plt.figure(figsize=(5,5))
ax = plt.axes()
ax.set_xlabel('cat')
ax.set_ylabel('dog')
plt.title("Set of 2 animals")
if step>=1:
x = np.linspace(0, 1.0, 1000)
ax.plot(x, 1.0-x,zorder = 0)
if step>=2:
p0 = 0.5
p1 = 0.5
color = "blue"
textd =0.05
ax.scatter([p0],[p1], color = color,zorder=1)
ax.text(p0+textd, p1+textd, 'tiger',color = color,zorder =2)
plot.show()
should be able to solve the problem.

Related

How can I remove colormaps in matplotlib? [duplicate]

This question already has answers here:
Display image as grayscale using matplotlib
(9 answers)
Closed 4 years ago.
I have the following code:
fig, ax = plt.subplots()
fig.set_size_inches(10, 10, forward=True)
min_val, max_val = 0, 28
inputBild = np.round(np.reshape(inputBild, [28, 28]), 1)
plt.imshow(inputBild)
for i in range(28):
for j in range(28):
c = inputBild[j,i]
ax.text(i, j, str(c), va='center', ha='center')
ax.set_facecolor((1.0, 0.47, 0.42))
plt.savefig('/tmp/inputMitZahlOhneCmap.png', bbox_inches='tight')
inputBild is a random image of the mnist dataset.
I want to only plot the numbers but not the colormap.
How can I remove it if I didn't even specify one?
I am not sure if you want a scatter plot when you say "only plot the numbers" but looking at your usage of imshow, I think you want to hide the colorbar. Here is an example:
With color bar
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111)
data = np.random.rand(100, 100)
cax = ax.imshow(data)
cbar = plt.colorbar(cax) # This line includes the color bar
Without color bar
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111)
data = np.random.rand(100, 100)
cax = ax.imshow(data)
Deleting color bar: Method 1 (not showing initial lines of code)
data = np.random.rand(100, 100)
cax = ax.imshow(data)
cbar = plt.colorbar(cax)
cbar.remove()
Deleting color bar: Method 2 (not showing initial lines of code)
data = np.random.rand(100, 100)
cax = ax.imshow(data)
plt.colorbar(cax)
plt.delaxes(fig.axes[1]) # axes[0] correspond to the main plot.
Output Method 1 and 2

How to remove spacing from figure created with imshow()?

I have a matrix that I want to show (np.asarray(vectors).T) and so far everything works except that the image is having way to much padding below the bottom x-axis.
I tried to use tight_layout() but it has absolutely no effect.
How can I crop my image correctly such that there is not so much spacing
import numpy as np
import matplotlib.pyplot as plt
# Creating fake data
topn = 15
nb_classes = 13
rows = 27
columns = nb_classes * topn
labels = ['Class {:d}'.format(i) for i in range(nb_classes)]
m = np.random.random((rows,columns))
# Plotting
plt.figure()
plt.imshow(m, interpolation='none')
plt.grid(False)
plt.xlabel('Word', size=16)
plt.ylabel('Dimension', size=16)
ax = plt.gca()
ax.yaxis.set_ticks_position("right")
ax.xaxis.set_ticks_position("top")
yticks = list()
for i in range(0, nb_classes):
if i != 0:
plt.axvline(i*n - 0.5, c='w')
yticks.append((i*n - 0.5 + n/2))
plt.xticks(yticks, labels, rotation=90)
plt.tight_layout()
plt.show()
This is the resulting image (grey lines just to visualize the size):
Use plt.figure(figsize=(8,4)) and aspect='auto' in the call of plt.imshow:
import numpy as np
import matplotlib.pyplot as plt
# Creating fake data
topn = 15
nb_classes = 13
rows = 27
columns = nb_classes * topn
labels = ['Class {:d}'.format(i) for i in range(nb_classes)]
m = np.random.random((rows,columns))
# Plotting
plt.figure(figsize=(8,4))
plt.imshow(m, interpolation='None', aspect='auto')
plt.grid(False)
plt.xlabel('Word', size=16)
plt.ylabel('Dimension', size=16)
ax = plt.gca()
ax.yaxis.set_ticks_position("right")
ax.xaxis.set_ticks_position("top")
yticks = list()
for i in range(0, nb_classes):
if i != 0:
plt.axvline(i*n - 0.5, c='w')
yticks.append((i*n - 0.5 + n/2))
plt.xticks(yticks, labels, rotation=90)
plt.tight_layout()
plt.show()

A presentable way to plot frequency of 43 distinct classes

I created the following histogram from the frequeny of each class in a training set
The label of each class is too long and is similar to
Speed limit (20km/h)
Can I place each label on the bar itself?
Maybe something like this?
import numpy as np
import matplotlib.pyplot as plt
N=5
xlabel = ["Speed limit ("+str(i)+"km/h)" for i in range(0,N)]
xs = np.arange(0,7,1.5)
ys = [8,6,10,7,9]
width = 0.3*np.ones(N)
fig, ax = plt.subplots()
bars = ax.bar(xs, ys, width, color='k',alpha=0.3)
plt.xticks(xs, xlabel,rotation=270)
for i,bar in enumerate(bars):
height = bar.get_height()
ax.text(bar.get_x() + bar.get_width()/2., 0.1*height,
'%s' % xlabel[i],rotation=90,ha='center', va='bottom')
plt.show()
To change it to horizontal bar plot:
import numpy as np
import matplotlib.pyplot as plt
N = 5
xlabel = ["Speed limit ("+str(i)+"km/h)" for i in range(0,5)]
xs = np.arange(0,5)/2
ys = [8,6,10,7,9]
width = 0.3*np.ones(N)
fig, ax = plt.subplots()
bars = ax.barh(xs, ys, width, color='k',alpha=0.3)
plt.xticks([])
for i,bar in enumerate(bars):
height = bar.get_height()
ax.text(bar.get_x()+3, bar.get_y()+bar.get_height()/3,
'%s' % xlabel[i],rotation=0,ha='center', va='bottom')
plt.tight_layout()
plt.show()

How to plot secondary_y in log scale in pyplot

I would like to have two lines (or better scatter plots) in one plot.
The Secondary Y line should be in log scale. How to do it with python matplotlib?
You can create a second y axis by using ax2 = ax.twinx(). You can then, as tacaswell pointed out in the comments, set this second axis to log scale.
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize=(5,3))
ax = fig.add_subplot(111)
ax2 = ax.twinx()
x = np.random.rand(10)
y = np.random.rand(10)
y2 = np.random.randint(1,10000, size=10)
l1 = ax.scatter(x,y, c="b", label="lin")
l2 = ax2.scatter(x,y2, c="r", label="log")
ax2.set_yscale("log")
ax2.legend(handles=[l1, l2])
ax.set_ylabel("Linear axis")
ax2.set_ylabel("Logarithmic axis")
plt.tight_layout()
plt.show()

Embedding small plots inside subplots in matplotlib

If you want to insert a small plot inside a bigger one you can use Axes, like here.
The problem is that I don't know how to do the same inside a subplot.
I have several subplots and I would like to plot a small plot inside each subplot.
The example code would be something like this:
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
for i in range(4):
ax = fig.add_subplot(2,2,i)
ax.plot(np.arange(11),np.arange(11),'b')
#b = ax.axes([0.7,0.7,0.2,0.2])
#it gives an error, AxesSubplot is not callable
#b = plt.axes([0.7,0.7,0.2,0.2])
#plt.plot(np.arange(3),np.arange(3)+11,'g')
#it plots the small plot in the selected position of the whole figure, not inside the subplot
Any ideas?
I wrote a function very similar to plt.axes. You could use it for plotting yours sub-subplots. There is an example...
import matplotlib.pyplot as plt
import numpy as np
#def add_subplot_axes(ax,rect,facecolor='w'): # matplotlib 2.0+
def add_subplot_axes(ax,rect,axisbg='w'):
fig = plt.gcf()
box = ax.get_position()
width = box.width
height = box.height
inax_position = ax.transAxes.transform(rect[0:2])
transFigure = fig.transFigure.inverted()
infig_position = transFigure.transform(inax_position)
x = infig_position[0]
y = infig_position[1]
width *= rect[2]
height *= rect[3] # <= Typo was here
#subax = fig.add_axes([x,y,width,height],facecolor=facecolor) # matplotlib 2.0+
subax = fig.add_axes([x,y,width,height],axisbg=axisbg)
x_labelsize = subax.get_xticklabels()[0].get_size()
y_labelsize = subax.get_yticklabels()[0].get_size()
x_labelsize *= rect[2]**0.5
y_labelsize *= rect[3]**0.5
subax.xaxis.set_tick_params(labelsize=x_labelsize)
subax.yaxis.set_tick_params(labelsize=y_labelsize)
return subax
def example1():
fig = plt.figure(figsize=(10,10))
ax = fig.add_subplot(111)
rect = [0.2,0.2,0.7,0.7]
ax1 = add_subplot_axes(ax,rect)
ax2 = add_subplot_axes(ax1,rect)
ax3 = add_subplot_axes(ax2,rect)
plt.show()
def example2():
fig = plt.figure(figsize=(10,10))
axes = []
subpos = [0.2,0.6,0.3,0.3]
x = np.linspace(-np.pi,np.pi)
for i in range(4):
axes.append(fig.add_subplot(2,2,i))
for axis in axes:
axis.set_xlim(-np.pi,np.pi)
axis.set_ylim(-1,3)
axis.plot(x,np.sin(x))
subax1 = add_subplot_axes(axis,subpos)
subax2 = add_subplot_axes(subax1,subpos)
subax1.plot(x,np.sin(x))
subax2.plot(x,np.sin(x))
if __name__ == '__main__':
example2()
plt.show()
You can now do this with matplotlibs inset_axes method (see docs):
from mpl_toolkits.axes_grid.inset_locator import inset_axes
inset_axes = inset_axes(parent_axes,
width="30%", # width = 30% of parent_bbox
height=1., # height : 1 inch
loc=3)
Update: As Kuti pointed out, for matplotlib version 2.1 or above, you should change the import statement to:
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
There is now also a full example showing all different options available.
From matplotlib 3.0 on, you can use matplotlib.axes.Axes.inset_axes:
import numpy as np
import matplotlib.pyplot as plt
fig, axes = plt.subplots(2,2)
for ax in axes.flat:
ax.plot(np.arange(11),np.arange(11))
ins = ax.inset_axes([0.7,0.7,0.2,0.2])
plt.show()
The difference to mpl_toolkits.axes_grid.inset_locator.inset_axes mentionned in #jrieke's answer is that this is a lot easier to use (no extra imports etc.), but has the drawback of being slightly less flexible (no argument for padding or corner locations).
source: https://matplotlib.org/examples/pylab_examples/axes_demo.html
from mpl_toolkits.axes_grid.inset_locator import inset_axes
import matplotlib.pyplot as plt
import numpy as np
# create some data to use for the plot
dt = 0.001
t = np.arange(0.0, 10.0, dt)
r = np.exp(-t[:1000]/0.05) # impulse response
x = np.random.randn(len(t))
s = np.convolve(x, r)[:len(x)]*dt # colored noise
fig = plt.figure(figsize=(9, 4),facecolor='white')
ax = fig.add_subplot(121)
# the main axes is subplot(111) by default
plt.plot(t, s)
plt.axis([0, 1, 1.1*np.amin(s), 2*np.amax(s)])
plt.xlabel('time (s)')
plt.ylabel('current (nA)')
plt.title('Subplot 1: \n Gaussian colored noise')
# this is an inset axes over the main axes
inset_axes = inset_axes(ax,
width="50%", # width = 30% of parent_bbox
height=1.0, # height : 1 inch
loc=1)
n, bins, patches = plt.hist(s, 400, normed=1)
#plt.title('Probability')
plt.xticks([])
plt.yticks([])
ax = fig.add_subplot(122)
# the main axes is subplot(111) by default
plt.plot(t, s)
plt.axis([0, 1, 1.1*np.amin(s), 2*np.amax(s)])
plt.xlabel('time (s)')
plt.ylabel('current (nA)')
plt.title('Subplot 2: \n Gaussian colored noise')
plt.tight_layout()
plt.show()