我使用Plotly.js创建了3个时间序列图,我想保持缩放级别/平移同步,所以如果用户放大/平移3个图中的任何一个,则另外2个会更新。
现在我在plotly_relayout
事件的第一个图表上设置了一个事件处理程序。事件处理程序使用传入的事件数据在另外两个图表上调用Plotly.relayout
。
有没有人知道如何识别首先发出plotly_relayout
事件的情节,以便它不会陷入处理自己事件的循环中?或者可能有更好的方法来处理多个图表之间的缩放/平移同步?
答案 0 :(得分:0)
我在这里复制@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>
答案 1 :(得分:0)
正如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>
答案 2 :(得分:-1)
类似的事情可以用破折号来完成。代码段如下。
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()