Reputation: 13
I have data that is pretty cyclical in nature but not quite exactly Here is what part of the data looks like . I want to color all the points that are monotonically increasing one color, call it color A, then I want to color all the points that decreasing one color ,call it B, and then the next points that are increasing color C and then color B for when we decrease. The data is essentially a running total of X until Y and then reset X back to 0 and keep counting. Data is in a pandas df and I am using matplotlib to do this graphing.
Any advice would be much appreciated!
Upvotes: 1
Views: 130
Reputation: 5294
Let's start with a sample dataset, hoping it mimicks yours well enough:
y = np.linspace(0, 10000, 1000, endpoint=True)
for i in np.sort(np.random.randint(1000, size=10)):
y[i:] = y[i:] - y[i]
Now we need to identify the monotonically increasing segments. You can find where the first discrete derivative becomes negative and use cumulative sum to get a discrete category/color for each group of points.
It's easier done than said:
c = np.cumsum((np.diff(y) < 0))
Now c represents the color of our segments, its shape is (999,) but we want it to be (1000,) like y, so
c = np.hstack([c[0], c])
Now you can use plt.scatter
with c
as color to plot each segment with a different shade:
plt.scatter(np.arange(len(y)), y, marker='.', c=plt.cm.tab20(c))
If you prefer to plot proper lines instead of using scatter it's a little more tricky: take a look at How to plot one line in different colors
This assumes your dataset only includes monotonically increasing segments. If you also have decreasing ones you can use the sign of the first derivative (change color when sign changes). Something like:
c = np.pad((np.diff(np.sign(np.diff(y))) != 0).cumsum(), [1,1], mode='edge')
Just for the sake of completess let's try this with a sawtooth-ish signal:
y = np.linspace(0, 10000, 1000, endpoint=True)
for i in np.sort(np.random.randint(1000, size=5)):
y = np.abs(y - y[i]) + y[i]
Let's use c
from the relation above and do a scatter plot:
plt.scatter(np.arange(len(y)), y, marker='.', c=plt.cm.tab20(c))
Upvotes: 1