Plotly.py: Fill To Zero, Different Color For Positive/negative
Solution 1:
I was in need of such a graph so I wrote a function.
defresid_fig(resid, tickvalues):
"""
resid: The y-axis points to be plotted. x-axis is assumed to be linearly increasing
tickvalues: The values you want to be displayed as ticklabels on x-axis. Works for hoverlabels too. Has to be
same length as `resid`. (This is necessary to ignore 'gaps' in graph where two polygons meet.)
"""#Adjusting array with paddings to connect polygons at zero line on x-axis
index_array = []
start_digit = 0
split_array = np.split(resid,np.where(np.abs(np.diff(np.sign(resid)))==2)[0]+1)
split_array = [np.append(x,0) for x in split_array]
split_array = [np.insert(x,0,0) for x in split_array]
split_array[0] = np.delete(split_array[0],0)
split_array[-1] = np.delete(split_array[-1],-1)
for x in split_array:
index_array.append(np.arange(start_digit,start_digit+len(x)))
start_digit += len(x)-1#Making an array for ticklabels
flat = []
for x in index_array:
for y in x:
flat.append(y)
flat_counter = Counter(flat)
none_indices = np.where([(flat_counter[x]>1) for x in flat_counter])[0]
custom_tickdata = []
neg_padding = 0
start_pos = 0for y inrange(len(flat)):
for x inrange(start_pos,flat[-1]+1):
if x in none_indices:
custom_tickdata.append('')
break
custom_tickdata.append(tickvalues[x-neg_padding])
neg_padding +=1
start_pos = 1+x
#Making an array for hoverlabels
custom_hoverdata=[]
sublist = []
for x in custom_tickdata:
if x == '':
custom_hoverdata.append(sublist)
sublist = []
sublist.append(x)
continue
sublist.append(x)
sublist2 = sublist.copy()
custom_hoverdata.append(sublist2)
#Creating figure
fig = go.Figure()
idx = 0for x,y inzip(split_array,index_array):
color = 'rgba(219,43,57,0.8)'if x[1]<0else'rgba(47,191,113,0.8)'if (idx==0and x[0] < 0):
color= 'rgba(219,43,57,0.8)'
fig.add_scatter(y=x, x=y, fill='tozeroy', fillcolor=color, line_color=color, customdata=custom_hoverdata[idx],
hovertemplate='%{customdata}<extra></extra>',legendgroup='mytrace',
showlegend=Falseif idx>0elseTrue)
idx += 1
fig.update_layout()
fig.update_xaxes(tickformat='', hoverformat='',tickmode = 'array',
tickvals = np.arange(index_array[-1][-1]+1),
ticktext = custom_tickdata)
fig.update_traces(mode='lines')
fig.show()
Example-
resid_fig([-2,-5,7,11,3,2,-1,1,-1,1], [1,2,3,4,5,6,7,8,9,10])
Now, for the caveats-
It does use separate polygons but I have combined all the traces into a single
legendgroup
so clicking on legend turns all of them on or off. About the legend colour, one way is to change0
to1
inshowlegend=False if idx>0
in thefig.add_scatter()
call. It then shows two legends, red and green still in the same legendgroup though so they still turn on and off together.The function works by first separating continuous positive and negative values into arrays, adding
0
to the end and start of each array so the polygons can meet at the x-axis. This means the figure does not scale as well but depending on the use-case, it might not matter as much. This does not affect the hoverlabels or ticklabels as they are blank on these converging points.The most important one, the graph does not work as intended when any of the point in the passed array is
0
. I'm sure it can be modified to work for it but I have no use for it and the question doesn't ask for it either.
Post a Comment for "Plotly.py: Fill To Zero, Different Color For Positive/negative"