Adding plots to different figures using matplotlib - python

for a particular purpose, I want to plot 2-3 different figures using matplotlib and add different graphs to each of these figures. My particular requirement is complex and hard to explain, so I will try to explain with a simpler example.
For example, imagine I have a list of signals called
[signal_1,signal_2,signal_3, .... , signal _40]
where each 'signal_XXX' represents a numpy-array, some of length 5000 and other length 10,000.
I want to plot all these signals in 2 different graphs, depending on their length.
import matplotlib.pyplot as plt
my_signals = [ signal_1,signal_2,....,signal_40]
fig_5000 = plt.figure(1)
fig_10000 = plt.figure(2)
for signal_i in my_signals :
if len(signal_i) == 5000 :
fig_5000.plot(signal_i)
if len(signal_i) == 10000 :
fig_10000.plot(signal_i)
# now I want to individually show these 2 figures
fig_5000.show()
" do something else here "
fig_10000.show()
Obviously the code which I wrote will not work, also on the last part if I use
plt.show() both graphs will show at the same time, which I don't want.
Is there any way to do the stuff which I want to do using matplotlib ? or should I try something else?
EDIT
I include a 'working' code , with suggestion from Diziet Asahi,
import numpy
import matplotlib.pyplot as plt
my_signals = []
for i in range (0,25):
if i//2 == 0 :
my_signals.append( numpy.random.rand(100))
if i//2 == 1 :
my_signals.append( numpy.random.rand(200))
"""numpy.random.rand craetes an array with random numbers of the given shape.
now we have a list of 50 arrays with 100 and 200 lengths """
fig_100 = plt.figure(1)
ax100 = fig_100.add_subplot(111)
plt.title(" length = 100")
fig_200 = plt.figure(2)
plt.title(" length = 200")
ax200 = fig_200.add_subplot(111)
for arrayzz in my_signals :
if len(arrayzz) == 100 :
ax100.plot(arrayzz)
if len(arrayzz) == 200:
ax200.plot(arrayzz)
plt.show()
This fixes the first part of the earlier problem. Still, I can't show them individually.

In addition to creating figures you also need to create axes. You don't say if you want all your signals to be on the same axes, but generally this should do the trick:
import matplotlib.pyplot as plt
my_signals = [ signal_1,signal_2,....,signal_40]
fig_5000 = plt.figure(1)
ax_5000 = fig_5000.add_subplot(111)
fig_10000 = plt.figure(2)
ax_10000 = fig_10000.add_subplot(111)
for signal_i in my_signals :
if len(signal_i) == 5000 :
ax_5000.plot(signal_i)
if len(signal_i) == 10000 :
ax_10000.plot(signal_i)
plt.show()

There is no good solution for this currently. plt.show() shows all open pyplot figures. You can of course close anyThe problem is essentially the same as this one, and of course writing your own GUI for the figure, showing it whenever you want is possible, but cumbersome.
There is an idea to enhance the show function in a future version, see https://github.com/matplotlib/matplotlib/pull/14024, but for now the solution would be
import numpy
import matplotlib.pyplot as plt
def reshow(fig):
import importlib
import matplotlib.backends
import matplotlib.backend_bases
backend_mod = importlib.import_module(f"matplotlib.backends.backend_{plt.get_backend().lower()}")
Backend = type("Backend", (matplotlib.backends._Backend,), vars(backend_mod))
fm = Backend.new_figure_manager_given_figure(1, fig)
matplotlib.backend_bases.Gcf.set_active(fm)
plt.show()
my_signals = []
for i in range (0,25):
if i//2 == 0 :
my_signals.append( numpy.random.rand(100))
if i//2 == 1 :
my_signals.append( numpy.random.rand(200))
fig_100 = plt.figure(1)
ax100 = fig_100.add_subplot(111)
ax100.set_title(" length = 100")
fig_200 = plt.figure(2)
ax200 = fig_200.add_subplot(111)
ax200.set_title(" length = 200")
for arrayzz in my_signals :
if len(arrayzz) == 100 :
ax100.plot(arrayzz)
if len(arrayzz) == 200:
ax200.plot(arrayzz)
# First close all figures
plt.close("all")
#Then (re)show a single figure
reshow(fig_100)
# and the other one
reshow(fig_200)

Related

Individual colors for animated 3-D scatter plot in Python

