Use Qwebengineview To Display Something Larger Than 2mb?
I'm trying to display some Plot.ly or Plot.ly Dash plots ( I haven't settled on using one or the other, so I'm experimenting with both right now) in a PyQt5 GUI using QWebEngineVie
Solution 1:
As this answer indicates a possible solution is to use a QWebEngineUrlSchemeHandler
, in the next section I have created a class that allows you to register functions that are invoked through custom urls:
qtplotly.py
from PyQt5 import QtCore, QtWebEngineCore, QtWebEngineWidgets
import plotly.offline as po
import plotly.graph_objs as go
classPlotlySchemeHandler(QtWebEngineCore.QWebEngineUrlSchemeHandler):
def__init__(self, app):
super().__init__(app)
self.m_app = app
defrequestStarted(self, request):
url = request.requestUrl()
name = url.host()
if self.m_app.verify_name(name):
fig = self.m_app.fig_by_name(name)
ifisinstance(fig, go.Figure):
raw_html = '<html><head><meta charset="utf-8" />'
raw_html += '<script src="https://cdn.plot.ly/plotly-latest.min.js"></script></head>'
raw_html += "<body>"
raw_html += po.plot(fig, include_plotlyjs=False, output_type="div")
raw_html += "</body></html>"
buf = QtCore.QBuffer(parent=self)
request.destroyed.connect(buf.deleteLater)
buf.open(QtCore.QIODevice.WriteOnly)
buf.write(raw_html.encode())
buf.seek(0)
buf.close()
request.reply(b"text/html", buf)
return
request.fail(QtWebEngineCore.QWebEngineUrlRequestJob.UrlNotFound)
classPlotlyApplication(QtCore.QObject):
scheme = b"plotly"def__init__(self, parent=None):
super().__init__(parent)
scheme = QtWebEngineCore.QWebEngineUrlScheme(PlotlyApplication.scheme)
QtWebEngineCore.QWebEngineUrlScheme.registerScheme(scheme)
self.m_functions = dict()
definit_handler(self, profile=None):
if profile isNone:
profile = QtWebEngineWidgets.QWebEngineProfile.defaultProfile()
handler = profile.urlSchemeHandler(PlotlyApplication.scheme)
if handler isnotNone:
profile.removeUrlSchemeHandler(handler)
self.m_handler = PlotlySchemeHandler(self)
profile.installUrlSchemeHandler(PlotlyApplication.scheme, self.m_handler)
defverify_name(self, name):
return name in self.m_functions
deffig_by_name(self, name):
return self.m_functions.get(name, lambda: None)()
defregister(self, name):
defdecorator(f):
self.m_functions[name] = f
return f
return decorator
defcreate_url(self, name):
url = QtCore.QUrl()
url.setScheme(PlotlyApplication.scheme.decode())
url.setHost(name)
return url
main.py
import numpy as np
import plotly.graph_objs as go
from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets
from qtplotly import PlotlyApplication
# PlotlyApplication must be created before the creation# of QGuiApplication or QApplication
plotly_app = PlotlyApplication()
@plotly_app.register("scatter")defscatter():
t = np.arange(0, 200000, 1)
y = np.sin(t / 20000)
fig = go.Figure(data=[{"type": "scattergl", "y": y}])
return fig
@plotly_app.register("scatter2")defscatter2():
N = 100000
r = np.random.uniform(0, 1, N)
theta = np.random.uniform(0, 2 * np.pi, N)
fig = go.Figure(
data=[
{
"type": "scattergl",
"x": r * np.cos(theta),
"y": r * np.sin(theta),
"marker": dict(color=np.random.randn(N), colorscale="Viridis"),
}
]
)
return fig
@plotly_app.register("scatter3")defscatter3():
x0 = np.random.normal(2, 0.45, 30000)
y0 = np.random.normal(2, 0.45, 30000)
x1 = np.random.normal(6, 0.4, 20000)
y1 = np.random.normal(6, 0.4, 20000)
x2 = np.random.normal(4, 0.3, 20000)
y2 = np.random.normal(4, 0.3, 20000)
traces = []
for x, y in ((x0, y0), (x1, y1), (x2, y2)):
trace = go.Scatter(x=x, y=y, mode="markers")
traces.append(trace)
fig = go.Figure(data=traces)
return fig
classWidget(QtWidgets.QWidget):
def__init__(self, parent=None):
super().__init__(parent)
self.m_view = QtWebEngineWidgets.QWebEngineView()
combobox = QtWidgets.QComboBox()
combobox.currentIndexChanged[str].connect(self.onCurrentIndexChanged)
combobox.addItems(["scatter", "scatter2", "scatter3"])
vlay = QtWidgets.QVBoxLayout(self)
hlay = QtWidgets.QHBoxLayout()
hlay.addWidget(QtWidgets.QLabel("Select:"))
hlay.addWidget(combobox)
vlay.addLayout(hlay)
vlay.addWidget(self.m_view)
self.resize(640, 480)
@QtCore.pyqtSlot(str)defonCurrentIndexChanged(self, name):
self.m_view.load(plotly_app.create_url(name))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
# Init_handler must be invoked before after the creation# of QGuiApplication or QApplication
plotly_app.init_handler()
w = Widget()
w.show()
sys.exit(app.exec_())
Structure:
├── main.py
└── qtplotly.py
Output:
Post a Comment for "Use Qwebengineview To Display Something Larger Than 2mb?"