Plotly: how to make an unbounded vertical line in a subplot?

我的梦境 提交于 2020-08-24 10:29:11

问题


The goal is to get vertical infinite lines in every subplot, at x=1. In this example, I'll just try a single plotly shape of type="line" in the first row, first column

from plotly.subplots import make_subplots
import plotly.graph_objects as go
import numpy as np


fig = make_subplots(
    rows=2,
    cols=2,
    subplot_titles=list(map(str, range(4))),
    shared_xaxes=True,
    shared_yaxes=False,
)

time = np.linspace(-np.pi, np.pi, 1000)

for i in range(4):
    data = np.sin((i+1) * time)
    fig.add_trace(
        go.Scatter(y=data,x=time, name=str(i)),
        row=1 if i in [0, 1] else 2,
        col=1 if i in [0, 2] else 2,
    )

fig.add_shape(
    go.layout.Shape(
        type="line",
        yref="paper",
        xref="x",
        x0=1,
        y0=0,
        x1=1,
        y1=1,
        line=dict(color="RoyalBlue", width=3),
    ),row=1,col=1)

fig.write_image("1.png",width=800, height=600, scale=1)

So it looks like adding a shape with row and column overrides the yref and xref properties, returning a segment of a line instead of an infinite line. Forcing yref to be "paper" before printing...

for shape in fig.layout.shapes:
    shape["yref"]="paper"

...I get this:

This is arguably worse, a line that's relative to the whole figure instead of the subplot y axis. Has anyone stumbled with this problem before? Any ideas?


回答1:


Is this your desired plot?

If that's the case then you'll have to inset a shape to each subplot defined by the positions row=i,col=j. The following snippet will do that for you. If you change the total numbers of subplots You'll just need to have som oversight of how your grid will look with regards to the numbers of rows and columns.

from plotly.subplots import make_subplots
import plotly.graph_objects as go
import numpy as np


fig = make_subplots(
    rows=2,
    cols=2,
    subplot_titles=list(map(str, range(4))),
    shared_xaxes=True,
    shared_yaxes=False,
)

time = np.linspace(-np.pi, np.pi, 1000)

for i in range(4):
    data = np.sin((i+1) * time)
    fig.add_trace(
        go.Scatter(y=data,x=time, name=str(i)),
        row=1 if i in [0, 1] else 2,
        col=1 if i in [0, 2] else 2,
    )

colors = ['blue', 'firebrick', 'green', 'purple']
rows = 2
cols = 2

# add traces
counter=0 # for colors
for i in range(1,3):
    for j in range(1,3):
        fig.add_shape(go.layout.Shape(type="line",
                                        yref="paper",
                                        xref="x",
                                        x0=1,
                                        y0=-2,
                                        x1=1,
                                        y1=2,
                                        #line=dict(color="RoyalBlue", width=3),),
                                        line=dict(color=colors[counter], width=3),),
                      row=i,
                      col=j)
        counter = counter + 1

fig.show()

Edit after comments:

To my knowledge, you can't define an unbounded directly. But what you're trying to accomplish will work pretty good as long as you define axis limits well beyond the data you want to visualize. Because contrary to your comment, you can set the axis limits of each subplot like this:

# Set y ranges for each subplot
for i in range(1,3):
    for j in range(1,3):
        fig.update_yaxes(range=[-4, 4], row=i, col=j)

And instead of predefined limits you can find the proper max and min values from your datasets.

Plot 2: Unzoomed

Plot 3: Zoomed out

I hope this is a bit more helpful!



来源:https://stackoverflow.com/questions/59214406/plotly-how-to-make-an-unbounded-vertical-line-in-a-subplot

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!