簡體   English   中英

如何使用 Plotly.js 同步多個圖表的縮放級別?

[英]How do I synchronize the zoom level of multiple charts with Plotly.js?

我使用 Plotly.js 創建了 3 個時間序列圖,並且我希望保持縮放級別/平移同步,因此如果用戶縮放/平移 3 個圖中的任何一個,則其他 2 個得到更新。

現在我在第一個圖表上為plotly_relayout事件設置了一個事件處理程序。 事件處理程序使用傳入的事件數據調用其他兩個圖表上的Plotly.relayout

有誰知道如何確定哪個圖首先發出了plotly_relayout事件,這樣它就不會陷入處理自己事件的循環中? 或者也許有更好的方法來處理保持多個圖表之間的縮放/平移同步?

見筆在Plotly.js圖表鏈接放大活動由不寧頭腦工作室( @restlessmindsstudio上) CodePen

正如 Ashish Rathi 所注意到的,上述解決方案有一個錯誤 - 當您嘗試按下某些按鈕時,代碼執行會進入無限循環。 解決方案是在自己的重新布局處理程序中檢查 'ed' 變量,如果它沒有屬性 - 只是退出。 看起來在某些情況下 Plotly 發送帶有包含更新的空對象的 plotly_relayout 事件只是為了好玩 - 可能是某種錯誤。

在我的情況下,我不想讓 Y 縮放從一個圖傳播到另一個圖 - 因此我准備了一個單獨的結構,其中僅包含我想要傳播的那些屬性。

 var myDiv = document.getElementById("myDiv"); var myDiv2 = document.getElementById("myDiv2"); var myDiv3 = document.getElementById("myDiv3"); var startTime = new Date().getTime(); var timeStep = 60000; var myDivMax = 70; var myDiv2Max = 9000; var myDiv3Max = 500; var d3 = Plotly.d3, N = 40, x = d3.range(N).map(() => { return new Date((startTime += timeStep)); }), y = d3.range(N).map(() => Math.random() * myDivMax), data = [{ x: x, y: y }]; var layout = { height: 200, margin: { l: 45, t: 5, r: 45, b: 45 }, xaxis: { tickfont: { size: 10, color: "#7f7f7f" } }, yaxis: { fixedrange: true, tickfont: { size: 10, color: "#7f7f7f" } } }; var layout2 = { height: 200, margin: { l: 45, t: 5, r: 45, b: 45 }, xaxis: { tickfont: { size: 10, color: "#7f7f7f" } }, yaxis: { fixedrange: true, tickfont: { size: 10, color: "#7f7f7f" } } }; var layout3 = { height: 200, margin: { l: 45, t: 5, r: 45, b: 45 }, xaxis: { tickfont: { size: 10, color: "#7f7f7f" } }, yaxis: { fixedrange: true, tickfont: { size: 10, color: "#7f7f7f" } } }; Plotly.plot(myDiv, data, layout); var data2 = [{ x: x, y: d3.range(N).map(() => Math.random() * myDiv2Max) }]; Plotly.plot(myDiv2, data2, layout2); var data3 = [{ x: x, y: d3.range(N).map(() => Math.random() * myDiv3Max) }]; Plotly.plot(myDiv3, data3, layout3); var divs = [myDiv, myDiv2, myDiv3]; function relayout(ed, divs) { if (Object.entries(ed).length === 0) {return;} divs.forEach((div, i) => { let x = div.layout.xaxis; if (ed["xaxis.autorange"] && x.autorange) return; if (x.range[0] != ed["xaxis.range[0]"] ||x.range[1] != ed["xaxis.range[1]"]) { var update = { 'xaxis.range[0]': ed["xaxis.range[0]"], 'xaxis.range[1]': ed["xaxis.range[1]"], 'xaxis.autorange': ed["xaxis.autorange"], }; Plotly.relayout(div, update); } }); } var plots = [myDiv, myDiv2, myDiv3]; plots.forEach(div => { div.on("plotly_relayout", function(ed) { relayout(ed, divs); }); });
 <script src="https://cdn.plot.ly/plotly-latest.min.js"></script> <h2>Resize any chart, the others will get the same zoom level applied</h2> <div id="myDiv"></div> <div id="myDiv2"></div> <div id="myDiv3"></div>

我在此處復制@ChrisG 的評論,以表揚他並回答我的問題:

找到了一個更好的解決方案: https : //codepen.io/anon/pen/NXRpzW?editors=1010

 var myDiv = document.getElementById("myDiv"); var myDiv2 = document.getElementById("myDiv2"); var myDiv3 = document.getElementById("myDiv3"); var startTime = new Date().getTime(); var timeStep = 60000; var myDivMax = 70; var myDiv2Max = 9000; var myDiv3Max = 500; var d3 = Plotly.d3, N = 40, x = d3.range(N).map(() => { return new Date((startTime += timeStep)); }), y = d3.range(N).map(() => Math.random() * myDivMax), data = [{ x: x, y: y }]; var layout = { height: 200, margin: { l: 45, t: 5, r: 45, b: 45 }, xaxis: { tickfont: { size: 10, color: "#7f7f7f" } }, yaxis: { fixedrange: true, tickfont: { size: 10, color: "#7f7f7f" } } }; var layout2 = { height: 200, margin: { l: 45, t: 5, r: 45, b: 45 }, xaxis: { tickfont: { size: 10, color: "#7f7f7f" } }, yaxis: { fixedrange: true, tickfont: { size: 10, color: "#7f7f7f" } } }; var layout3 = { height: 200, margin: { l: 45, t: 5, r: 45, b: 45 }, xaxis: { tickfont: { size: 10, color: "#7f7f7f" } }, yaxis: { fixedrange: true, tickfont: { size: 10, color: "#7f7f7f" } } }; Plotly.plot(myDiv, data, layout); var data2 = [{ x: x, y: d3.range(N).map(() => Math.random() * myDiv2Max) }]; Plotly.plot(myDiv2, data2, layout2); var data3 = [{ x: x, y: d3.range(N).map(() => Math.random() * myDiv3Max) }]; Plotly.plot(myDiv3, data3, layout3); var divs = [myDiv, myDiv2, myDiv3]; function relayout(ed, divs) { divs.forEach((div, i) => { let x = div.layout.xaxis; if (ed["xaxis.autorange"] && x.autorange) return; if ( x.range[0] != ed["xaxis.range[0]"] || x.range[1] != ed["xaxis.range[1]"] ) Plotly.relayout(div, ed); }); } var plots = [myDiv, myDiv2, myDiv3]; plots.forEach(div => { div.on("plotly_relayout", function(ed) { console.log(ed); relayout(ed, divs); }); });
 <script src="https://cdn.plot.ly/plotly-latest.min.js"></script> <h2>Resize any chart, the others will get the same zoom level applied</h2> <div id="myDiv"></div> <div id="myDiv2"></div> <div id="myDiv3"></div>

