I want the green rectangle to not disappear as it moves from one value to another in matrix b. For example, the rectangle is around 0.24671953. Then the rectangle stays on this value. Then another rectangle appears onto the next value which is 0.25959473. Then another rectangle appears on 0.41092171, with the previous two rectangles not disappearing.
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
import seaborn as sns
import numpy as np
from celluloid import Camera
a = np.array([[0.24671953, 0.25959473, 0.85494718],
[0.60553861, 0.76276659, 0.41092171],
[0.37356358, 0.69378785, 0.46988614]])
b = np.array([[0.24671953,0.25959473],
[0.41092171,0.46988614],
[0.37356358,0.60553861]])
annot=True
fig, ax1 = plt.subplots(1)
camera = Camera(fig)
sns.set_style('white')
ax1 = sns.heatmap(a, linewidth=0.5,ax=ax1,annot=annot)
for bb in b.flatten():
ax1.add_patch(plt.Rectangle((np.where(a == bb)[1][0],
np.where(a == bb)[0][0]), 1, 1, fc='none', ec='green', lw=5, clip_on=False))
camera.snap()
animation = camera.animate(interval=800)
animation.save('animation2.gif')
plt.show()
It looks like celluloid clears the existing plot at each snap. You can recreate the plot from scratch at each step. The rectangles can be stored in a list.
To avoid that new colorbar positions are set at each step, you can use sns.heatmap's cbar_ax= parameter to always use the same colorbar ax:
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
from celluloid import Camera
a = np.array([[0.24671953, 0.25959473, 0.85494718],
[0.60553861, 0.76276659, 0.41092171],
[0.37356358, 0.69378785, 0.46988614]])
b = np.array([[0.24671953, 0.25959473],
[0.41092171, 0.46988614],
[0.37356358, 0.60553861]])
fig, (ax1, cbar_ax) = plt.subplots(ncols=2, gridspec_kw={'width_ratios': [20, 1]})
camera = Camera(fig)
sns.set_style('white')
rectangles = []
for bb in b.flatten():
sns.heatmap(a, linewidth=0.5, ax=ax1, annot=True, cbar_ax=cbar_ax)
rectangles.append(plt.Rectangle((np.where(a == bb)[1][0], np.where(a == bb)[0][0]), 1, 1,
fc='none', ec='green', lw=5, clip_on=False))
for rect in rectangles:
ax1.add_patch(rect)
camera.snap()
animation = camera.animate(interval=800)
animation.save('animation2.gif')
plt.show()
An alternative could be to directly use matplotlib's animation framework. Then, the code could look like:
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import seaborn as sns
import numpy as np
a = np.array([[0.24671953, 0.25959473, 0.85494718],
[0.60553861, 0.76276659, 0.41092171],
[0.37356358, 0.69378785, 0.46988614]])
b = np.array([[0.24671953, 0.25959473],
[0.41092171, 0.46988614],
[0.37356358, 0.60553861]])
fig, ax1 = plt.subplots()
sns.set_style('white')
sns.heatmap(a, linewidth=0.5, ax=ax1, annot=True)
def animate(i):
bb = b.flatten()[i]
patch = ax1.add_patch(plt.Rectangle((np.where(a == bb)[1][0], np.where(a == bb)[0][0]), 1, 1,
fc='none', ec='green', lw=5, clip_on=False))
return patch,
animation = FuncAnimation(fig, animate, frames=range(0, b.size), interval=800, repeat=False)
animation.save('animation2.gif')
plt.show()
Related
I would like to create a plot with a Cartopy plot on the left-hand side and two stacked Matplotlib plots on the right-hand side. If I'd only use Matplotlib plots, the code would be as follows.
import matplotlib.gridspec as gridspec
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
gs = gridspec.GridSpec(2, 2)
# LEFT
ax = fig.add_subplot(gs[:, 0])
ax.plot(np.arange(0, 1000, 100))
# RIGHT TOP
ax = fig.add_subplot(gs[0, 1])
ax.plot(np.arange(0, 1000, 100))
# RIGHT BOTTOM
ax = fig.add_subplot(gs[1, 1])
ax.plot(np.arange(0, 1000, 100))
plt.show()
... so far so good.
However, if I add a Cartopy plot, I don't manage to make it stick to the axis on the left-hand side. I suppose there's a problem with how I use ax = plt.axes().
import cartopy.crs as ccrs
import matplotlib.gridspec as gridspec
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
gs = gridspec.GridSpec(2, 2)
# LEFT
ax = fig.add_subplot(gs[:, 0])
ax = plt.axes(
projection = ccrs.Orthographic(
central_longitude=0,
central_latitude=0
)
)
ax.stock_img()
# RIGHT TOP
ax = fig.add_subplot(gs[0, 1])
ax.plot(np.arange(0, 1000, 100))
# RIGHT BOTTOM
ax = fig.add_subplot(gs[1, 1])
ax.plot(np.arange(0, 1000, 100))
plt.show()
How can I make the Cartopy plot stick to the axis of the subplot on the left-hand side?
That happens because after creating the left-pane, you created a new axis for cartopy covering the entire figure. Instead, you need to pass projection inside fig.add_subplot, like this:
import cartopy.crs as ccrs
import matplotlib.gridspec as gridspec
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
gs = gridspec.GridSpec(2, 2)
# LEFT
ax = fig.add_subplot(gs[:, 0], projection = ccrs.Orthographic(
central_longitude=0,
central_latitude=0
))
ax.stock_img()
# RIGHT TOP
ax = fig.add_subplot(gs[0, 1])
ax.plot(np.arange(0, 1000, 100))
# RIGHT BOTTOM
ax = fig.add_subplot(gs[1, 1])
ax.plot(np.arange(0, 1000, 100))
plt.show()
I'm new to python's matplotlib, and i want to animate a 1x1 square that moves diagonally across a grid space. I have written this bit of code that almost does what i want it to do, but the previous positions of the rectangle are still visible.
import matplotlib.pyplot as plt
import matplotlib.animation
import numpy as np
from matplotlib.patches import Rectangle
moving_block = [[0,0],[1,1],[2,2],[3,3],[4,4],[5,5]]
fig, ax = plt.subplots()
#set gridlines and lines every one unit
ax.grid(which='both')
ax.axis([0,5,0,5])
rectangle = Rectangle(moving_block[0], 1,1)
ax.add_patch(rectangle)
def animate(i):
ax.add_patch(Rectangle(moving_block[i], 1,1))
ani = matplotlib.animation.FuncAnimation(fig, animate,
frames=len(moving_block), interval=300, repeat=True)
plt.show()
How can i make only the current rectangle visible? Should i be using something other than this ax.add_patch(Rectangle) function?
Added cleaning "ax", at each iteration in the function "animate".
If you are satisfied with the answer, do not forget to vote for it :-)
import matplotlib.pyplot as plt
import matplotlib.animation
from matplotlib.patches import Rectangle
moving_block = [[0,0],[1,1],[2,2],[3,3],[4,4],[5,5]]
fig, ax = plt.subplots()
#set gridlines and lines every one unit
ax.grid(which='both')
ax.axis([0, 5, 0, 5])
rectangle = Rectangle(moving_block[0], 1,1)
ax.add_patch(rectangle)
def animate(i):
ax.clear()
ax.axis([0, 5, 0, 5])
ax.grid(which='both')
ax.add_patch(Rectangle(moving_block[i], 1,1))
ani = matplotlib.animation.FuncAnimation(fig, animate,
frames=len(moving_block), interval=300, repeat=True)
plt.show()
Suppose I draw a plot using the code below. How to plot the rug part on the top edge of x-axis?
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
sns.distplot(np.random.normal(0, 0.1, 100), rug=True, hist=False)
plt.show()
The seaborn.rugplot creates a LineCollection with the length of the lines being defined in axes coordinates. Those are always the same, such that the plot does not change if you invert the axes.
You can create your own LineCollection from the data though. The advantage compared to using bars is that the linewidth is in points and therefore no lines will be lost independend of the data range.
import numpy as np; np.random.seed(42)
import matplotlib.pyplot as plt
import seaborn as sns
def upper_rugplot(data, height=.05, ax=None, **kwargs):
from matplotlib.collections import LineCollection
ax = ax or plt.gca()
kwargs.setdefault("linewidth", 1)
segs = np.stack((np.c_[data, data],
np.c_[np.ones_like(data), np.ones_like(data)-height]),
axis=-1)
lc = LineCollection(segs, transform=ax.get_xaxis_transform(), **kwargs)
ax.add_collection(lc)
fig, ax = plt.subplots()
data = np.random.normal(0, 0.1, 100)
sns.distplot(data, rug=False, hist=False, ax=ax)
upper_rugplot(data, ax=ax)
plt.show()
Rugs are just thin lines at the data points. Yo can think of them as thin bars. That being said, you can have a following work around: Plot distplot without rugs and then create a twin x-axis and plot a bar chart with thin bars. Following is a working answer:
import numpy as np; np.random.seed(21)
import matplotlib.pyplot as plt
import seaborn as sns
fig, ax = plt.subplots()
data = np.random.normal(0, 0.1, 100)
sns.distplot(data, rug=False, hist=False, ax=ax)
ax1 = ax.twinx()
ax1.bar(data, height=ax.get_ylim()[1]/10, width=0.001)
ax1.set_ylim(ax.get_ylim())
ax1.invert_yaxis()
ax1.set_yticks([])
plt.show()
In the example below, I create a rectangular patch using matplotlib.patches.Polygon. Is there a way to scale the patch before adding it to the plot?
I've tried using matplotlib.transforms.Affine2D in a variety of ways with no success. As usual, the matplotlib documentation on transformations is woefully insufficient.
import matplotlib.pyplot as plt
from matplotlib.patches import Polygon
fig = plt.figure()
ax = fig.add_subplot(111)
plt.plot([-3,3],[-3,3])
x = [-1,0,1,1,0,-1]
y = [1,1,1,-1,-1,-1]
poly = Polygon( zip(x,y), facecolor='red', edgecolor='red', alpha=0.5)
ax.add_patch(poly)
plt.show()
If by scale you mean multiplication by a factor, you can easily do this via numpy.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Polygon
fig = plt.figure()
ax = fig.add_subplot(111)
plt.plot([-3,3],[-3,3])
x = [-1,0,1,1,0,-1]
y = [1,1,1,-1,-1,-1]
scale = 2
poly = Polygon( np.c_[x,y]*scale, facecolor='red', edgecolor='red', alpha=0.5)
ax.add_patch(poly)
plt.show()
The same can be achieved with a matplotlib.transforms.Affine2D() transform.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Polygon
import matplotlib.transforms as transforms
fig = plt.figure()
ax = fig.add_subplot(111)
plt.plot([-3,3],[-3,3])
x = [-1,0,1,1,0,-1]
y = [1,1,1,-1,-1,-1]
trans = transforms.Affine2D().scale(2) + ax.transData
poly = Polygon( np.c_[x,y], facecolor='red', edgecolor='red', alpha=0.5,
transform=trans)
ax.add_patch(poly)
plt.show()
Although it seems a bit overkill for a simple scaling like this.
I am trying to plot a colorbar in Python using the matplotlib libraries. The plot works well, but the color bar wont show the end ticks on the color bar.
Using the following command plots the colorbar properly, but I only have ticks ranging from -1.6 to +1.6 ( the top and bottom ticks are absent). The range of my data is from -2 to +2.
fig.colorbar(surf, shrink=1, aspect=12)
This is seen in the following figure:
I tried using the command:
cbar.set_ticks([-2,-1,0,1,2]);
But that also failed to get the correct result.
UPDATE:
I tried using the ticks=[-2,0,2] parameter, but that did not work as well. This is a snippet of my plotting code:
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
CHI = np.linspace(-45, 45, 35);
M = np.linspace(0, 1, 35)
CHI, M = np.meshgrid(CHI, M)
R = 2*M*np.sin( 2 * np.deg2rad(CHI) )
surf = ax.plot_surface(CHI, M, R, rstride=1, cstride=1, cmap=cm.hsv,linewidth=0, antialiased=False)
ax.set_xlim(-45,45)
cbar = plt.colorbar(surf, shrink=1, aspect=12, ticks=[-2,-1,0,1,2])
plt.show()
This produces the following plot:
As seen, the colorbar lacks the end ticks, viz. -2 and 2
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
CHI = np.linspace(-45, 45, 35);
M = np.linspace(0, 1, 35)
CHI, M = np.meshgrid(CHI, M)
R = 2*M*np.sin( 2 * np.deg2rad(CHI) )
surf = ax.plot_surface(CHI, M, R, rstride=1, cstride=1, cmap=cm.hsv,linewidth=0, antialiased=False)
surf.set_clim([-2, 2]) # <- this is the important line
ax.set_xlim(-45,45)
cbar = plt.colorbar(surf, shrink=1, aspect=12, ticks=[-2,-1,0,1,2])
plt.show()
Something is going wrong with the auto-scaling (I would guess issues with floating point equality tests), if you explicitly set the clim to [-2, 2] it works.
You should be able to set the ticks parameter when calling plt.colorbar:
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
cmap = plt.get_cmap('jet')
data = np.random.randint(-2,3, size=(10,10))
im = ax.imshow(data, interpolation='nearest', cmap=cmap)
cbar = plt.colorbar(im, ticks=[-2,-1,0,1,2])
plt.show()