I'm trying to make an animated 3-D scatter plot with the ability to plot a dynamic number of classes as different colors. This is one of the attempts. I've included the whole code in case it is helpful, and marked the trouble spot with a row of stars:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.animation as animation
from random import uniform
x_arr,y_arr,depth_arr,time_arr,ml_arr,cluster_arr = np.loadtxt(data, unpack=5, usecols=(0, 1, 2, 5, 6))
class Point:
def __init__(self,x,y,depth,time,cluster):
self.x=x
self.y=y
self.depth=depth
self.time=time
self.cluster=cluster
points = []
for i in range(0,len(x_arr)):
points.append(Point(x_arr[i],y_arr[i],depth_arr[i],time_arr[i],cluster_arr[i]))
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.set_xlim(min(x_arr), max(x_arr))
ax.set_ylim(min(y_arr), max(y_arr))
ax.set_zlim(min(depth_arr), max(depth_arr))
colors_1 = plt.cm.jet(np.linspace(0,max(cluster_arr),max(cluster_arr)+1))
colors = colors_1.reshape(-1,4)
def plot_points(time):
x = []
y = []
z = []
clust = []
points_cp = list(np.copy(points))
for i in range(0,(int(max(cluster_arr))+1)):
for event in points_cp:
if event.cluster == i:
if event.time < time:
points_cp.remove(event)
elif event.time <= time + 86400:
x.append(event.x)
y.append(event.y)
z.append(event.depth)
clust.append(event.cluster)
points_cp.remove(event)
# **************************************************************
color_ind = 0
first_ind = 0
last_ind = 0
for i in range(0,len(x)):
if clust[i] != color_ind:
last_ind = i
for i in range(0,len(x)):
ax.scatter(x[first_ind:last_ind],y[first_ind:last_ind],z[first_ind:last_ind],c=colors[int(color_ind)])
color_ind = clust[i]
first_ind = i
time = np.linspace(min(time_arr),max(time_arr),100)
ani = animation.FuncAnimation(fig,plot_points,time)
plt.show()
This gives me a plot with the correct colors, but once a point is plotted, it remains throughout the entire animation.
I have also tried set_x, set_color, etc., but this doesn't work with a loop (it is updated with each iteration, so that only the last class is actually plotted), and I need to use a for loop to accommodate a variable number of classes. I've tried using a colormap with a fixed extent, but have been unsuccessful, as colormapping doesn't work with the plot function, and I haven't been able to get the rest of the code to work with a scatter function.
Thanks in advance for your help, and my apologies if the code is a little wonky. I'm pretty new to this.

Updating matplotlib figures in real time for data acquisition

I want to plot data in matplotlib in real time. I want to open a figure once at the start of the programme, then update the figure when new data is acquired. Despite there being a few similar questions out there, none quite answer my specific question.
I want each set of data points new_data1 and new_data2 to be plotted on the same figure at the end of each while loop i.e. one line after the first while loop, two lines on the same figure after the second while loop etc. Currently they are all plotted together, but only right at the end of the programme, which is no use for real time data acquisition.
import matplotlib.pyplot as plt
import numpy
hl, = plt.plot([], [])
def update_line(hl, new_datax, new_datay):
hl.set_xdata(numpy.append(hl.get_xdata(), new_datax))
hl.set_ydata(numpy.append(hl.get_ydata(), new_datay))
plt.xlim(0, 50)
plt.ylim(0,200)
plt.draw()
x = 1
while x < 5:
new_data1 = []
new_data2 = []
for i in range(500):
new_data1.append(i * x)
new_data2.append(i ** 2 * x)
update_line(hl, new_data1, new_data2)
x += 1
else:
print("DONE")
This programme plots all 5 lines, but at the end of the programme. I want each line to be plotted after one another, after the while loop is completed. I have tried putting in plt.pause(0.001) in the function, but it has not worked.
This programme is different from the one that has been put forward - that programme only plots one graph and does not update with time.
If I correctly understood your specifications, you can modify just a bit your MWE as follows:
import matplotlib.pyplot as plt
import numpy
fig = plt.figure(figsize=(11.69,8.27))
ax = fig.gca()
ax.set_xlim(0, 50)
ax.set_ylim(0,200)
hl, = plt.plot([], [])
def update_line(hl, new_datax, new_datay):
# re initialize line object each time if your real xdata is not contiguous else comment next line
hl, = plt.plot([], [])
hl.set_xdata(numpy.append(hl.get_xdata(), new_datax))
hl.set_ydata(numpy.append(hl.get_ydata(), new_datay))
fig.canvas.draw_idle()
fig.canvas.flush_events()
x = 1
while x < 10:
new_data1 = []
new_data2 = []
for i in range(500):
new_data1.append(i * x)
new_data2.append(i ** 2 * x)
update_line(hl, new_data1, new_data2)
# adjust pause duration here
plt.pause(0.5)
x += 1
else:
print("DONE")
which displays :
Not sure, if I am reading the requirements right but below is a blueprint. Please change it to suit your requirements. You may want to change the function Redraw_Function and edit the frames (keyword parameter, which is np.arange(1,5,1) ) in the FuncAnimation call. Also interval=1000 means 1000 milliseconds of delay.
If you are using Jupyter then comment out the second last line (where it says plt.show()) and uncomment the last line. This will defeat your purpose of real time update but I am sorry I had trouble making it work real time in Jupyter. However if you are using python console or official IDLE please run the code as it is. It should work nicely.
import numpy as np
from matplotlib import pyplot as plt
from matplotlib.animation import FuncAnimation
fig, ax = plt.subplots()
plot, = plt.plot([],[])
def init_function():
ax.set_xlim(0,50)
ax.set_ylim(0,250)
return plot,
def Redraw_Function(UpdatedVal):
new_x = np.arange(500)*UpdatedVal
new_y = np.arange(500)**2*UpdatedVal
plot.set_data(new_x,new_y)
return plot,
Animated_Figure = FuncAnimation(fig,Redraw_Function,init_func=init_function,frames=np.arange(1,5,1),interval=1000)
plt.show()
# Animated_Figure.save('MyAnimated.gif',writer='imagemagick')
When you run the code, you obtain the below result. I tried to keep very little code but I am sorry, if your requirement was totally different.
Best Wishes,

