Change color of continuous line based on value

Is it possible to get a plot like below ( color line given y axis value as cutoff)

image

Hi @yogi_dhiman ,

I think there is no built in function for this. There are two possible solutions I came up with, the first does not answer your question but could be a option, the second includes some preparation of your data first.

The first is coloring the markers instead of the line:

import plotly.graph_objects as go
import numpy as np

# generate data
x = np.arange(0, 8*np.pi, 0.1)
y = np.sin(x)

# cutoff value
cutoff = 0

# generate color list
colors=['red' if val < cutoff else 'blue' for val in y]

# create trace
trace = go.Scatter(
    x=x, 
    y=y, 
    mode='markers+lines', 
    marker={'color': colors}, 
    line={'color': 'gray'}
)

# crate figure, plot 
fig = go.Figure(data=trace)
fig.show()

result:

The second option adds each line segment between two points as a new trace. In proximity to the cutoff value the line color is not correct if one of the two y- values lies above the cutoff and the other y-value lies below the cutoff. If you prepare your data so that this does not occur (i.e serch for those cases and create a midpoint) the line color should be accurate.

import plotly.graph_objects as go
import itertools as it
import numpy as np

# generate data
x = np.arange(0, 8*np.pi, 0.1)
y = np.sin(x)

# cutoff value
cutoff = 0

# create coordinate  pairs
x_pairs = it.pairwise(x)
y_pairs = it.pairwise(y)

# generate color list
colors=['red' if any([i < cutoff for i in y_values]) else 'blue' for y_values in it.pairwise(y)]

# create base figure
fig = go.Figure()

# add traces (line segments)
for x, y, color in zip(x_pairs, y_pairs, colors):
    fig.add_trace(
        go.Scatter(
            x=x,
            y=y, 
            mode='lines', 
            line={'color': color}
        )
    )
    
fig.update_layout(showlegend=False)

result:

mrep linecolor

2 Likes

I share a third solution with you, something that I have learned between trials and errors is that NaN values ​​are not graphed in this way we could create a line of as many colors as you want and you only need to add a line for each color, having a base arrangement we separate it in as many arrays as colors you want filling each array with values ​​when certain conditions are met and putting NaN when they are not.

The following function receives the source array as a parameter and returns two arrays to represent the change of direction in the graph.

function linesBuySell(source, isbuy = false, issell = false){
	let buyline = [], 
	sellline = [], 
	isBuy = isbuy, 
	isSell = issell,
	start = source.length - 3

	if(source[start + 1] > source[start + 2]) {
		buyline = source.slice(source.length - 2)
		sellline = [NaN, NaN]
	}
	else {
		sellline = source.slice(source.length - 2)
		buyline = [NaN, NaN]
	}
	
	for(let i = start; i >= 0; i -= 1) {
		if(!isBuy) {
			isBuy = (source[i] > source[i + 1]) && (source[i + 1] < source[i + 2])
			if(isBuy) isSell = false
		}

		if(!isSell) {
			isSell = (source[i] < source[i + 1]) && (source[i + 1] > source[i + 2])
			if(isSell) isBuy = false
		}				

		if(!isBuy && !isSell) {
			buyline.unshift(buyline[0] != NaN ? source[i] : NaN)
			sellline.unshift(sellline[0] != NaN ? source[i] : NaN)
		}

		if(isBuy && !isSell) {
			
			buyline.unshift(source[i])
			if(buyline[1])
				sellline.unshift(NaN)
			else
				sellline.unshift(source[i])
		}

		if(isSell && !isBuy) {
			
			sellline.unshift(source[i])
			if(sellline[1])
				buyline.unshift(NaN)
			else
				buyline.unshift(source[i])
		}
	}

	return {buy: buyline, sell: sellline, isbuy: isBuy, issell: isSell}
}

And then I just need to graph both arrangements

    Plotly.addTraces(this.kl.layer, 
    [{
        id: this.id,
        name: this.name,
        type: 'line',
        x: this.x,
        y: this.buy,
        xaxis: 'x',
        yaxis: `y${this.yaxi}`,
        hoverinfo: 'none',
        mode: 'lines',
        cliponaxis: true,
        visible: true,
        opacity: this.opacity,
        line: {
            shape: 'spline',
            smoothing: 0.5,
            color: 'green',
            width: this.width    
        }
    },{
        id: this.id,
        name: this.name,
        type: 'line',
        x: this.x,
        y: this.sell,
        xaxis: 'x',
        yaxis: `y${this.yaxi}`,
        hoverinfo: 'none',
        mode: 'lines',
        cliponaxis: true,
        visible: true,
        opacity: this.opacity,
        line: {
            shape: 'spline',
            smoothing: 0.5,
            color: 'red',
            width: this.width    
        }
    }])

And I only needed two strokes, one for each color, now the next challenge is to draw a cloud of ichimoku