You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

QWebEngineView中Plotly图表无法同步的问题求助

解决PyQt5中QWebEngineView嵌入Plotly图表无法同步缩放/平移的问题

问题描述

将实现Plotly多图表同步缩放/平移的HTML代码,放入PyQt5的三个独立QWebEngineView组件后,图表的平移或缩放操作完全没有同步效果,但单独运行该HTML文件时功能正常。已尝试更新Plotly、QWebEngineView及清除缓存,均无效。

问题根源

每个QWebEngineView都对应一个独立的浏览器JavaScript运行环境,三个视图之间的JS上下文完全隔离。原代码中监听的plotly_relayout事件只能在当前视图内部生效,无法跨视图传递同步信号,因此三个图表无法联动。

解决方案

使用单个QWebEngineView加载包含三个图表的HTML页面,让所有图表处于同一个JS运行环境中,这样事件监听和同步逻辑就能正常工作。

修正后的代码

import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget
from PyQt5.QtWebEngineWidgets import QWebEngineView

class SynchronizedPlotWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        # 只使用一个Web视图加载包含三个图表的页面
        self.graph_view = QWebEngineView()

        # 加载包含同步图表的HTML内容
        html_content = """
        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>Plotly Synchronized Charts</title>
            <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
        </head>
        <body>
            <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>
            <script>
                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>
        </body>
        </html>
        """

        self.graph_view.setHtml(html_content)

        # 布局设置
        layout = QVBoxLayout()
        layout.addWidget(self.graph_view)

        container = QWidget()
        container.setLayout(layout)
        self.setCentralWidget(container)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = SynchronizedPlotWindow()
    window.show()
    sys.exit(app.exec_())

内容的提问来源于stack exchange,提问作者Diego Alexis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 01:54:54