Matplotlib FuncAnimation color changing scatter plot - matplotlib

I am trying to create an animated scatter plot whereby the scatter points plot in order and change color over time, thus the newest scatter points always appear in the same color (in this case, red) while the older scatter points age to different colors using a color map.
The code works except for the newest scatter point in every frame of the animation, which appears as the 'oldest' color in the plot, rather than the newest. How can I get it to appear in the correct color?
My code is this:
import matplotlib.animation as animation
from matplotlib import cm
import matplotlib.pyplot as plt
%matplotlib notebook
brg = cm.get_cmap('hsv',500)
cmapz = brg(range(500))
x = [0]
y = [0]
def update_lines(num):
dx = x[-1]+np.random.random()
x.append(dx)
dy = np.random.random()
y.append(dy)
text.set_text("{:d}: [{:.0f},{:.0f}]".format(num, x[-1], y[-1]))
array = cmapz[:num]
graph.set_offsets(np.c_[x, y])
graph.set_color(array[::-1])
return graph,
fig,ax=plt.subplots(1,1,figsize=(8,5))
ax = plt.axes(xlim=(0,251),ylim=(-1,2))
graph = ax.scatter(x, y,c=cmapz[0])
text = fig.text(0, 1, "TEXT", va='top')
ani = animation.FuncAnimation(fig, update_lines, frames=499, interval=10, blit=False, repeat = False)
plt.show()

Related

Animate 2 different plots on top of each other with Matplotlib

SO I am have animated a series of frames with Matplotlib. Now there is a specific point for every frame that I want to mark with a red dot. I have the index of the dot of every frame in a list. How can I add the plotting of the dot to the animation.
here is my code:
data_clean is the main data that I'm already animating. pred is the list that contains the dots.
fig = plt.figure(figsize=(10,5))
ax= fig.add_subplot(111,xlabel='Range bins', ylabel='Doppler bins' )
im = ax.imshow(data_clean[0,0,...], vmin= -60, vmax=0, animated=True)
cbar = fig.colorbar(im)
cbar.set_label('dB Full Scale')
#this should scatter the dot
im4 = plt.scatter(*pred[:,0], color="r")
def animate(i):
im3.set_array(data_clean[i,0])
im4.set_array(pred[:,i])
return im3, im4
anim = animation.FuncAnimation(fig, animate,
frames=50, interval=50, blit=False, repeat=True)

How to expand matplolib window without stretching the plot?

I want to increase the grey area around the plot, but keeping the plot the same size. I've already tried changing the figure size, which ends up stretching the plot.
The axes inside the figure is positionned relative to the figure. Per default you have e.g. a fraction of 0.125 of figure width as space at the left. This means that resizing the figure, scales the axes as well.
You may calculate how much the spacings need to change such that if the figure is rescaled, the axes size remains constant. The new spacings then need to be set using fig.subplots_adjust.
import matplotlib.pyplot as plt
def set_figsize(figw,figh, fig=None):
if not fig: fig=plt.gcf()
w, h = fig.get_size_inches()
l = fig.subplotpars.left
r = fig.subplotpars.right
t = fig.subplotpars.top
b = fig.subplotpars.bottom
hor = 1.-w/float(figw)*(r-l)
ver = 1.-h/float(figh)*(t-b)
fig.subplots_adjust(left=hor/2., right=1.-hor/2., top=1.-ver/2., bottom=ver/2.)
fig, ax=plt.subplots()
ax.plot([1,3,2])
set_figsize(9,7)
plt.show()
You may then also use this function to update the subplot params when the figure window is resized.
import matplotlib.pyplot as plt
class Resizer():
def __init__(self,fig=None):
if not fig: fig=plt.gcf()
self.fig=fig
self.w, self.h = self.fig.get_size_inches()
self.l = self.fig.subplotpars.left
self.r = self.fig.subplotpars.right
self.t = self.fig.subplotpars.top
self.b = self.fig.subplotpars.bottom
def set_figsize(self, figw,figh):
hor = 1.-self.w/float(figw)*(self.r-self.l)
ver = 1.-self.h/float(figh)*(self.t-self.b)
self.fig.subplots_adjust(left=hor/2., right=1.-hor/2., top=1.-ver/2., bottom=ver/2.)
def resize(self, event):
figw = event.width/self.fig.dpi
figh = event.height/self.fig.dpi
self.set_figsize( figw,figh)
fig, ax=plt.subplots()
ax.plot([1,3,2])
r = Resizer()
cid = fig.canvas.mpl_connect("resize_event", r.resize)
plt.show()
In the window of a matplotlib figure, there's a button called 'Configure subplots' (see below picture, screenshot on Windows 10 with matplotlib version 1.5.2). Try to change the parameters 'left' and 'right'. You can also change these parameters with plt.subplots_adjust(left=..., bottom=..., right=..., top=..., wspace=..., hspace=...).

