I have a line viewer made in PyQt5
; I managed to make a vispy
scene as the viewport for the QGrapichsView
. I have made it zoom and pan capable.
Problem
The viewer works very fast but the problem comes when I try to manually (push the fullscreen button in the right upper corner) the QgrapichsView (main widget) resize fine, but the sceneCanvas from vispy does not resize and stay the same.
states
before the manual fullscreen click, anyways this is not well positioned try to pan or zoom and you will se there is a barrier in the rigth side.
after the fullscreen it goes to the bottom left and does not rezize.
This code comes from needing to use a faster approach to show many lines, but now the problem is the correct positioing of the canvas.
What I have tried
Mainly, I have made a signal from the QgrapichsView
resize event to pass to the vispy
canvas, but it just wont work.
Code
import sys
from PyQt5.QtGui import QPainter, QPaintEvent
from PyQt5 import QtCore
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QGraphicsView, QApplication
import vispy.scene
from vispy.scene import visuals
import numpy as np
def dummy_generator(num_points, max_points):
from scipy.spatial import Voronoi
# Define las dimensiones
city_width = 8000
city_height = 6000
points = np.random.rand(num_points, 2) * np.array([city_width, city_height])
# Calcula el diagrama de Voronoi de los puntos para generar los bordes de los predios
vor = Voronoi(points)
# Crea una lista de coordenadas de vértices para cada polilínea que representa los bordes de los predios
polylines = []
pos_arr = []
for ridge in vor.ridge_vertices:
if ridge[0] >= 0 and ridge[1] >= 0:
x1, y1 = vor.vertices[ridge[0]]
x2, y2 = vor.vertices[ridge[1]]
if x1 < 0 or x1 > city_width or y1 < 0 or y1 > city_height:
continue
if x2 < 0 or x2 > city_width or y2 < 0 or y2 > city_height:
continue
# Genera puntos intermedios en la línea para obtener polilíneas más suaves
val = np.random.randint(3, max_points)
xs = np.linspace(x1, x2, num=val)
ys = np.linspace(y1, y2, num=val)
polyline = [(xs[i], ys[i]) for i in range(val)]
points = np.array(polyline).T
polylines.append(points)
pos_arr.append(max(points.shape))
# Calculate the start and end indices of each contour
pos_arr = np.array(pos_arr) - 1
fill_arr = np.ones(np.sum(pos_arr)).astype(int)
zero_arr = np.zeros(len(pos_arr)).astype(int)
c = np.insert(fill_arr, np.cumsum(pos_arr), zero_arr)
connect = np.where(c == 1, True, False)
coords = np.concatenate(polylines, axis=1)
return coords.T, connect
class VispyViewport(QGraphicsView):
def __init__(self, parent=None):
super().__init__(parent)
self.scale_factor = 1.5
self.setRenderHint(QPainter.Antialiasing)
self.setInteractive(True)
# Create a VisPy canvas and add it to the QGraphicsView
# self.canvas = canvas = vispy.scene.SceneCanvas( app='pyqt5', show=True, size=(2100, 600))
self.canvas = canvas = vispy.scene.SceneCanvas(app='pyqt5', show=True)
vispy_widget = canvas.native
vispy_widget.setParent(self)
# Set the VisPy widget as the viewport for the QGraphicsView
self.setViewport(vispy_widget)
self.setGeometry(QtCore.QRect(0,0, 2100,600))
# Create a grid layout and add it to the canvas
grid = canvas.central_widget.add_grid()
# Create a ViewBox and add it to the grid layout
self.view_vispy = grid.add_view(row=0, col=0, bgcolor='#c0c0c0')
self.grid = self.canvas.central_widget.add_grid()
line_data, connect = dummy_generator(5000, 50)
self.line = visuals.Line(line_data, parent=self.view_vispy.scene, connect=connect, color=(0.50196, 0.50196, 0.50196, 1))
self.view_vispy.camera = vispy.scene.PanZoomCamera()
self.view_vispy.camera.set_range()
self.view_vispy.camera.aspect = 1.0
#get m transformer
self.tform = self.view_vispy.scene.transform
def wheelEvent(self, event):
# Get the center of the viewport in scene coordinates
pos = event.pos()
# Determine the zoom factor
if event.angleDelta().y() > 0:
zoom_factor = 1 / self.scale_factor
else:
zoom_factor = self.scale_factor
#map to vispy coordinates
center = self.tform.imap((pos.x(), pos.y(), 0))
#apply zoom factor to a center anchor
self.view_vispy.camera.zoom(zoom_factor, center=center)
def mousePressEvent(self, event):
if event.button() == Qt.MiddleButton:
self.setDragMode(QGraphicsView.ScrollHandDrag)
self.setInteractive(True)
self.mouse_press_pos = event.pos()
self.mouse_press_center = self.view_vispy.camera.center[:2]
else:
super().mousePressEvent(event)
def mouseReleaseEvent(self, event):
if event.button() == Qt.MiddleButton:
self.setDragMode(QGraphicsView.NoDrag)
self.setInteractive(False)
else:
super().mouseReleaseEvent(event)
def mouseMoveEvent(self, event):
if self.dragMode() == QGraphicsView.ScrollHandDrag:
# Get the difference in mouse position
diff = event.pos() - self.mouse_press_pos
# Get the movement vector in scene coordinates
move_vec = self.tform.imap((diff.x(), diff.y())) - self.tform.imap((0, 0))
# Apply panning and set center
self.view_vispy.camera.center = (self.mouse_press_center[0] - move_vec[0], self.mouse_press_center[1] - move_vec[1])
else:
super().mouseMoveEvent(event)
def paintEvent(self, event: QPaintEvent) -> None:
# force send paintevent
self.canvas.native.paintEvent(event)
return super().paintEvent(event)
if __name__ == '__main__':
app = QApplication(sys.argv)
view = VispyViewport()
view.show()
# Start the Qt event loop
sys.exit(app.exec_())