It is possible to fill area with different colors on a line plot?

Hi! i want to fill an area based on y values: red to negative, green to positives. How can i do that?

image

I don’t know how to it with one single trace, but here is a solution using numpy masks:

import plotly.graph_objects as go
import numpy as np
x = np.linspace(0, 2*np.pi, 100)
y = np.sin(x)
mask = y >= 0
fig = go.Figure(go.Scatter(x=x[mask], y=np.sin(x)[mask], mode='lines',
                           fill='tozeroy', fillcolor='green'))
fig.add_trace(go.Scatter(x=x[~mask], y=y[~mask], mode='lines', fill='tozeroy', fillcolor='red'))

fig.show()

1 Like

Thank you for your answer! But i want to do it with a single trace

I don’t think you can. That would be a new mode for the fill argument of Scatter traces.

Ok, thanks for your help!!!

@yuricda96 If your usecase of having only one trace is so that the legend behaves as a single trace, you can do the following:

  • Hide the legend for one of the two traces showlegend=False
  • Put both traces in the same legend group (e.g. legendgroup="my-trace")

This way you will only see one trace for the two and clicking on the legend shows/hides both traces at once.

You can also set the line color and fillcolor differently to have continuity of the line with different fill colors if necessary.

Hope this can be of help.

I’ll just add this here, Fill area between 2 lines [SOLVED]
This saved me from a great deal of frustration.

Great tips, I like it
However, it has some issues when the values are equal to the threshold (zero in your example).
so it has a gaped space with no color.

Save

and if the steps are few it will be bigger and awful plot :frowning: .

So I tried to solve this and get this maybe someone needs it :slight_smile: (like me a few hours ago)

import plotly.graph_objects as go
import numpy as np
x = np.linspace(0, 2*np.pi, 100)
y = np.sin(x)
# I just add a threshold

threshold= 0
x2=[]
y2=[]

for i in range(len(y)-1):
	x2 +=[x[i]]
	y2  +=[y[i]]
	if y[i]>threshold>y[i+1] or y[i]<threshold<y[i+1]:
		Xi=x[i]+((threshold-y[i])*(x[i+1]-x[i])/(y[i+1]-y[i]))
		x2 +=[Xi]
		y2 +=[threshold]
x2 +=[x[-1]]
y2 +=[y[-1]]

x2 = np.array(x2)
y2 = np.array(y2)

mask   = y2 >= threshold
mask2 = y2 <= threshold

fig = go.Figure(go.Scatter(x=x2[mask], y=np.sin(x2)[mask], mode='lines',
                           fill='tozeroy', fillcolor='green'))
fig.add_trace(go.Scatter(x=x2[mask2], y=y2[mask2], mode='lines', fill='tozeroy', fillcolor='red'))

fig.show()

and it works

you can set the threshold as you wish (0.2)

All my best

1 Like