This question already has answers here:
Maintaining one colorbar for maptlotlib FuncAnimation
(3 answers)
Closed 4 years ago.
I want to make gif animation with FuncAnimation of matplotlib.
Here is the code.
However the output image contains multiple colorbars like this(link)
Does anyone know how to fix this problem ?
If I set
plt.colorbar()
just after or before
ani = animation.FuncAnimation(fig, update, interval=100 ,frames=400)
, it returns
RuntimeError: No mappable was found to use for colorbar creation. First define a mappable such as an image (with imshow) or a contour set (with contourf).
If I subsitute plt.colorbar() with if(k==0): plt.colorbar(), image contains same 2 colorbars.
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from PIL import Image
import moviepy.editor as edit
from mpl_toolkits.axes_grid1 import make_axes_locatable
def update(k):
plt.cla() # clear axis
#updating Val...
plt.contourf(X0, Y0, Val, cmap = "bwr")
plt.colorbar()
plt.axes().set_aspect("equal")
plt.title("title-name")
fig = plt.figure()
ani = animation.FuncAnimation(fig, update, interval=100 ,frames=400)
ani.save("out.gif", writer='imagemagick')
I add
plt.colorbar(plt.contourf(X0,Y0,charge,cmap="bwr",levels=np.linspace(-1,1,100,endpoint=True)))
just after
fig=plt.figure()
and it works successfully.
This method is adopted from Mr. ImportanceOfBeingErnest's answer(Maintaining one colorbar for maptlotlib FuncAnimation)
Related
I am trying to create a real-time colour map. I want to continuously change slightly the RGB values of some elements in the matrix to make up my colour map. I read data from an excel file and a part of my data looks like this
Then I want to show the colour change in my colour map in one figure like a video. I tried this code:
df=pd.read_excel(r"G:\3Y_individualProject\Crop_color_data.xlsx", usecols="C:E")
color_data_2d=np.array(df.iloc[0:101])
color_data_1d=np.reshape(color_data_2d,(300))
color_data=color_data_1d.reshape(5,20,3)
for x in range(5):
fig, ax = plt.subplots()
ax.imshow(color_data)
ax.set_aspect("equal")
plt.pause(0.05)
for i in range(3):
color_data[0,1,i]=color_data[0,1,i]+0.1
color_data[1,1,i]=color_data[1,1,i]+0.2
color_data[2,1,i]=color_data[1,1,i]+0.25
print(color_data)
But it plots many different figures instead of showing them in a figure as I expected. I've also just tried to learn and use matplotlib.animation. I have tried the code below:
from matplotlib import pyplot as plt
import pandas as pd
import numpy as np
from matplotlib import cm
from matplotlib.animation import FuncAnimation
from matplotlib.colors import ListedColormap, LinearSegmentedColormap
import itertools
def changeColor(x):
fig, ax = plt.subplots()
ax.imshow(color_data)
ax.set_aspect("equal")
for i in range(3):
color_data[0,1,i]=color_data[0,1,i]+0.1
color_data[1,1,i]=color_data[1,1,i]+0.2
color_data[2,1,i]=color_data[1,1,i]+0.25
results=FuncAnimation(plt.gcf(), changeColor, interval=5)
plt.tight_layout()
plt.show()
But with that code, my figure doesn't even display anything. As said I am quite new to matplotlib.animation so can anyone show me how to use matplotlib.animation or any other way to plot a real-time color map in my case, please? Thank you so much!
This question already has answers here:
matplotlib Legend Markers Only Once
(2 answers)
Closed 3 years ago.
I am trying to make a costum legend in a Basemap plot so was considering using Line2D. It works ok, but I want that the legend only consist of one marker and no line, instead of a line between two markers (see below).
Here is the most important part of the code I use to plot this costum legend:
from matplotlib.lines import Line2D
import matplotlib.pyplot as plt
fig,ax = plt.subplots()
legend_elements = [Line2D([0],[0],marker='o',markersize=10,color='green',label='Label1'),
Line2D([0],[0],marker='s',markersize=12,color='red',label='Label2')]
ax.legend(handles=legend_elements,loc=2)
plt.show()
use numpoints= in the legend() call to control the number of points shown for a Line2D object. A line is still shown though. If you want to remove the line, set its width to 0 when creating the Line2D.
from matplotlib.lines import Line2D
import matplotlib.pyplot as plt
fig,ax = plt.subplots()
legend_elements = [Line2D([0],[0],marker='o',markersize=10,color='green',label='Label1', lw=0),
Line2D([0],[0],marker='s',markersize=12,color='red',label='Label2', lw=0)]
ax.legend(handles=legend_elements,loc=2, numpoints=1)
plt.show()
This question already has an answer here:
adjusting subplot with a colorbar
(1 answer)
Closed 3 years ago.
I am trying to use Matplotlib to plot a time series along with its spectrogram and its associated colorbar.
Below is a MCVE:
import numpy as np
import matplotlib.pyplot as plt
import scipy.signal as scignal
import random
array=np.random.random(10000)
t,f,Sxx=scignal.spectrogram(array,fs=100)
plt.subplot(211)
plt.plot(array)
plt.subplot(212)
plt.pcolormesh(Sxx)
plt.colorbar()
This code yields the following figure:
However, I would like both subplots to have the same size:
I thought of changing the orientation of the colorbar using plt.colorbar(orientation='horizontal') but I am not satisfied with the result as the subplots end up not having the same height.
Any help will be appreciated!
The reason this happens is that plt.colorbar creates a new Axes object, which "steals" space from the lower Axes (this is the reason making a horizontal colourbar also affects the two original plots).
There are a few ways to work around this; one is to create a Figure with four Axes, allocate most of the space to the left ones, and just make one invisible:
import numpy as np
import matplotlib.pyplot as plt
import scipy.signal as scignal
import random
array = np.random.random(10000)
t, f, Sxx = scignal.spectrogram(array,fs=100)
fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(5, 6), gridspec_kw={'width_ratios': [19, 1]})
(ax1, blank), (ax2, ax_cb) = axes
blank.set_visible(False)
ax1.plot(array)
m = ax2.pcolormesh(Sxx)
fig.colorbar(m, cax=ax_cb)
I am trying to make a figure with 4 subplots of windrose, But I realised that the windrose only have axis like this:ax = WindroseAxes.from_ax() So, how can I draw a subplots with windrose?
There are two solutions:
(a) creating axes from rectangles
First of all there is a similar question already here: How to add specific axes to matplotlib subplot?
There, the solution is to create a rectangle rect with coordinates of the new subplot axes within the figure and then call ax = WindroseAxes(fig, rect)
An easier to understand example would be
from windrose import WindroseAxes
from matplotlib import pyplot as plt
import numpy as np
ws = np.random.random(500) * 6
wd = np.random.random(500) * 360
fig=plt.figure()
rect=[0.5,0.5,0.4,0.4]
wa=WindroseAxes(fig, rect)
fig.add_axes(wa)
wa.bar(wd, ws, normed=True, opening=0.8, edgecolor='white')
plt.show()
(b) adding a projection
Now it may be rather annoying to create this rectangle and it would be much better to be able to use the matplotlib subplot functionality.
One suggestion that has been made here is to register the WindroseAxes as a projection into matplotlib. To this end, you need to edit the file windrose.py in the site-packages/windrose as follows:
Include an import from matplotlib.projections import register_projection at the beginning of the file.
Then add a name variable :
class WindroseAxes(PolarAxes):
name = 'windrose'
...
Finally, at the end of windrose.py, you add:
register_projection(WindroseAxes)
Once that is done, you can easily create your windrose axes using the projection argument to the matplotlib axes:
from matplotlib import pyplot as plt
import windrose
import matplotlib.cm as cm
import numpy as np
ws = np.random.random(500) * 6
wd = np.random.random(500) * 360
fig = plt.figure()
ax = fig.add_subplot(221, projection="windrose")
ax.contourf(wd, ws, bins=np.arange(0, 8, 1), cmap=cm.hot)
ax.legend(bbox_to_anchor=(1.02, 0))
plt.show()
To make the subplots on the same scale (e.g. for monthly data), simply add the rmax argument in the add_subplot function. For me worked:
ax = fig.add_subplot(nrows, ncols, month, projection="windrose", rmax = 50)
Inspired by the accepted answer (by ImportanceOfBeingErnest) I used the following to add a windrose to an existing subplots instance:
import matplotlib as plt
from windrose import WindroseAxes
fig, axes = plt.subplots(1,2)
rect=axes[0,1].get_position()
wax=WindroseAxes(fig, rect)
wax.bar(wd, ws)
axes[0,1].axis('off')
This question already has answers here:
How to change legend fontsize with matplotlib.pyplot
(9 answers)
Closed 6 years ago.
Here is my code
import os,sys
import Image
import matplotlib.pyplot as plt
from matplotlib.pyplot import *
from matplotlib.font_manager import FontProperties
jpgfile = Image.open("t002.jpg")
# Set up the figure and axes.
fig = plt.figure(figsize=(18,10)) # ...or whatever size you want.
ax = fig.add_subplot(111)
ax.legend(fontsize=18)
# Draw things.
plt.imshow(jpgfile) # Unlike plot and scatter, not a method on ax.
ax.set_xlabel('normalized resistivities')
ax.set_ylabel('normalized velocities')
ax.set_xticks([]); ax.set_yticks([])
# Save and show.
plt.savefig("fig.jpg")
plt.show()
But
/usr/local/lib/python2.7/dist-packages/matplotlib/axes/_axes.py:519: UserWarning: No labelled objects found. Use label='...' kwarg on individual plots
How should I set the labels?
Legend fonts are customized by providing a dict of font property-value pairs to the 'prop' kwarg:
ax.legend(prop=dict(size=18))