Python Multiprocessing yields different results in matplotlib - python

I run the following code and I get two plots as I expected. If I change the last three lines in the function multiP() to include multiprocessing, I only get the dimensions of the plot.
import matplotlib.pyplot as plt
import numpy as np
import multiprocessing
multiprocessing.freeze_support() # <- may be required on windows
def plot(g, x, y):
fig, ax = plt.subplots()
ax.plot(x, y)
plt.legend()
plt.show()
print(g)
def multiP():
for i in range(2):
g = "TEST"
x = np.arange(0.0, 5.0, 0.01)
y = 1 + np.sin(2 * np.pi * x)
#p = multiprocessing.Process(target=plot, args=(g, x, y))
#p.start()
plot(g, x, y)
if __name__ == "__main__":
multiP()
What am I missing?

Related

Recenter plot after set_xdata and set_ydata

I can use the set_xdata and set_ydata functions to update an existing matplotlib plot. But after updating I want to recenter the plot so that all the points fall into the "view" of the plot.
In the below example, the y data keeps getting bigger but the zoom level of the plot remains same so the data points quickly get out of the scope.
import time
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
y = np.sin(x)
plt.ion()
figure, ax = plt.subplots(figsize=(10, 8))
(line1,) = ax.plot(x, y)
plt.xlabel("X-axis")
plt.ylabel("Y-axis")
for i in range(1000):
new_y = np.sin(x - 0.5 * i) * i
line1.set_xdata(x)
line1.set_ydata(new_y)
figure.canvas.draw()
figure.canvas.flush_events()
time.sleep(0.1)
Adding ax.relim() and ax.autoscale() fixes the issue
import time
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
y = np.sin(x)
plt.ion()
ax: plt.Axes
figure, ax = plt.subplots(figsize=(10, 8))
(line1,) = ax.plot(x, y)
ax.autoscale(True)
plt.xlabel("X-axis")
plt.ylabel("Y-axis")
for i in range(1000):
new_y = np.sin(x - 0.5 * i) * i
line1.set_xdata(x)
line1.set_ydata(new_y)
# Rescale axes limits
ax.relim()
ax.autoscale()
figure.canvas.draw()
figure.canvas.flush_events()
time.sleep(0.1)
np.sin(x - 0.5 * i) has multiplied by i, which can be 1000. One alternative is to make the y-axis have a limit greater than 1000. So, you can include plt.ylim([-1100,1100]):
import time
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
y = np.sin(x)
plt.ion()
figure, ax = plt.subplots(figsize=(10, 8))
(line1,) = ax.plot(x, y)
plt.xlabel("X-axis")
plt.ylabel("Y-axis")
plt.ylim([-1100,1100])
for i in range(1000):
new_y = np.sin(x - 0.5 * i) * i
line1.set_xdata(x)
line1.set_ydata(new_y)
figure.canvas.draw()
figure.canvas.flush_events()
time.sleep(0.1)

How to normalize colorbar in Python?

I want to adjust colobar scale from my current figure1 to the desired figure2 !!
My colorbar scale range is -1 to 1, but I want it in exponential form and for that I tried levels = np.linspace(-100e-2,100e-2) as well, but it also doesn't give the desired scale2
import xarray as xr
import numpy as np
import matplotlib.pyplot as plt
ds = xr.open_dataset('PL_Era_Tkt.nc')
wp = ds.w.mean(dim=['longitude','latitude']).plot.contourf(x='time',cmap='RdBu',add_colorbar=False,extend='both')
wpcb = plt.colorbar(wp)
wpcb.set_label(label='Pa.s${^{-1}}$',size=13)
plt.gca().invert_yaxis()
plt.title('Vertical Velocity',size=15)
My current scale
My desired scale
Since the data is not presented, I added normalized color bars with the data from the graph sample here. I think the color bar scales will also be in log format with this setup. Please note that the data used is not large, so I have not been able to confirm this.
%matplotlib inline
import matplotlib.pyplot as plt
import matplotlib as mpl
import matplotlib.ticker as ticker
import numpy as np
plt.style.use('seaborn-white')
def f(x, y):
return np.sin(x) ** 10 + np.cos(10 + y * x) * np.cos(x)
x = np.linspace(0, 5, 50)
y = np.linspace(0, 5, 40)
X, Y = np.meshgrid(x, y)
Z = f(X, Y)
fig, ax = plt.subplots()
ax.contourf(X, Y, Z, 20, cmap='RdGy')
cmap = mpl.cm.RdGy
norm = mpl.colors.Normalize(vmin=-1, vmax=1.0)
fig.colorbar(mpl.cm.ScalarMappable(norm=norm, cmap=cmap),
ax=ax, orientation='vertical', label='Some Units', extend='both', ticks=ticker.LogLocator())
plt.show()

