Plotly:使用范围滑块时自动调整 y 轴范围

问题描述 投票:0回答:1

经过长时间的搜索,我找不到任何线程/讨论来帮助我使 autoscaling 与plotly一起工作。

这个想法是,当我使用 x 范围滑块浏览数据时,每次移动滑块时 y 轴都会动态重新缩放。

目前,它是这样的(相当无用):

这是我的代码片段:

fig = plt.figure()
    
    # Layout format and buttons
    layout = dict(
        xaxis=dict(
            rangeselector=dict(
                buttons=list([
                    dict(count=1,
                         label='1m',
                         step='month',
                         stepmode='backward'),
                    dict(count=6,
                         label='6m',
                         step='month',
                         stepmode='backward'),
                    dict(count=1,
                        label='YTD',
                        step='year',
                        stepmode='todate'),
                    dict(count=1,
                        label='1y',
                        step='year',
                        stepmode='backward'),
                    dict(step='all')
                ])
            ),
            rangeslider=dict(
                visible = True
            ),
            type='date'
        )
    )
    
    # Plot open, high, low, close for each coins
    for c in dic.keys():
        ohlc = dic[c][['open','high','low','close']].copy()
        
        candlestick = go.Candlestick(x = ohlc.index,
                                     open = ohlc['open'],
                                     high = ohlc['high'],
                                     low = ohlc['low'],
                                     close = ohlc['close'],
                                     name = 'OHLC')
        
        fig = go.Figure(data = [candlestick],
                        layout = layout)
        
        fig.update_yaxes(showgrid=True, 
                          zeroline=False, 
                          showticklabels=True,
                          showspikes=True, 
                          spikemode='across', 
                          spikesnap='cursor', 
                          spikethickness=1, 
                          showline=True, 
                          spikedash='dot',
                          spikecolor="#707070",
                          autorange = True,     # DOESN'T WORK....
                          fixedrange= False     # DOESN'T WORK....
                          )
            
        fig.update_xaxes(showgrid=True, 
                          zeroline=False, 
                          showticklabels=True,
                          showspikes=True, 
                          spikemode='across', 
                          spikesnap='cursor', 
                          spikethickness=1, 
                          showline=True, 
                          spikedash='dot',
                          spikecolor="#707070",
                          type='date',
                          )
        
        fig.update_layout(title = 'OHLC for: '+c,
                          height = 750,
                          plot_bgcolor="#FFFFFF",
                          hovermode="x",
                          hoverdistance=100,
                          spikedistance=1000,
                          xaxis_rangeslider_visible=True,
                          dragmode='pan',
                          )
        
        fig.show()

我尝试使用

autorange = True
fixedrange = False
但显然这没有任何作用,原因我不明白。

预先感谢您的帮助!

plotly autoscaling yaxis
1个回答
0
投票

Plotly.py 的交互式渲染器使用 Plotly.js 显示数字,因此我们可以挂钩

plotly_relayout
事件,并在需要时通过将适当的 javascript 代码传递给
.show()
方法来重新缩放 y 轴范围,这要归功于
post_script 
参数。我在这里提供了一个 JS/Plotly.js 解决方案,然后是 Python 解决方案,因为它包含嵌入 JS 代码。

请注意,您可能需要根据实际 OHLC 数据分辨率调整

formatDateRange()
函数(在这两种情况下)(请参阅评论)。

Plotly.js

Plotly.newPlot('<plot_id>', data, layout).then(gd => {

  gd.on('plotly_relayout', (e) => {
    if (e['yaxis.range'] || e['yaxis.autorange'] || e.autosize || e.width || e.height) {
      return;
    }

    if (e['xaxis.autorange']) {
      Plotly.relayout(gd, {'yaxis.autorange': true});
      return;
    }

    // NB. `formatDateRange()` depends on your OHLC data resolution (assuming one 
    // index per day here, formatted as 'yyyy-MM-dd'; but could be per hour, etc.) :
    // - Slider/zoom range uses datetime format 'yyyy-MM-dd hh:mm:ss.SSSS'
    // - need to match the date format 'yyyy-MM-dd'
    const formatDateRange = x => x.replace(/(\d{4}-\d{2}-\d{2}).*/, '$1');
    const xrange = gd._fullLayout.xaxis.range.map(formatDateRange);

    const ohlc = gd._fullData[0];
    let i0 = ohlc.x.indexOf(xrange[0]);
    let i1 = ohlc.x.indexOf(xrange[1]);

    if (i0 === -1) i0 = 0;
    if (i1 === -1) i1 = ohlc.x.length - 1;

    const data = [...ohlc.open.slice(i0, i1), ...ohlc.close.slice(i0, i1)];
    const ymin = Math.min(...data);
    const ymax = Math.max(...data);

    const room = Math.floor((ymax - ymin) / 20);
    const yrange = [ymin - room, ymax + room];

    Plotly.relayout(gd, {'yaxis.range': yrange});
  });
});

Plotly.py

# ... build `fig`

fig.update_layout(
    xaxis_rangeslider_visible=True,
    xaxis_rangeslider_yaxis_rangemode="auto" # so we can still see the big picture in the rangeslider plot
)

js = '''
const gd = document.getElementById('{plot_id}');

gd.on('plotly_relayout', (e) => {
    if (e['yaxis.range'] || e['yaxis.autorange'] || e.autosize || e.width || e.height) {
        return;
    }

    if (e['xaxis.autorange']) {
        Plotly.relayout(gd, {'yaxis.autorange': true});
        return;
    }

    const formatDateRange = x => x.replace(/(\d{4}-\d{2}-\d{2}).*/, '$1');
    const xrange = gd._fullLayout.xaxis.range.map(formatDateRange);

    const ohlc = gd._fullData[0];
    let i0 = ohlc.x.indexOf(xrange[0]);
    let i1 = ohlc.x.indexOf(xrange[1]);

    if (i0 === -1) i0 = 0;
    if (i1 === -1) i1 = ohlc.x.length - 1;

    const data = [...ohlc.open.slice(i0, i1), ...ohlc.close.slice(i0, i1)];
    const ymin = Math.min(...data);
    const ymax = Math.max(...data);

    const room = Math.floor((ymax - ymin) / 20);
    const yrange = [ymin - room, ymax + room];

    Plotly.relayout(gd, {'yaxis.range': yrange});
});

fig.show(post_script=[js])
'''


© www.soinside.com 2019 - 2024. All rights reserved.