Map a colorbar based on plot instead of imshow

I'm trying to get a colorbar for the following minimal example of my code.
g1 = gridspec.GridSpec(1, 1)
f, ((ax0)) = plt.subplots(1, 1)
ax0 = subplot(g1[0])
cmap = matplotlib.cm.get_cmap('viridis')
for i in linspace(0,1,11):
x = [-1,0,1]
y = [i,i,i]
rgba = cmap(i)
im = ax0.plot(x,y,color=rgba)
f.colorbar(im)
I also tried f.colorbar(cmap)
Probably pretty obvious, but I get errors such as
'ListedColormap' object has no attribute 'autoscale_None'
In reality, the value defining i is more complex, but I think this should do the trick. My data is plotted with plot and not with imshow (for which I know how to make the colormap).
The answers so far seem overly complicated. fig.colorbar() expects a ScalarMappable as its first argument. Often ScalarMappables are produced by imshow or contourplots and are readily avaible.
In this case you would need to define your custom ScalarMappable to provide to the colorbar.
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
cmap = plt.cm.get_cmap('viridis')
for i in np.linspace(0,1,11):
x = [-1,0,1]
y = [i,i,i]
rgba = cmap(i)
im = ax.plot(x,y,color=rgba)
sm = plt.cm.ScalarMappable(cmap=cmap)
sm.set_array([])
fig.colorbar(sm)
plt.show()
You should pass an Image or ContourSet when you call colorbar on a Figure.
You can make an image of the data points by calling plt.imshow with the data. You can start with this:
data = []
for i in np.linspace(0,1,11):
x = [-1,0,1]
y = [i,i,i]
rgba = cmap(i)
ax0.plot(x,y,color=rgba)
data.append([x, y])
image = plt.imshow(data)
figure.colorbar(image)
plt.show()
Reference:
https://matplotlib.org/api/figure_api.html#matplotlib.figure.Figure.colorbar
Oluwafemi Sule's solution almost works, but it plots the matrix into the same figure as the lines. Here a solution that opens a second figure, does the imshow call on that second figure, uses the result to draw the colorbar in the first figure, and then closes the second figure before calling plt.show():
import matplotlib
from matplotlib import pyplot as plt
from matplotlib import gridspec
import numpy as np
cmap = matplotlib.cm.get_cmap('viridis')
g1 = gridspec.GridSpec(1, 1)
f0, ((ax0)) = plt.subplots(1, 1)
f1, ((ax1)) = plt.subplots(1, 1)
for i in np.linspace(0,1,11):
x = [-1,0,1]
y = [i,i,i]
rgba = cmap(i)
ax0.plot(x,y,color=rgba)
data = np.linspace(0,1,100).reshape((10,10))
image = ax1.imshow(data)
f0.colorbar(image)
plt.close(f1)
plt.show()
The result looks like this:

How to hide contour lines / data from a specific area on Basemap

I am working some meteorological data to plot contour lines on a basemap. The full working example code I have done earlier is here How to remove/omit smaller contour lines using matplotlib. All works fine and I don’t complain with the contour plot. However there is a special case that I have to hide all contour lines over a specific region (irregular lat & lon) on a Basemap.
The only possible solution I can think of is to draw a ploygon lines over a desired region and fill with the color of same as Basemap. After lot of search I found this link How to draw rectangles on a Basemap (code below)
from mpl_toolkits.basemap import Basemap
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Polygon
def draw_screen_poly( lats, lons, m):
x, y = m( lons, lats )
xy = zip(x,y)
poly = Polygon( xy, facecolor='red', alpha=0.4 )
plt.gca().add_patch(poly)
lats = [ -30, 30, 30, -30 ]
lons = [ -50, -50, 50, 50 ]
m = Basemap(projection='sinu',lon_0=0)
m.drawcoastlines()
m.drawmapboundary()
draw_screen_poly( lats, lons, m )
plt.show()
It seems to work partially. However, I want to draw a region which is irregular.
Any solution is appreciated.
Edit: 1
I have understood where the problem is. It seems that any colour (facecolor) filled within the polygon region does not make it hide anything below. Always it is transparent only, irrespective of alpha value used or not. To illustrate the problem, I have cropped the image which has all three regions ie. contour, basemap region and polygon region. Polygon region is filled with red colour but as you can see, the contour lines are always visible. The particular line I have used in the above code is :-
poly = Polygon(xy, facecolor='red', edgecolor='b')
Therefore the problem is not with the code above. It seem the problem with the polygon fill. But still no solution for this issue. The resulting image (cropped image) is below (See my 2nd edit below the attached image):-
Edit 2:
Taking clue from this http://matplotlib.1069221.n5.nabble.com/Clipping-a-plot-inside-a-polygon-td41950.html which has the similar requirement of mine, I am able to remove some the data. However, the removed data is only from outside of polygon region instead of within. Here is the code I have taken clue from:-
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import RegularPolygon
data = np.arange(100).reshape(10, 10)
fig = plt.figure()
ax = fig.add_subplot(111)
ax.contourf(data)
poly = RegularPolygon([ 0.5, 0.5], 6, 0.4, fc='none',
ec='k', transform=ax.transAxes)
for artist in ax.get_children():
artist.set_clip_path(poly)
Now my question is that what command is used for removing the data within the polygon region?
Didn't noticed there was a claim on this so I might just give the solution already proposed here. You can tinker with the zorder to hide stuff behind your polygon:
import matplotlib
import matplotlib.mlab as mlab
import matplotlib.pyplot as plt
matplotlib.rcParams['xtick.direction'] = 'out'
matplotlib.rcParams['ytick.direction'] = 'out'
delta = 0.025
x = np.arange(-3.0, 3.0, delta)
y = np.arange(-2.0, 2.0, delta)
X, Y = np.meshgrid(x, y)
Z1 = mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
Z2 = mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
# difference of Gaussians
Z = 10.0 * (Z2 - Z1)
# Create a simple contour plot with labels using default colors. The
# inline argument to clabel will control whether the labels are draw
# over the line segments of the contour, removing the lines beneath
# the label
fig = plt.figure()
ax = fig.add_subplot(111)
CS = plt.contour(X, Y, Z,zorder=3)
plt.clabel(CS, inline=1, fontsize=10)
plt.title('Simplest default with labels')
rect1 = matplotlib.patches.Rectangle((0,0), 2, 1, color='white',zorder=5)
ax.add_patch(rect1)
plt.show()
, the result is:

matplotlib - Draw a heatmap/pixelmap with ability to edit individual pixel colours (different colormaps by row)

