suvayu
suvayu

Reputation: 4664

QWebEngineView renders bokeh vizualisation with largish data (~18000 points) slowly

I'm trying to include a Bokeh based visualisation canvas in a Qt application written in Python (using PySide6). So I create the visualisation, save it in an HTML file, and read it in a QWebEngineView widget. It renders fine, but is extremely sluggish to interact with it; e.g. try selecting the zoom tool and zooming in, or panning. The surprising part is, when I open the same HTML in Firefox, it is pretty snappy, as I would expect.

There are 2 time series, with 8760 data points each in the plot. What is going on here?

Minimal example

from argparse import ArgumentParser
from pathlib import Path


from PySide6.QtCore import QUrl, QSize
from PySide6.QtWidgets import QApplication, QMainWindow
from PySide6.QtWebEngineWidgets import QWebEngineView


class MainWindow(QMainWindow):
    def __init__(self, path: str = "", *args, **kwargs):
        super().__init__(*args, **kwargs)

        if path:
            self.browser = QWebEngineView()
            self.browser.setUrl(QUrl.fromLocalFile(Path(path).absolute()))
            self.setCentralWidget(self.browser)
            self.resize(QSize(800, 500))


if __name__ == "__main__":
    # HTML example produced using Bokeh: dump-viz.html
    parser = ArgumentParser()
    parser.add_argument("file")
    opts = parser.parse_args()

    app = QApplication()
    window = MainWindow(opts.file)
    window.show()
    app.exec()

The above script, and an example HTML is available in this gist.

You can run it with hatch run pyside-qwebengine-slow.py qwebengine-ex-viz.html, or create a virtual env, then pip install PySide6, and run normally.

Additional info

The code that I use to generate that plot, is more or less equivalent to:

def make_plot(data_list)
    """`data_list`: list of dataclasses representing a time series;
    data.y, data.labels, etc.
    """
    palette = TolRainbow[10]
    cds = ColumnDataSource(data=pd.DataFrame({data.labels[0]: data.y for data in data_list}))
    legend_items = {}
    fig = figure(x_axis_label="x_label", y_axis_label="y_label", title="title", height=400, width=800)
    for idx, data in enumerate(data_list):
        line = fig.line("index", data.labels[0], source=cds, color=palette[idx])
        point = fig.scatter("index", data.labels[0], source=cds, color=palette[idx], size=7)
        legend_items[data.labels[0]] = [line, point]

    legend = Legend(items=list(legend_items.items()))
    fig.add_layout(legend, "right")
    fig.legend.click_policy = "hide"
    return fig

fig = make_plot(data_list)
html = file_html(fig, INLINE, title)

Upvotes: 0

Views: 84

Answers (0)

Related Questions