Plot size = 1/{N∗⌈log2N⌉∗[(1/70)/60]} in matplotlib in python?

Similar with: Plot size = 1/{N∗⌈log2N⌉∗[(1/70)/60]} in R?
But with matplotlib in python (I guess it will be better to plot the function with matplotlib):
size = 1/{N∗⌈log_2(N)⌉∗[(a)/60]}
a = [1/70, 1/60, 1/50, 1/40]
How can I plot this function (for every value in a - it should be one graphic) with matplotlib in python?
(⌈⌉= ceil)
For example:
With label "size" for y-axis and "N" for the x-axis.
N >= 2, N is natural Number (2,3,4,5,6,...) (but it is not necessary to implement this... see picture above)
I have tried this one as a first approach:
import matplotlib.pyplot as plt
import numpy as np
n = np.arange(3,50,0.1)
size = (1)/n*np.ceil(np.log2(n))*((1/70)/60))
plt.plot(n,size)
plt.axis([3,50,0,550])
plt.show()
If you are looking to plot all the distinct segments and not as continuous lines, one way would be to look for discontinuities in the derivative. In this case, the slopes should always be increasing as n increases (n > 0), so you can look for when it violates this condition and then split the lines there.
import matplotlib.pyplot as plt
import numpy as np
from numpy import diff
n = np.arange(3,50,0.1)
a = [1/70,1/60,1/50,1/40]
discont = np.ones(len(n)-1) #array to show discontinuities
discont[1] = 0
for i in a:
size = 1/(n*np.ceil(np.log2(n))*(i/60))
derivs = diff(size)
for k in range(len(derivs)-2):
if derivs[k+1] > derivs[k]:
discont[k+2] = 0
segments = np.squeeze(np.asarray(discont.nonzero()))
for j in range(len(segments)-1):
start, stop = segments[j], segments[j+1]
plt.plot(n[start:stop],size[start:stop], 'b')
plt.axis([0,20,0,300])
plt.xlabel('N')
plt.ylabel('Size')
plt.grid()
plt.show()
This will produce the following plot:

Python Animated plotting, one point at a time

I have a set of points [index, minimum] and I would like to scatter one point i (index[i],minimum[i]) at a time so that I can see the evolution of the plot.
I would like to know how I can do that. I have tried a time- delay like:
plt.figure()
for i in range (np.size(index)):
plt.plot(index[i], minimum[i],'*')
plt.show()
time.sleep(1)
it did not work.
Thanks in advance.
Might seem stupid but did you import the time library ? Also there is no indentation, is your code really like that or that's a copy/paste fail ?
Edit: Answer in comments, use plt.pause(1), see http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.pause
you should use an "animate" plot :
http://matplotlib.org/api/animation_api.html
and here some good example :
http://matplotlib.org/examples/animation/index.html
You do have to use a nan arrays to plot empty values then update your array as you move in time. Here is a working example:
import numpy as np
import matplotlib.pyplot as plt
import time
nbPoints = 100
nanArray = np.array(np.ones(nbPoints))
nanArray[:] = np.nan
index = range(nbPoints)
minimum = np.random.randint(5, size=nbPoints)
minimumPlotData = nanArray
fig = plt.figure()
ax = plt.subplot(111)
ax.set_xlim(0, nbPoints)
ax.set_ylim(min(minimum), max(minimum))
li, = ax.plot(index,minimumPlotData, marker = 'o', linestyle="")
fig.canvas.draw()
plt.show(block=False)
for i in range(nbPoints):
minimumPlotData[i]=minimum[i]
li.set_ydata(minimumPlotData)
fig.canvas.draw()
time.sleep(1)

At least two tick labels on colobar

If I'm generating a colorbar for an imshow plot, sometimes I end up with a result that includes only one tick-mark --- making the scale fairly indeterminate. Is there a way to ensure that at least 2 tick marks will be present? For example, making sure that at least both ends of the scale are labeled?
For example:
Code to reproduce:
import numpy as np
import matplotlib as mpl
from matplotlib import pyplot as plt
SIZE = [100,100]
MIN = 0.2
tt = np.square(np.random.uniform(size=SIZE))
for ii in range(SIZE[0]):
for jj in range(SIZE[1]):
while( tt[ii,jj] < MIN ): tt[ii,jj] = np.random.uniform()
ran = [ np.min(tt), np.max(tt) ]
print ran
use_norm = mpl.colors.LogNorm()
use_norm.vmin = ran[0]
use_norm.vmax = ran[1]
plt.imshow(tt, norm=use_norm)
plt.colorbar()
plt.show()
which produces something like:

Categories

Resources