I'm trying to draw a heat map/pixelmap representation of a matrix using matplotlib. I currently have the following code which gives me the pixelmap as required (adapted from Heatmap in matplotlib with pcolor?):
import matplotlib.pyplot as plt
import numpy as np
column_labels = list('ABCD')
row_labels = list('0123')
data = np.array([[0,1,2,0],
[1,0,1,1],
[1,2,0,0],
[0,0,0,1]])
fig, ax = plt.subplots()
heatmap = ax.pcolor(data, cmap=plt.cm.Blues)
# put the major ticks at the middle of each cell
ax.set_xticks(np.arange(data.shape[0])+0.5, minor=False)
ax.set_yticks(np.arange(data.shape[1])+0.5, minor=False)
# want a more natural, table-like display
ax.invert_yaxis()
ax.xaxis.tick_top()
ax.set_xticklabels(row_labels, minor=False)
ax.set_yticklabels(column_labels, minor=False)
ax.yaxis.grid(True, which='minor', linestyle='-', color='k', linewidth = 0.3, alpha = 0.5)
ax.xaxis.grid(True, which='minor', linestyle='-', color='k', linewidth = 0.3, alpha = 0.5)
# Set the location of the minor ticks to the edge of pixels for the x grid
minor_locator = AutoMinorLocator(2)
ax.xaxis.set_minor_locator(minor_locator)
# Lets turn off the actual minor tick marks though
for tickmark in ax.xaxis.get_minor_ticks():
tickmark.tick1On = tickmark.tick2On = False
# Set the location of the minor ticks to the edge of pixels for the y grid
minor_locator = AutoMinorLocator(2)
ax.yaxis.set_minor_locator(minor_locator)
# Lets turn off the actual minor tick marks though
for tickmark in ax.yaxis.get_minor_ticks():
tickmark.tick1On = tickmark.tick2On = False
plt.show()
Which gives the following plot:
However I would like to extend this such that on mouse click I can highlight a 'row' in the pixelmap in green, e.g. if the user selected row 'C' I would have (I appreciate the green highlight is not clear for pixels with a 0 value):
I know how to deal with the mouse events but I'm not sure how to modify the colour of a single row in the pixelmap. It would also help if I could set labels for individual pixels of the pixel map to be retrieved on mouse click, as opposed to using the mouse x/y location to index the label lists.
I have figured out my own problem, with help from this question:
Plotting of 2D data : heatmap with different colormaps.
The code is below and the comments should explain the steps taken clearly.
import matplotlib.pyplot as plt
import numpy as np
from numpy.ma import masked_array
import matplotlib.cm as cm
from matplotlib.ticker import AutoMinorLocator
column_labels = list('ABCD')
row_labels = list('0123')
data = np.array([[0,1,2,0],
[1,0,1,1],
[1,2,0,0],
[0,0,0,1]])
fig, ax = plt.subplots()
# List to keep track of handles for each pixel row
pixelrows = []
# Lets create a normalizer for the whole data array
norm = plt.Normalize(vmin = np.min(data), vmax = np.max(data))
# Let's loop through and plot each pixel row
for i, row in enumerate(data):
# First create a mask to ignore all others rows than the current
zerosarray = np.ones_like(data)
zerosarray[i, :] = 0
plotarray = masked_array(data, mask=zerosarray)
# If we are not on the 3rd row down let's use the red colormap
if i != 2:
pixelrows.append(ax.matshow(plotarray, norm=norm, cmap=cm.Reds))
# Otherwise if we are at the 3rd row use the green colormap
else:
pixelrows.append(ax.matshow(plotarray, norm=norm, cmap=cm.Greens))
# put the major ticks at the middle of each cell
ax.set_xticks(np.arange(data.shape[0]), minor=False)
ax.set_yticks(np.arange(data.shape[1]), minor=False)
# want a more natural, table-like display
ax.xaxis.tick_top()
ax.set_xticklabels(row_labels, minor=False)
ax.set_yticklabels(column_labels, minor=False)
ax.yaxis.grid(True, which='minor', linestyle='-', color='k', linewidth = 0.3, alpha = 0.5)
ax.xaxis.grid(True, which='minor', linestyle='-', color='k', linewidth = 0.3, alpha = 0.5)
# Set the location of the minor ticks to the edge of pixels for the x grid
minor_locator = AutoMinorLocator(2)
ax.xaxis.set_minor_locator(minor_locator)
# Lets turn of the actual minor tick marks though
for tickmark in ax.xaxis.get_minor_ticks():
tickmark.tick1On = tickmark.tick2On = False
# Set the location of the minor ticks to the edge of pixels for the y grid
minor_locator = AutoMinorLocator(2)
ax.yaxis.set_minor_locator(minor_locator)
# Lets turn of the actual minor tick marks though
for tickmark in ax.yaxis.get_minor_ticks():
tickmark.tick1On = tickmark.tick2On = False
plt.show()