Differentiate some points in a python plot - python

I have a plot in Python of the following
a = (1,2,3,4,5)
b = (1,2,3,4,5)
plot(a,b)
I want to differentiate some of the x axis points in the plot with a dots of unique colors
for examples this points
c = (2,4)
I tried the following:
a = (1,2,3,4,5)
b = (1,2,3,4,5)
plot(a,b)
matplotlib.pyplot.scatter(a, c)
But I got the error "x and y must be the same size"

If you google "matplotlib scatter" or something like that, one of the first links will be this one, which says that the function gives "a scatter plot of y vs. x". So, the error message you shared makes sense, since the length of a is greater than the length of c. I hope it makes sense to you why what your original code gives that error.
Your problem is specific enough that there isn't an out-of-the-box solution in matplotlib that I'm aware of, so this will require the use of your own custom functions. I'll give one approach that might be helpful to you. I'm structuring my answer here so you can see how to solve the issue to your own specifications, instead of relying too heavily on copying & pasting other people's code, since the latter makes it harder for you to do exactly what you want to do.
To restate the problem in more concise terms: How can a matplotlib user plot a line, and then put markers on a subset of the line's points, specified by their x-values?
To begin, here is what your program might look like currently:
import matplotlib.pyplot as plt
x_coords = [ ] # fill in x_coords here
y_coords = [ ] # fill in y_coords here
marker_x_coords = [ ] # fill in with x coordinates of points you want to have markers
plt.plot(x_coords, y_coords) # plots the line
#### TODO: plot the markers ####
Now, you have the x-values of the points you want to put markers on. How might you get their corresponding y-values? Well, you can make a function that searches for the index of the x-value in x_coords, and then gives the corresponding value at the same index of y_coords:
def getYVals(x_coords_lst, y_coords_lst, marker_x_coords_lst):
marker_y_coords = [] # start with an empty list
for x_point in marker_x_coords_lst:
point_index = x_coords_lst.index(x_point) # get the index of a point in the x list
marker_y_coords.append(y_coords_lst[point_index]) # add the value of the y list at that index to the list that will be returned
return marker_y_coords
This isn't the fastest method, but it is the clearest on what is happening. Here's an alternative that would give the same results but would likely perform faster computationally (it uses something called "list comprehension"):
def getYVals(x_coords_lst, y_coords_lst, marker_x_coords_lst):
return [y_coords_lst[x_coords_lst.index(x_val)] for x_val in marker_x_coords_lst]
The output of either of the getYVals function above will work as the y values of the markers. This can be put in the y argument of plt.scatter, and you already have the x values of it, so from there you should be good to go!

Related

Adding a 2D Array to a 3D Array

Im struggling a little with stacking two matrices on top of each other. I'm using the pyKalman package, which when updated, returns a tuple of matrices. One with an updated estimate (new_pred a 1 x 2 vector) and the corresponding covariance matrix (new_cov a 2 x 2 matrix).
After the update, I want to stack the returned values to their corresponding outputs, for a recursive smoothing of the data, through these estimates.
The following is how it is currently implemented.
for meas in onlineObservations:
(new_pred, new_cov) = kf.filter_update(states_pred[-1], cov_pred[-1], meas)
states_pred = np.vstack((states_pred, new_pred))
cov_pred = np.stack((cov_pred, new_cov), axis=0)
Which works really well for the updated estimate (the 1x2 vector), but fails when i try to add new_cov to the array called cov_pred. For good measure:
states_pred.shape = (900,2)
cov_pred.shape = (900, 2, 2)
I've tried changing the axis of "stack" to no avail. It's probably something elementary, but i've been struggling with it for the past hour, and cannot seem to find a "simple" solution.
Thanks in advance.
This should work -
cov_pred = []
for meas in onlineObservations:
(new_pred, new_cov) = kf.filter_update(states_pred[-1], cov_pred[-1], meas)
states_pred = np.vstack((states_pred, new_pred))
cov_pred.append[new_cov]
cov_pred = np.stack(cov_pred, axis=0)
But since you want to update array which you are using already in code, you should use np.concatenate
for meas in onlineObservations:
(new_pred, new_cov) = kf.filter_update(states_pred[-1], cov_pred[-1], meas)
states_pred = np.vstack((states_pred, new_pred))
cov_pred = np.concatenate((cov_pred, np.reshape(new_cov, (1,2,2))), axis=0)
I've been able to make it work by converting cov_pred to a list, and then use:
cov_pred.append(new_cov)
And then re-convert it back again after the for loop. But it seems tedious - at least if there's an even better way!
You can keep your code inside a For Loop (While Loop will also do) and use 'Auto-index Enabled' and thats it....
At the output of Loop, LabVIEW will create a 3D data exactly as your requirement.

Can I call the index of an array?

So I have an image which I imported to python. The imread command basically gives me an array X,Y,Z where X and Y are the coordinates of the pixels and Z (which has four dimensions) gives me the RGB values at a given point (X,Y).
import matplotlib.image as img
import numpy as np
RawImg = img.imread('tek0000.bmp','RGB')
CrpImg = RawImg[14:208,12:256,:]
x_values = []
y_values = []
for row in CrpImg:
for cell in row:
print(np.nonzero)
if (cell == [136,136,0,255]).all:
My goal is to analyze the exact points in the array where the RGB configuration is [136,136,0,255]. These points are greenish-yellow. I want to add the X and Y values to lists or arrays so I can plot them.
In order to achieve this, I iterate over every point X and Y (row and column) of the array, and analyze the Z values. What I need is the coordinate (X,Y) of the cell in the for loop.
Basically, if the color in the point (X,Y) of the image is yellow, add that point (X,Y) to the list.
Surprisingly I cannot find pretty much anything online for what I think, is a relatively simple thing. I realize that I can interate using the following:
for i in range len(X axis) something like that, but I want to know if it is possible this way.
Not completely sure this is what you're looking for, but I think you want to get the index from inside the loop. The main ways to do this would be
loop using the index, e.g. for i in range(0,255): and then index into the array
iterate using enumerate, which returns an index as well as value in a collection
use the index method
I think the easiest option for you will be the index method.
for row in CrpImg:
for cell in row:
print(np.nonzero)
if (cell == [136,136,0,255]).all:
print(CrpImg.index(row), row.index(cell))
Note that this is going to give you the index inside your crop rather than the full image. You can either adjust (by adding 14 and 12), or you can iterate over the full image.
If you use enumerate from the standard library, you get access to a tuple containing a count and your values. The count starts at 0 by default
for row in CrpImg
becomes
for num, row in enumerate(CrpImg):
print(num)
Try using numpy.where:
indices = numpy.where(my_array == [136,136,0,255])

