Annotating in matplotlib at each point - python

I am working on Radar sensor. I plot the data every time I get it from the sensor. I want to annotate each point with its characteristics e.g x.y.z. How can I do it?
I know about ax.annotate but I can do 1 point at one time. If I loop this command it slows my program. This is what I'm trying to accomplish:

I got the answer of my own question.
We need to use .set_text() command in a loop which updates the text(characteristics of points). Here is the abstract code:
fig1=plt.figure(figsize=(15,32))
ax1=fig1.add_subplot(111, aspect='equal')
ax1.grid(True)
Ln, = ax1.plot(plot_x,plot_y,'ro') #plot_X,plot_y are lists of points
plt.ion() # to make figure interactive
plt.show()
......
......
......
Ln.set_data(plot_x,plot_y) #to updates points in the lists
for i in range(len(plot_ann)): #each time plot_ann number will change
if i >= len(ann_objs): #ann_objs is annotation object list
ann_objs.append(ax1.annotate("", xy=(0,0)))
ann_objs[i].set_text(plot_ann[i])
ann_objs[i].xy = (plot_x[i], plot_y[i])
ann_objs[i].xyann = (plot_x[i]+0.2, plot_y[i]+0.2)

Related

Figure with multiple traces in subplots

I'm trying to create a plot containing 3 subplots, each subplot containing a number of lines plus 2 threshold lines. So far I'm able to create the subplots and plot a couple of lines, but when I want to add more than 2 lines, it won't display them.
Here is the code I'm using:
# Make many subplots
for p_i in range(poses_values_array.shape[1]-6):
if p_i%3 == 0:
main_fig = subplots.make_subplots(rows=3, cols=1, subplot_titles=("lLeg","rLeg","Hip"))
fig = go.Figure()
# Treshold lines
fig.add_trace(go.Scatter(x= list(range(poses_values_array.shape[2])),
y= [pose_max[p_i]] * poses_values_array.shape[2],
name=f'Max Pose {pose_motion[p_i%3]} {pose_names[int(p_i/3)]} Threshold'))
fig.add_trace(go.Scatter(x= list(range(poses_values_array.shape[2])),
y= [pose_min[p_i]] * poses_values_array.shape[2],
name=f'Min Pose {pose_motion[p_i%3]} {pose_names[int(p_i/3)]} Threshold'))
# Data
for t_i in range(poses_values_array.shape[0]):
fig.add_trace(go.Scatter(x=list(range(len(poses_values_array[t_i, p_i, :]))),
y=poses_values_array[t_i, p_i, :],
name=f'Target {t_i+1} - Pose {pose_motion[p_i%3]} {pose_names[int(p_i/3)]}'))
fig.update_layout(title=f'Pose {p_i}',
xaxis_title='Dataset',
yaxis_title='Pose Value')
fig.update_yaxes(autorange=False, zeroline=True, zerolinewidth=2, zerolinecolor='LightPink')
# Update the subplots
for i in range (poses_values_array.shape[0]):
main_fig.append_trace(fig.data[i], row=(p_i%3)+1, col=1)
main_fig.update_layout(title=f'Aggregated {pose_names[int(p_i/3)]} Pose {p_i}-{p_i+3}')
# Update subplots individual subtitles
main_fig.layout.annotations[p_i%3].update(text=f"{pose_names[int(p_i/3)]} {pose_motion[p_i%3]} Pose")
I also tried placing the Threshold lines after the for loop that plots Data, resulting in my current 2 lines (will have more actually) of data showing up but not the treshold lines.
I tried too using fig.add_hline() with the same result.
This is what results from the code. Ideally I would like to see the t_i lines of data in between the thresholds lines:
Hope I can get a hint of what I'm doing wrong.
Thanks!
Oh, wow, soon after posting this question, giving another read to my code, I found the error.
I was not taking into account the threshold lines as part of fig.data, so I was only looping through the first 2 traces that were added to it on the # Update subplots line. I just had to switch for i in range (poses_values_array.shape[0]) to for i in range (poses_values_array.shape[0]+2).

3D Pointcloud Plot

got some Issues here, I do have Coordinates in lists. These coordinates are from a Laserscanner, which scans in layers, so finished one layer it gets to the next, this is were the indicies and nested lists come from. The single lists for X Y and Z are 720 indices long. And the descriebed earlier nested lists for every indice are representing the layers. This gives me a Structure like shown here:
len(X) = 720
X[1] = [ 0. 8.62348279 ... 9.10556606 9.15339632 9.11527918 9.11995584]
What did i try until now?
I did try to plot this Stuff as a Scatterplot, which works quite fine.
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
for i in range(len(X1)):
plt.scatter(X1[i],Y1[i],Z1[i],marker='x')
plt.show()
Now on to my questions:
The ScatterPlot, which you see implemented above shows the points in
a strange "gluLookAt" condition, my first question is how to manipulate
the Look At Angle or Position. So I´m watching the Plot like I´am in the
Position of the scanner, or a bit above.
How can I plot the single Layers in different colors, there are 24 Layers
for one scan circle.
In addition to show how the scanner works, it would be nice to have an
animated scan profile, so every layer get´s scanned one after another.
I hope you guys can help me again, Thanks in advance.
Best regards

