Closed helloitsjulian closed 4 years ago
Also wondering if this is in the works! Maybe something along the lines of:
.update_layout(hline=5)
.update_layout(vline=-1)
You can indeed add horizontal and vertical lines to plots in general, but we don't have a "facet-aware" way of doing this yet unfortunately, so this only really works well/easily with a single plot:
import plotly.express as px
df = px.data.tips()
fig = px.scatter(df, x="total_bill", y="tip")
fig.update_layout(shapes=[
dict(
type= 'line',
yref= 'paper', y0= 0, y1= 1,
xref= 'x', x0= 5, x1= 5
)
])
This adds a vertical line at x
=5
I'm finding that if you add fig.show(config={"showLink":False})
, you receive duplicate charts:
import plotly.express as px
df = px.data.tips()
fig = px.scatter(df, x="total_bill", y="tip")
fig.update_layout(shapes=[
dict(
type= 'line',
yref= 'paper', y0= 0, y1= 1,
xref= 'x', x0= 5, x1= 5
)
])
fig.show(config={"showLink":False})
Is this behavior intended/built in to .update_layout(...)
?
I'm not sure what you mean by "duplicate charts" here...? Also note that the "showLink: False"
is redundant in Plotly.py v4, as this is the default :)
Ah, if you mean that fig.update_layout()
returns fig
then yes, this is intentional, so if you have a notebook cell that ends with this call, then fig.show()
is optional. But in a single notebook cell, your code above should output only a single chart.
Nice @nicolaskruchten ! Is there a way to add more than one xref or yref? Because my express px.scatter have multiple facets.
Answer: just add another dict in the shape list:
fig.update_layout(shapes=[ # Line Diagonal
dict(
type="line",
yref='y1',
y0=200,
y1=200,
xref='x1',
x0=min_x*0.8,
x1=max_x*1.2,
line=dict(
color="Red",
width=4,
dash="dashdot",
)
),
dict(
type="line",
yref='y2',
y0=200,
y1=200,
xref='x2',
x0=min_x*0.8,
x1=max_x*1.2,
line=dict(
color="Red",
width=4,
dash="dashdot",
)
)
])
we don't have a "facet-aware" way of doing this yet unfortunately
@nicolaskruchten Is there any plans of implementing this? It's very useful when trying to display thresholds values or summary statistics (mean, median) across facets (Either constant value across all facets, or generated upon grouping for facets). yintercept or xintercept values could be used and just utilize the trend line functionality to just display a constant trend.
Yes, we will implement a nice .add_hlines()
and .add_vlines()
in an upcoming version, as the current way is pretty clunky.
You can follow the development here: https://github.com/plotly/plotly.py/issues/2141
fig.update_layout(shapes=[ # Line Diagonal dict( type="line", yref='y1', y0=200, y1=200, xref='x1', x0=min_x*0.8, x1=max_x*1.2, line=dict( color="Red", width=4, dash="dashdot", ) ), dict( type="line", yref='y2', y0=200, y1=200, xref='x2', x0=min_x*0.8, x1=max_x*1.2, line=dict( color="Red", width=4, dash="dashdot", ) ) ])
@vcmorini Thanks for the idea. A more generalized solution based off this:
fig.layout.update(
shapes=[{'type': 'line',
'y0':y_intercept,' y1': y_intercept,
'x0':str(df.x_value.min()), 'x1':str(df.x_value.max()),
'xref':'x' + str(i + 1), 'yref':'y' + str(i + 1),
'line': {'color': 'black', 'width': 1, 'dash': 'dot'}}
for i, member in enumerate(pd.unique(df.x_value))])
I was using go.Scatter to generate a plot. One solution, which is also clunky, for go is adding another plot with
trace2 = go.Scatter(
x = [df.Date.min(),df.Date.max()],
y = [df.Close.mean(),df.Close.mean()]
mode = "lines",
name = "Close price",
marker = dict(color = 'rgba(80, 26, 80, 0.8)')
)
.add_hlines() is just finding the x_min and x_max with two fixed y .add_vlines() vice versa. BTW, looking forward to upcoming versions!
It somehow bugs with Plotly Express with multiple facets:
{
"type": "line",
"yref": "paper",
"y0": 0,
"y1": 50,
"xref": "x{}".format(i + 1),
"x0": -200,
"x1": -200,
"line": {
"color":"Red",
"width":1,
}
}
Workaround:
counts, _ = np.histogram(df["data"], bins=bins)
max_bin_count = counts.max()
....
{
"type": "line",
"yref": "y{}".format(i + 1),
"y0": 0,
"y1": max_bin_count,
"xref": "x{}".format(i + 1),
"x0": -200,
"x1": -200,
"line": {
"color":"Red",
"width":1,
}
}
Ref: https://plotly.com/python/histograms/#accessing-the-counts-yaxis-values
Is there a way to add a label on the x-axis for each vertical line?
I would like to know too.
In R, there is an easy way that could be adapted to python.
vline <- function(x = 0, color = "red") {
list(
type = "line",
y0 = 0,
y1 = 1,
yref = "paper",
x0 = x,
x1 = x,
line = list(color = color)
)
}
hline <- function(y = 0, color = "blue") {
list(
type = "line",
x0 = 0,
x1 = 1,
xref = "paper",
y0 = y,
y1 = y,
line = list(color = color)
)
}
plot_ly() %>%
layout(shapes = list(vline(4), hline(5)))
@SpyderRivera thanks!
We've got a PR almost ready to merge that introduces a fig.add_hline(y=...)
API which will make this much easier... should be out in Plotly.py 4.11 by the end of September. Stay tuned! :)
added a horizontal line using fig.add_shape(), however, the line was disabled once i specified the 'seaborn' template, is there a way around this? @nicolaskruchten, thanks in advance
@SpyderRivera thanks!
We've got a PR almost ready to merge that introduces a
fig.add_hline(y=...)
API which will make this much easier... should be out in Plotly.py 4.11 by the end of September. Stay tuned! :)
great to hear that! I'm looking forward for 4.11 release! are there any dates already?
This feature has been moved to 4.12, but I estimate that within 2 weeks we should have it out :)
OK took longer than two weeks, sorry folks :) But it's out now in 4.12! https://community.plotly.com/t/announcing-plotly-py-4-12-horizontal-and-vertical-lines-and-rectangles/46783
@nicolaskruchten @SpyderRivera so the hline method works in a single line plot. However I have 2 lines with 2 differnt scales..of which I want to add an hline according to the 2nd rrighter scale...though this doesnt work:
plot %>% layout(yaxis2 = list(shapes = list(hline(10))))
Any help?
plot%>% layout(shapes = list(hline(10))) does work but only for the left 1st scale
OK took longer than two weeks, sorry folks :) But it's out now in 4.12! https://community.plotly.com/t/announcing-plotly-py-4-12-horizontal-and-vertical-lines-and-rectangles/46783
Guys, you all rock. Thanks for your dedication and commitment :tada:
Hi! I have found add_hline doesn't work when ploting it with dash :(
This will work with recent versions of Dash: I recommend upgrading to the latest, which is 1.20 :)
Hi @nicolaskruchten , thanks for the support. Well, I do actually have the latest version of dash, I also noted I am not using plotly express, I am using graphic objects. But still can't get the add_hline or add_vline working.
@self.app.callback(
Output(_id, 'figure'),
[Input(_id, 'id'),
Input('update_interval', 'n_intervals')]
)
def callback(component_id, _):
graph = next(component for component in components if component.id == component_id)
figure = go.Figure()
lines = graph.get_lines()
for line in lines:
if isinstance(line, VectorLine):
figure.add_trace(go.Scatter(
x=[point[0] for point in line.vector],
y=[point[1] for point in line.vector],
name=line.title,
mode='lines',
))
if isinstance(line, HLine):
figure.add_hline(line.y,
annotation_text=line.title,
annotation_position="bottom right")
if isinstance(line, VLine):
figure.add_vline(line.x)
figure.layout = go.Layout(title=graph.title, height=700)
return figure
The thing is, if I do a figure.show() I get the horizontal line.
Solved, The layout must be set before hlines and vlines are added.
To be precise: setting the layout to some value will overwrite what add_*line
added to the pre-existing layout, yes :)
Something similar to this https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.axes.Axes.axhline.html
Is there any intention for this to be added or should we go through accessing layout?