Matplotlib Ticker

Can someone give me an example of how to use the following tickFormatters. The docs are uninformative to me.
ticker.StrMethodFormatter()
ticker.IndexFormatter()
for example I might think that
x = np.array([ 316566.962, 294789.545, 490032.382, 681004.044, 753757.024,
385283.153, 651498.538, 937628.225, 199561.358, 601465.455])
y = np.array([ 208.075, 262.099, 550.066, 633.525, 612.804, 884.785,
862.219, 349.805, 279.964, 500.612])
money_formatter = tkr.StrMethodFormatter('${:,}')
plt.scatter(x,y)
ax = plt.gca()
fmtr = ticker.StrMethodFormatter('${:,}')
ax.xaxis.set_major_formatter(fmtr)
would set my tick labels to be dollar signed and comma sep for thousands places ala
['$300,000', '$400,000', '$500,000', '$600,000', '$700,000', '$800,000', '$900,000']
but instead I get an index error.
IndexError: tuple index out of range
For IndexFormatter docs say:
Set the strings from a list of labels
don't really know what this means and when I try to use it my tics disappear.
The StrMethodFormatter works indeed by supplying a string that can be formatted using the format method. So the approach of using '${:,}' goes in the right direction.
However from the documentation we learn
The field used for the value must be labeled x and the field used for the position must be labeled pos.
This means that you need to give an actual label x to the field. Additionally you may want to specify the number format as g not to have the decimal point.
fmtr = matplotlib.ticker.StrMethodFormatter('${x:,g}')
The IndexFormatter is of little use here. As you found out, you would need to provide a list of labels. Those labels are used for the index, starting at 0. So using this formatter would require to have the x axis start at zero and ranging over some whole numbers.
Example:
plt.scatter(range(len(y)),y)
fmtr = matplotlib.ticker.IndexFormatter(list("ABCDEFGHIJ"))
ax.xaxis.set_major_formatter(fmtr)
Here, the ticks are placed at (0,2,4,6,....) and the respective letters from the list (A, C, E, G, I, ...) are used as labels.

Plotting two objects using a 4-item list

I have this simulator (gravitation) I've been working on, and I've dissected the equations, math, etc. and it's totally legitimate. However, when I animate the thing I get weird behavior. I'd rather not bore everyone with the entire script because it's sorta lengthy, but the method I'm calling in line.set under the animate(i) function returns a list of four values, which are the positions of my two particles in Cartesian (x,y) coordinates. For example my list looks like:
[1.2, 3.2, 4.5, 5.1]
where the first index is the x-position of the first particle, the second index is the y-position and likewise for the the last two elements corresponding to the second particle (indices 2 and 3).
My question is whether the line.set_data(force.updatePosition(dt)) should be working the way I think it does, i.e. plotting the first particle with indices 0 and 1 and particle two with indices 2 and 3, or am I missing the point? The plotting works, the particles show up, but they get weird, non-sensical movement.
If it's completely necessary here is the script in its entirety...again it's long-ish that's why I didn't post it directly. Also, it's pretty messy as I'm still fighting with it and haven't cleaned it up yet.
Tl;DR Should line.set_data() be able to plot two separate objects if it is fed a list with 4 items?
def init():
line.set_data([], [])
return line,
def animate(i):
line.set_data(force.updatePosition(dt))
return line,
The docs say:
Definition: l.set_data(self, *args)
Docstring:
Set the x and y data
ACCEPTS: 2D array (rows are x, y) or two 1D arrays
So I imagine you want to give it two lists:
line.set_data([x1, x2], [y1, y2])
But it seems that force.updatePosition already returns a list of two lists([pos1]+[pos2]), so you can maybe try:
line.set_data(np.transpose(force.updatePosition(dt)))
My opinion is you might be better off keeping all this info in arrays and remove half the lines of your code, since you write every line two or four times for each element.

Sort arrays by two criteria

My figure has a very large legend, and to make it easier to find each corresponding line, I want to sort the legend by the y value of the line at the last datapoint.
plots[] contains a list of Line2D objects,
labels[] is the corresponding labels to each Line2D object, generated through labels = [plot._label for plot in plots]
I want to sort each/both arrays by plots._y[-1], the value of y at the last point
Bonus points if I can also sort first by _linestyle (a string) and then by the y value.
I am unsure of how to do this well, I wouldn't think it would require a loop, but it might because I am sorting by 2 criteria, one of which will be tricky to deal with (':' and '-' are the values of linestyle). Is there a function that can help me out here?
edit: it just occurred to me that I can generate labels after I sort, so that uncomplicates things a bit. However, I still have to sort plots by each object's linestyle and y[-1] value.
I believe this may work:
sorted(plots, key = lambda plot :(plot._linestyle, plot._y[-1]))

Categories

Resources