Obtaining a value from inside a def()

I have defined a function to plot a histogram. Inside this function I am doing some analysis of the data which I obtain from 2 clicks on the figure.
My code is below:
def hist_maker():
heights,edges = np.histogram(data, 1000)
edges = edges[:-1]+(edges[1]-edges[0])
fig, ax = plt.subplots()
ax.plot(edges,heights) # plot histogram
plt.yscale('log', nonposy='clip')
ax.set(title=titl, xlabel='ADC Value(DN/40)', ylabel='Frequency')
point1, point2 = fig.ginput(2) # get input from 2 clicks on figure
ax.axvspan(point1[0], point2[0], color='red', alpha=0.5) # paint selected area in red
mask = (edges>point1[0]) & (edges<point2[0])
# calculate which values are selected and display mean
fig.text(0.2,0.84,'Mean: ' + str((sum(edges[mask]*heights[mask])/sum(heights[mask]))))
mean = sum(edges[mask]*heights[mask])/sum(heights[mask])
mean_noise = edges[heights.argmax() # Find the x value corresponding to the max y value
fig.text(0.2,0.8,'Std: ' + str(g))
What's actually going on inside the function all works fine. But, for example from the code if I wanted to use the caculated mean_noise at some point later on in the code, I get an error which says that mean noise is not defined (which is right because it isn't defined outside of the function)
So my question is how to extract the value of mean_noise that I calculate automatically when I have defined hist_maker so that I can use it later on?
One way around this is to get rid of the function hist_maker and just repeat the code inside for each histogram I am plotting which I'm sure would work. But as I am plotting multiple histograms I thought it would be easier to define a function and then just keep calling that for each histogram.
Simplest solution - the first line of your function should be:
global mean_noise
If you then run (outside the function):
hist_maker()
print(mean_noise)
The print should work. If you reversed the order of those two lines, you'll get a NameError.
Note, though, this is generally not considered good programming. The generally considered better solution would be to return mean_noise at the end of your function.

Update tripcolor graph in matplotlib animation

I have been trying to create an animation in matplotlib from the graph tripcolor. Let's say I have
field = ax.tripcolor(tri, C)
How do I change the value of C after each iteration of the animation?
Many thanks,
field is guaranteed to be an instance of the matplotlib.collections.Collection base class, which helpfully defines a set_array() method for just such occasions.
In each iteration of your animation, simply pass the new value of C to the field.set_array() method. Assuming you use the FuncAnimation class for animations, as you probably want to, this reduces to:
fig = plt.figure()
ax = plt.subplot(111)
field = ax.tripcolor(tri, C)
def update_tripcolor(frame_number):
# Do something here to update "C"!
C **= frame_number # ...just not this.
# Update the face colors of the previously plotted triangle mesh.
field.set_array(C)
# To triangular infinity and beyond! (Wherever that is. It's probably scary.)
FuncAnimation(fig, update_tripcolor, frames=10)
Updating tri, on the other hand, is considerably more difficult. While this question doesn't attempt to do so, the perspicacious reader may be curious to learn that you basically have to remove, recreate, and re-add the entire triangle mesh (i.e., field) onto this figure's axes. This is both inefficient and painful, of course. (Welcome to Matplotlib. Population: you.)
May the field.set_array() be with you.

Plotting millions of data points in Python?

I have written a complicated code. The code produces a set of numbers which I want to plot them. The problem is that I cannot put those numbers in a list since there are 2 700 000 000 of them.
So I need to plot one point then produce second point (the first point is replaced by second point so the first one is erased because I cannot store them). These numbers are generated in different sections of the code so I need to hold (MATLAB code) the figure.
For making it more conceivable to you, I write a simple code here and I want you to show me how to plot it.
import matplotlib.pyplot as plt
i=0
j=10
while i<2700000000:
plt.stem(i, j, '-')
i = i + 1
j = j + 2
plt.show()
Suppose I have billions of i and j!
Hmm I'm not sure if I understood you correctly but this:
import matplotlib.pyplot as plt
i=0
j=10
fig=plt.figure()
ax=fig.gca()
while i<10000: # Fewer points for speed.
ax.stem([i], [j]) # Need to provide iterable arguments to ax.stem
i = i + 1
j = j + 2
fig.show()
generates the following figure:
Isn't this what you're trying to achieve? After all the input numbers aren't stored anywhere, just added to the figure as soon as they are generated. You don't really need Matlab's hold equivalent, the figure won't be shown until you call fig.show() or plt.show() to show the current figure.
Or are you trying to overcome the problem that you can' hold the matplotlib.figure in your RAM? In which case my answer doesn't answer your question. Then you either have to save partial figures (only parts of the data) as pictures and combine them, as suggested in the comments, or think about an alternative way to show the data, as suggested in the other answer.

Categories

Resources