Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Matplotlib - Changing line color above/below hline

I have a line plot and 2 hlines, all using different colors, and I'm filling the areas where the main line crosses the hlines with the color of the hline. In addition to that, I'd like to use the same color for the main line in those areas. In a nutshell, current output: enter image description here

Desired output: enter image description here

And the relevant code I'm currently using:

lower, upper = 20, 80

self.indicatorPlot.axhline(lower, color="red")
self.indicatorPlot.axhline(upper, color="green")

self.indicatorPlot.plot(self.chartTimes, self.indicatorData, color="blue")

self.indicatorPlot.fill_between(self.chartTimes, self.indicatorData, lower, where=(self.indicatorData <= lower), facecolor="red", interpolate=True)
self.indicatorPlot.fill_between(self.chartTimes, self.indicatorData, upper, where=(self.indicatorData >= upper), facecolor="green", interpolate=True)
like image 924
Natsukane Avatar asked Sep 14 '17 07:09

Natsukane


1 Answers

In principle you may split up your plot into three parts, the values above upper, the values below lower and the values in the middle. In that sense this question has already been asked and answered, e.g.

  • Python: Is it possible to change line color in a plot if exceeds a specific range?
  • Plot: color all larger than different color

Those solutions work great if your point density is high enough, such that the lines end up close enough to the threshold line.

In the case where you have larger gaps they are probably not well suited. I will hence give a solution here, which interpolates the gaps such that the lines end exactly at the threshold line.

import numpy as np; np.random.seed(43)
import matplotlib.pyplot as plt

t = np.linspace(0,100,301)
x = np.cumsum(np.random.randn(len(t)))

lower,upper = 0,8

fig, ax=plt.subplots()

ax.axhline(lower, color="crimson")
ax.axhline(upper, color="limegreen")


def insertzeros(t, x, zero=0):
    ta = []
    positive = (x-zero) > 0
    ti = np.where(np.bitwise_xor(positive[1:], positive[:-1]))[0]
    for i in ti:
        y_ = np.sort(x[i:i+2])
        z_ = t[i:i+2][np.argsort(x[i:i+2])]
        t_ = np.interp(zero, y_, z_)
        ta.append( t_ )
    tnew = np.append( t, np.array(ta) )
    xnew = np.append( x, np.ones(len(ta))*zero )
    xnew = xnew[tnew.argsort()]
    tnew = np.sort(tnew)
    return tnew, xnew

t1,x1 = insertzeros(t,x, zero=lower)
t1,x1 = insertzeros(t1,x1, zero=upper)

xm = np.copy(x1)
xm[(x1 < lower) | (x1 > upper)] = np.nan        
ax.plot(t1,xm, color="C0")

xl = np.copy(x1)
xl[(x1 > lower)] = np.nan        
ax.plot(t1,xl, color="crimson")
#
xu = np.copy(x1)
xu[(xu < upper)] = np.nan        
ax.plot(t1,xu, color="limegreen")

ax.fill_between(t, x, lower, where=(x <= lower), facecolor="crimson", interpolate=True, alpha=0.5)
ax.fill_between(t, x, upper, where=(x >= upper), facecolor="limegreen", interpolate=True, alpha=0.5)


plt.show()

enter image description here

like image 161
ImportanceOfBeingErnest Avatar answered Sep 29 '22 08:09

ImportanceOfBeingErnest