根據@RMS(@ChrisG 的)和@Alex 的答案工作,當我想同時縮放 x 和 y 時仍然遇到問題(瀏覽器在放大方向之一或縮小時會完全凍結)。 我剛剛開始使用 js 來實現這個功能,但我通過這種方式使它適用於任何類型的縮放:

 var myDiv = document.getElementById("myDiv"); var myDiv2 = document.getElementById("myDiv2"); var myDiv3 = document.getElementById("myDiv3"); var startTime = new Date().getTime(); var timeStep = 60000; var myDivMax = 70; var myDiv2Max = 9000; var myDiv3Max = 500; var d3 = Plotly.d3, N = 40, x = d3.range(N).map(() => { return new Date((startTime += timeStep)); }), y = d3.range(N).map(() => Math.random() * myDivMax), data = [{ x: x, y: y }]; var layout = { height: 200, margin: { l: 45, t: 5, r: 45, b: 45 }, xaxis: { tickfont: { size: 10, color: '#7f7f7f' } }, yaxis: { tickfont: { size: 10, color: '#7f7f7f' } } }; var layout2 = { height: 200, margin: { l: 45, t: 5, r: 45, b: 45 }, xaxis: { tickfont: { size: 10, color: '#7f7f7f' } }, yaxis: { tickfont: { size: 10, color: '#7f7f7f' } } }; var layout3 = { height: 200, margin: { l: 45, t: 5, r: 45, b: 45 }, xaxis: { tickfont: { size: 10, color: '#7f7f7f' } }, yaxis: { tickfont: { size: 10, color: '#7f7f7f' } } }; Plotly.plot(myDiv, data, layout); var data2 = [{ x: x, y: d3.range(N).map(() => Math.random() * myDiv2Max) }]; Plotly.plot(myDiv2, data2, layout2); var data3 = [{ x: x, y: d3.range(N).map(() => Math.random() * myDiv3Max) }]; Plotly.plot(myDiv3, data3, layout3); var divs = [myDiv, myDiv2, myDiv3]; function relayout(ed, divs) { if (Object.entries(ed).length == 0) {return;} divs.forEach((div, i) => { let x = div.layout.xaxis; let y = div.layout.yaxis; var update = {}; if ("xaxis.autorange" in ed && ed["xaxis.autorange"] != x.autorange) { update['xaxis.autorange']= ed["xaxis.autorange"]; } if ("yaxis.autorange" in ed && ed["yaxis.autorange"] != y.autorange) { update['yaxis.autorange'] = ed["yaxis.autorange"]; } if ("xaxis.range[0]" in ed && ed["xaxis.range[0]"] != x.range[0]) { update['xaxis.range[0]'] = ed["xaxis.range[0]"]; } if ("xaxis.range[1]" in ed && ed["xaxis.range[1]"] != x.range[1]) { update['xaxis.range[1]'] = ed["xaxis.range[1]"]; } if ("yaxis.range[0]" in ed && ed["yaxis.range[0]"] != y.range[0]) { update['yaxis.range[0]'] = ed["yaxis.range[0]"]; } if ("yaxis.range[1]" in ed && ed["yaxis.range[1]"] != y.range[1]) { update['yaxis.range[1]'] = ed["yaxis.range[1]"]; } Plotly.relayout(div, update); }); } divs.forEach(div => { div.on("plotly_relayout", function(ed) {relayout(ed, divs);}); });
 <script src="https://cdn.plot.ly/plotly-latest.min.js"></script> <h2>Resize any chart, the others will get the same zoom level applied</h2> <div id="myDiv"></div> <div id="myDiv2"></div> <div id="myDiv3"></div>

這里還有一個 codepen 鏈接

類似的事情可以在 plotly dash 中完成。 代碼片段如下。

app=dash.Dash()

app.layout = html.Div([
            dcc.Graph(id='graph',figure=fig),
            html.Pre(id='relayout-data', style=styles['pre']),
            dcc.Graph(id='graph2', figure=fig)])

@app.callback(Output('relayout-data', 'children'),
              [Input('graph', 'relayoutData')])
def display_relayout_data(relayoutData):
    return json.dumps(relayoutData, indent=2)


@app.callback(Output('graph2', 'figure'),
             [Input('graph', 'relayoutData')], 
             [State('graph2', 'figure')])
def graph_event(select_data,  fig):
    try:
       fig['layout'] = {'xaxis':{'range':[select_data['xaxis.range[0]'],select_data['xaxis.range[1]']]}}
    except KeyError:
       fig['layout'] = {'xaxis':{'range':[zoomed out value]}}
return fig

app.run_server()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM