How to render Altair / Vega in a PyQt widget

不羁的心 提交于 2021-01-27 22:07:18

问题


Is it possible to have Altair or Vega(-Lite) render to a PyQt widget, similar to Matplotlib supporting multiple backends? I know I can use a Qt WebView widget to render a web page with Vega-embed, but I want to prevent the overhead of having to serve this, even if locally.


回答1:


The best option to visualize a plot with Altair is to use QWebEngineView since altair what is to create javascript code based on the instructions you set. IMHO the best solution is to obtain the html of the chart and set it in a QWebEngineView. In the following example I show how to do the above, in addition to enabling the characteristics of saving the image as svg or png, etc.

from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets

from io import StringIO


class WebEngineView(QtWebEngineWidgets.QWebEngineView):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.page().profile().downloadRequested.connect(self.onDownloadRequested)
        self.windows = []

    @QtCore.pyqtSlot(QtWebEngineWidgets.QWebEngineDownloadItem)
    def onDownloadRequested(self, download):
        if (
            download.state()
            == QtWebEngineWidgets.QWebEngineDownloadItem.DownloadRequested
        ):
            path, _ = QtWidgets.QFileDialog.getSaveFileName(
                self, self.tr("Save as"), download.path()
            )
            if path:
                download.setPath(path)
                download.accept()

    def createWindow(self, type_):
        if type_ == QtWebEngineWidgets.QWebEnginePage.WebBrowserTab:
            window = QtWidgets.QMainWindow(self)
            view = QtWebEngineWidgets.QWebEngineView(window)
            window.resize(640, 480)
            window.setCentralWidget(view)
            window.show()
            return view

    def updateChart(self, chart, **kwargs):
        output = StringIO()
        chart.save(output, "html", **kwargs)
        self.setHtml(output.getvalue())


if __name__ == "__main__":
    import sys

    import altair as alt
    from vega_datasets import data

    app = QtWidgets.QApplication(sys.argv)
    w = QtWidgets.QMainWindow()

    cars = data.cars()

    chart = (
        alt.Chart(cars)
        .mark_bar()
        .encode(x=alt.X("Miles_per_Gallon", bin=True), y="count()",)
        .properties(title="A bar chart")
        .configure_title(anchor="start")
    )

    view = WebEngineView()
    view.updateChart(chart)
    w.setCentralWidget(view)
    w.resize(640, 480)
    w.show()
    sys.exit(app.exec_())



回答2:


Currently the only rendering backend for Altair is Vega-Embed, so rendering it in a PyQt widget will require running some Javascript engine. I suspect that Qt WebView is probably the best option.

If you're OK losing interactivity of charts, you could also use altair_saver as a backend to store a static PNG, SVG, or PDF of the chart and show it within a QtWidget.



来源:https://stackoverflow.com/questions/60210035/how-to-render-altair-vega-in-a-pyqt-widget

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!