I am new to python and matplotlib.
I am trying to highlight a few points that match a certain criteria in an already existing plot in matplotlib.
The code for the initial plot is as below:
pl.plot(t,y)
pl.title('Damped Sine Wave with %.1f Hz frequency' % f)
pl.xlabel('t (s)')
pl.ylabel('y')
pl.grid()
pl.show()
In the above plot I wanted to highlight some specific points which match the criteria abs(y)>0.5. The code coming up with the points is as below:
markers_on = [x for x in y if abs(x)>0.5]
I tried using the argument 'markevery', but it throws an error saying
'markevery' is iterable but not a valid form of numpy fancy indexing;
The code that was giving the error is as below:
pl.plot(t,y,'-gD',markevery = markers_on)
pl.title('Damped Sine Wave with %.1f Hz frequency' % f)
pl.xlabel('t (s)')
pl.ylabel('y')
pl.grid()
pl.show()
4 Answers 4
The markevery
argument to the plotting function accepts different types of inputs. Depending on the input type, they are interpreted differently. Find a nice list of possibilities in this matplotlib example.
In the case where you have a condition for the markers to show, there are two options. Assuming t
and y
are numpy arrays and one has import
ed numpy as np
,
Either specify a boolean array,
plt.plot(t,y,'-gD',markevery = np.where(y > 0.5, True, False))
or
an array of indices.
plt.plot(t,y,'-gD',markevery = np.arange(len(t))[y > 0.5])
Complete example
import matplotlib.pyplot as plt
import numpy as np; np.random.seed(42)
t = np.linspace(0,3,14)
y = np.random.rand(len(t))
plt.plot(t,y,'-gD',markevery = np.where(y > 0.5, True, False))
# or
#plt.plot(t,y,'-gD',markevery = np.arange(len(t))[y > 0.5])
plt.xlabel('t (s)')
plt.ylabel('y')
plt.show()
resulting in
-
2
markevery = np.where(y > 0.5, True, False)
throws ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all(). Usingmarkevery = list(np.where(y > 0.5, True, False))
solves the issue.pfabri– pfabri2020年04月29日 18:19:35 +00:00Commented Apr 29, 2020 at 18:19 -
Apprently
markevery = np.arange(len(t))[y > 0.5]
throws the exact same error. But passing the output as alist
solves the problem. These errors are thrown in Matplotlib 3.1.3. Perhaps there was a breaking change somewhere along the line since 2017 when this question was first posted.pfabri– pfabri2020年04月29日 18:32:40 +00:00Commented Apr 29, 2020 at 18:32 -
@pfabri Thanks for the notification. This indeed went wrong a long time ago. I now fixed it in github.com/matplotlib/matplotlib/pull/17276.ImportanceOfBeingErnest– ImportanceOfBeingErnest2020年04月30日 14:33:05 +00:00Commented Apr 30, 2020 at 14:33
-
1You're welcome. I tried editing your answer adding in the fix from my comment as an alternative, but the editing queue is full. Perhaps you could also try... If you found my comment useful... well you know, I'm starved for those rep points :)pfabri– pfabri2020年04月30日 15:33:52 +00:00Commented Apr 30, 2020 at 15:33
markevery
uses boolean values to mark every point where a boolean is True
so instead of markers_on = [x for x in y if abs(x)>0.5]
you'd do markers_on = [abs(x)>0.5 for x in y]
which will return a list of boolean values the same size of y, and every point where |x|> 0.5 you'd get True
Then you'd use your code as is:
pl.plot(t,y,'-gD',markevery = markers_on)
pl.title('Damped Sine Wave with %.1f Hz frequency' % f)
pl.xlabel('t (s)')
pl.ylabel('y')
pl.grid()
pl.show()
I know this question is old, but I found this solution while trying to do the top answer as I'm not familiar with numpy and it seemed to overcomplicate things
The markevery argument only takes indices of type None, integer or boolean arrays as input. Since I was passing the values directly it was throwing the error.
I know it is not very pythonic but I used the below code to come up with the indices.
marker_indices = []
for x in range(len(y)):
if abs(y[x]) > 0.5:
marker_indices.append(x)
I was having this issue because I was trying to mark some points that were out of the bounds of the data frame.
For example:
some_df.shape
-> (276, 9)
markers = [1000, 1080, 1120]
some_df.plot(
x='date',
y=['speed'],
figsize=(17, 7), title="Performance",
legend=True,
marker='o',
markersize=10,
markevery=markers,
)
-> ValueError: markevery=[1000, 1080, 1120] is iterable but not a valid numpy fancy index
Just make sure that the values you are giving as markers are within the bounds of the data frame you want to plot.