How to generate an animation with images in subplots (matplotlib)

Is possible to animate pairs of images in a jupyter notebook?
With two lists of images:
greys = io.imread_collection(path_greys)
grdTru= io.imread_collection(path_grdTru)
The following naïve code fails to generate an animation:
for idx in range(1,900):
plt.subplot(121)
plt.imshow(greys[idx], interpolation='nearest', cmap=plt.cm.gray)
plt.subplot(122)
plt.imshow(grdTru[idx], interpolation='nearest', cmap=plt.cm.,vmin=0,vmax=3)
plt.show()
(It generates a list of subplots)
By the way,the example found in matplotlib doc failed if pasted in a notebook.
In order to make the example work in a jupyter notebook you need to include the
%matplotlib notebook
magic command.
import numpy as np
%matplotlib notebook
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig = plt.figure()
def f(x, y):
return np.sin(x) + np.cos(y)
x = np.linspace(0, 2 * np.pi, 120)
y = np.linspace(0, 2 * np.pi, 100).reshape(-1, 1)
im = plt.imshow(f(x, y), animated=True)
def updatefig(*args):
global x, y
x += np.pi / 15.
y += np.pi / 20.
im.set_array(f(x, y))
return im,
ani = animation.FuncAnimation(fig, updatefig, interval=50, blit=True)
plt.show()
You can then easily adapt it to your list of images.
From matplotlib version 2.1 on you also have the option to create a JavaScript animation inline.
from IPython.display import HTML
HTML(ani.to_jshtml())
Complete example:
import numpy as np
%matplotlib inline
import matplotlib.pyplot as plt
import matplotlib.animation as animation
def f(x, y):
return np.sin(x) + np.cos(y)
x = np.linspace(0, 2 * np.pi, 120)
y = np.linspace(0, 2 * np.pi, 100).reshape(-1, 1)
im = plt.imshow(f(x, y), animated=True);
def updatefig(*args):
global x, y
x += np.pi / 15.
y += np.pi / 20.
im.set_array(f(x, y))
return im,
ani = animation.FuncAnimation(fig, updatefig, interval=50, blit=True)
from IPython.display import HTML
HTML(ani.to_jshtml())

How to set axis ticks in multiples of pi (Python) (matplotlib)

I'd like to make a plot in Python and have x range display ticks in multiples of pi.
Is there a good way to do this, not manually?
I'm thinking of using matplotlib, but other options are fine.
EDIT 3: EL_DON's solution worked for me like this:
import matplotlib.ticker as tck
import matplotlib.pyplot as plt
import numpy as np
f,ax=plt.subplots(figsize=(20,10))
x=np.linspace(-10*np.pi, 10*np.pi,1000)
y=np.sin(x)
ax.plot(x/np.pi,y)
ax.xaxis.set_major_formatter(tck.FormatStrFormatter('%g $\pi$'))
ax.xaxis.set_major_locator(tck.MultipleLocator(base=1.0))
plt.style.use("ggplot")
plt.show()
giving:
EDIT 2 (solved in EDIT 3!): EL_DON's answer doesn't seem to work right for me:
import matplotlib.ticker as tck
import matplotlib.pyplot as plt
import numpy as np
f,ax=plt.subplots(figsize=(20,10))
x=np.linspace(-10*np.pi, 10*np.pi)
y=np.sin(x)
ax.plot(x/np.pi,y)
ax.xaxis.set_major_formatter(tck.FormatStrFormatter('%g $\pi$'))
ax.xaxis.set_major_locator(tck.MultipleLocator(base=1.0))
plt.style.use("ggplot")
plt.show()
gives me
which really doesn't look right
This is inspired by Python Data Science Handbook, although Sage attempts to do without explicit parameters.
EDIT: I've generalized this to allow you to supply as optional parameters the denominator, the value of the unit, and the LaTeX label for the unit. A class definition is included if you find that helpful.
import numpy as np
import matplotlib.pyplot as plt
def multiple_formatter(denominator=2, number=np.pi, latex='\pi'):
def gcd(a, b):
while b:
a, b = b, a%b
return a
def _multiple_formatter(x, pos):
den = denominator
num = np.int(np.rint(den*x/number))
com = gcd(num,den)
(num,den) = (int(num/com),int(den/com))
if den==1:
if num==0:
return r'$0$'
if num==1:
return r'$%s$'%latex
elif num==-1:
return r'$-%s$'%latex
else:
return r'$%s%s$'%(num,latex)
else:
if num==1:
return r'$\frac{%s}{%s}$'%(latex,den)
elif num==-1:
return r'$\frac{-%s}{%s}$'%(latex,den)
else:
return r'$\frac{%s%s}{%s}$'%(num,latex,den)
return _multiple_formatter
​
class Multiple:
def __init__(self, denominator=2, number=np.pi, latex='\pi'):
self.denominator = denominator
self.number = number
self.latex = latex
​
def locator(self):
return plt.MultipleLocator(self.number / self.denominator)
​
def formatter(self):
return plt.FuncFormatter(multiple_formatter(self.denominator, self.number, self.latex))
This can be used very simply, without any parameters:
x = np.linspace(-np.pi, 3*np.pi,500)
plt.plot(x, np.cos(x))
plt.title(r'Multiples of $\pi$')
ax = plt.gca()
ax.grid(True)
ax.set_aspect(1.0)
ax.axhline(0, color='black', lw=2)
ax.axvline(0, color='black', lw=2)
ax.xaxis.set_major_locator(plt.MultipleLocator(np.pi / 2))
ax.xaxis.set_minor_locator(plt.MultipleLocator(np.pi / 12))
ax.xaxis.set_major_formatter(plt.FuncFormatter(multiple_formatter()))
plt.show()
Or it can be used in a more sophisticated way:
tau = np.pi*2
den = 60
major = Multiple(den, tau, r'\tau')
minor = Multiple(den*4, tau, r'\tau')
x = np.linspace(-tau/60, tau*8/60,500)
plt.plot(x, np.exp(-x)*np.cos(60*x))
plt.title(r'Multiples of $\tau$')
ax = plt.gca()
ax.grid(True)
ax.axhline(0, color='black', lw=2)
ax.axvline(0, color='black', lw=2)
ax.xaxis.set_major_locator(major.locator())
ax.xaxis.set_minor_locator(minor.locator())
ax.xaxis.set_major_formatter(major.formatter())
plt.show()
f,ax=plt.subplots(1)
x=linspace(0,3*pi,1001)
y=sin(x)
ax.plot(x/pi,y)
ax.xaxis.set_major_formatter(FormatStrFormatter('%g $\pi$'))
ax.xaxis.set_major_locator(matplotlib.ticker.MultipleLocator(base=1.0))
I used info from these answers:
https://stackoverflow.com/a/19972993/6605826
https://stackoverflow.com/a/29188910/6605826
If you want to avoid dividing x by pi in the plot command, this answer can be adjusted slightly using a FuncFormatter instead of a FormatStrFormatter:
import numpy as np
from matplotlib import pyplot as plt
from matplotlib.ticker import FuncFormatter, MultipleLocator
fig,ax = plt.subplots()
x = np.linspace(-5*np.pi,5*np.pi,100)
y = np.sin(x)/x
ax.plot(x,y)
#ax.xaxis.set_major_formatter(FormatStrFormatter('%g $\pi$'))
ax.xaxis.set_major_formatter(FuncFormatter(
lambda val,pos: '{:.0g}$\pi$'.format(val/np.pi) if val !=0 else '0'
))
ax.xaxis.set_major_locator(MultipleLocator(base=np.pi))
plt.show()
gives the following image:
Solution for pi fractions:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import rc
rc('text', usetex=True) # Use LaTeX font
import seaborn as sns
sns.set(color_codes=True)
Plot your function:
fig, ax = plt.subplots(1)
x = np.linspace(0, 2*np.pi, 1001)
y = np.cos(x)
ax.plot(x, y)
plt.xlim(0, 2*np.pi)
Modify the range of the grid so that it corresponds to the pi values:
ax.set_xticks(np.arange(0, 2*np.pi+0.01, np.pi/4))
Change axis labels:
labels = ['$0$', r'$\pi/4$', r'$\pi/2$', r'$3\pi/4$', r'$\pi$',
r'$5\pi/4$', r'$3\pi/2$', r'$7\pi/4$', r'$2\pi$']
ax.set_xticklabels(labels)
import numpy as np
import matplotlib.pyplot as plt
x=np.linspace(0,3*np.pi,1001)
plt.ylim(-3,3)
plt.xlim(0, 4*np.pi)
plt.plot(x, np.sin(x))
tick_pos= [0, np.pi , 2*np.pi]
labels = ['0', '$\pi$', '$2\pi$']
plt.xticks(tick_pos, labels)
I created a PyPi Package that creates formatter and locator instances like Scott Centoni's answer.
"""Show a simple example of using MultiplePi."""
import matplotlib.pyplot as plt
import numpy as np
from matplot_fmt_pi import MultiplePi
fig = plt.figure(figsize=(4*np.pi, 2.4))
axes = fig.add_subplot(111)
x = np.linspace(-2*np.pi, 2*np.pi, 512)
axes.plot(x, np.sin(x))
axes.grid(True)
axes.axhline(0, color='black', lw=2)
axes.axvline(0, color='black', lw=2)
axes.set_title("MultiplePi formatting")
pi_manager = MultiplePi(2)
axes.xaxis.set_major_locator(pi_manager.locator())
axes.xaxis.set_major_formatter(pi_manager.formatter())
plt.tight_layout()
plt.savefig("./pi_graph.png", dpi=120)
Here is a version converting floats into fractions of pi. Just use your favorite formatter, then convert the float values it produced into pi fractions using function convert_to_pi_fractions(ax, axis='x'), specifying which spine must be converted (or both). You get that:
from that:
from fractions import Fraction
import numpy as np
from numpy import pi
import matplotlib.pyplot as plt
import matplotlib.ticker as tck
def convert_to_pi_fractions(ax, axis='x'):
assert axis in ('x', 'y', 'both')
if axis in ('x', 'both'):
vals, labels = process_ticks(ax.get_xticks())
if len(vals) > 0: ax.set_xticks(vals, labels)
if axis in ('y', 'both'):
vals, labels = process_ticks(ax.get_yticks())
if len(vals) > 0: ax.set_yticks(vals, labels)
def process_ticks(ticks):
vals = []
labels = []
for tick in ticks:
frac = Fraction(tick/pi)
if frac.numerator < 10 and frac.numerator < 10:
if frac.numerator == 0: label = '0'
elif frac.denominator == 1:
if frac.numerator == 1: label = '$\pi$'
elif frac.numerator == -1: label = '-$\pi$'
else: label = f'{frac.numerator} $\pi$'
elif frac.numerator == -1: label = f'-$\pi$/{frac.denominator}'
elif frac.numerator == 1: label = f'$\pi$/{frac.denominator}'
else: label = f'{frac.numerator}$\pi$/{frac.denominator}'
vals.append(tick)
labels.append(label)
return vals, labels
# Generate data
w_fr = np.linspace(-0.5*pi, 3.1*pi, 60)
H_func = lambda h, w: np.sum(h * np.exp(-1j * w[:, None] * np.arange(len(h))), axis=1)
r_fr = H_func([1, -1], w_fr)
# Prepare figure
fig, ax = plt.subplots(figsize=(10, 4), layout='constrained')
ax.grid()
ax.set_title('Frequency response')
ax.set_xlabel('normalized radian frequency')
ax.xaxis.set_major_locator(tck.MultipleLocator(base=pi/2))
g_c, p_c = 'C0', 'C1'
# Plot gain
ax.set_ylabel('amplitude', c=g_c)
ax.plot(w_fr, abs(r_fr), label='gain', c=g_c)
ax.tick_params(axis='y', labelcolor=g_c)
# Plot phase shift
ax1 = ax.twinx()
ax1.set_ylabel('phase shift', c=p_c)
ax1.yaxis.set_major_locator(tck.MultipleLocator(base=pi/4))
ax1.plot(w_fr, np.unwrap(np.angle(r_fr), period=2*pi), label='phase shift', c=p_c)
ax1.tick_params(axis='y', labelcolor=p_c)
# Convert floats to pi fractions
convert_to_pi_fractions(ax)
convert_to_pi_fractions(ax1, axis='y')

Python animate contour plot for function generated in for loops

I have a three-variable function myfunc that is generated inside three for loops. I want to draw a contour plot of y vs x and animate this for different times t. However, I've looked at the various matplotlib examples on the webpage, and am still unsure of how to do this.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import animation
def myfunc(x,y,t):
w = 0.5*x + y + 4*np.sin(1.8*t)
return w
xlist = np.linspace(0,10,10)
ylist = np.linspace(-1,1,10)
tlist = np.linspace(0,50,50)
plt.figure()
for t in tlist:
for x in xlist:
for y in ylist:
w = myfunc(x,y,t)
w_vec = np.array(w)
w_contour = w_vec.reshape((xlist.size, ylist.size))
w_plot = plt.contourf(ylist,xlist,w_contour)
plt.xlabel('x', fontsize=16)
plt.ylabel('y', fontsize=16)
plt.show()
Edit: I quite like the look of dynamic_image2.py in this tutorial. This seems to get things moving, but the axes are wrong:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig = plt.figure()
def f(x,y,t):
return 0.5*x + np.sin(y) + 4*np.sin(1.8*t)
x = np.linspace(0, 10, 10)
y = np.linspace(-1, 1, 10).reshape(-1, 1)
tlist = np.linspace(0,50,50)
ims = []
for t in tlist:
x += np.pi / 15.0
y += np.pi / 20.0
im = plt.imshow(f(x,y,t))
ims.append([im])
ani = animation.ArtistAnimation(fig, ims, interval=20, blit=True,
repeat_delay=1000)
plt.show()

Categories