I want to use QVTKRenderWindowInteractor
for displaying some 3D data and, in the same app but in tab viewer, I want to have QWebEngineView
to render interactive bokeh plots, i.e. each visualization has its own tab.
It seems not possible, however. Both widgets work ok when separated, but QWebEngineView
is not rendered once I put both to the same app where I have QVTKRenderWindowInteractor
.
I tried:
- First creating
QWebEngineView
and thenQVTKRenderWindowInteractor
and vice versa. - I tried to use the following lines in case the problem is that both are trying to use GPU.
os.environ["QTWEBENGINE_DISABLE_GPU"] = "1"
os.environ["QTWEBENGINE_CHROMIUM_FLAGS"] = "--disable-gpu --disable-software-rasterizer"
I have seen this workaround - Cannot use QVTKRenderWindowInteractor and QWebEngineView together in one application.. But I would like to find some easier workaround if possible.
Questions:
- Is the problem that they are fighting for GPU or rather for some other resource?
- Can there be some other workaround instead of embedding code?
- Can I use something else other than
QWebEngineView
that would not create conflict but would allow me to create interactive plots? I have thought about rendering png and just setting it as image to some simpler widgets, but sadly it is not possible as I really need user to have possibility to interactively navigate in the plot. - Does it help that the visualizations are in different tabs, i.e. user does not see them simultaneously? Can I somehow “stop” one visualization when closing the corresponding tab, but without long waiting time for switching tabs?
- Any other alternative to bokeh that does not require
QWebEngineView
to render and thus does not create conflict?
Problem in MRE below. I am on Windows 11, Python 3.11. I need to render VTK on GPU but I am ok with non-GPU rendering for QWebEngineView
.
import sys
import xyzservices.providers as xyz
from PySide6.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget, QTabWidget
from PySide6.QtWebEngineWidgets import QWebEngineView
from bokeh.plotting import figure
from bokeh.resources import CDN
from bokeh.embed import file_html
from vtkmodules.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor
import vtk
class MapViewer(QWidget):
def __init__(self):
super().__init__()
tile_provider = xyz.OpenStreetMap.Mapnik
self.plot = figure(
x_range=(-2000000, 6000000),
y_range=(-2000000, 6000000),
x_axis_type="mercator",
y_axis_type="mercator",
sizing_mode="stretch_both",
)
self.plot.add_tile(tile_provider)
# Convert Bokeh plot to HTML
self.web_view = QWebEngineView()
html = file_html(self.plot, CDN, "Bokeh Map")
self.web_view.setHtml(html)
layout = QVBoxLayout()
layout.addWidget(self.web_view)
self.setLayout(layout)
class VTKViewer(QWidget):
def __init__(self):
super().__init__()
self.vtk_widget = QVTKRenderWindowInteractor(self)
layout = QVBoxLayout()
layout.addWidget(self.vtk_widget)
self.setLayout(layout)
# Setup VTK Renderer
self.renderer = vtk.vtkRenderer()
self.vtk_widget.GetRenderWindow().AddRenderer(self.renderer)
self.iren = self.vtk_widget.GetRenderWindow().GetInteractor()
# Create a random 3D VTK Object (Sphere)
sphere = vtk.vtkSphereSource()
sphere.SetRadius(5.0)
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(sphere.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)
actor.GetProperty().SetColor(0, 1, 0)
self.renderer.AddActor(actor)
self.renderer.SetBackground(0.1, 0.1, 0.1)
self.iren.Initialize()
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Tab Widget with Bokeh Map and VTK 3D")
self.tabs = QTabWidget()
# Tab 1: Bokeh Map Viewer
self.map_viewer = MapViewer()
# Tab 2: VTK Viewer
self.vtk_viewer = VTKViewer()
self.tabs.addTab(self.map_viewer, "Map Viewer")
self.tabs.addTab(self.vtk_viewer, "VTK 3D Viewer")
self.setCentralWidget(self.tabs)
self.resize(1200, 800)
if __name__ == "__main__":
app = QApplication(sys.argv)
main_win = MainWindow()
main_win.show()
sys.exit(app.exec())