0

I am trying to show X Y axis for an image. Axis information of the image shows incorrectly before pan/zoom activity. But as soon as you pan or zoom the image, axis comes out properly.

Below I was able to replicate same issue with Embed Vispy into QT example.

Please find modified code below:

"""
Embed VisPy into Qt
===================

Display VisPy visualizations in a PyQt5 application.

"""

import numpy as np
from PyQt5 import QtWidgets

from vispy.scene import SceneCanvas, visuals, AxisWidget
from vispy.app import use_app

IMAGE_SHAPE = (600, 800)  # (height, width)
CANVAS_SIZE = (800, 600)  # (width, height)
NUM_LINE_POINTS = 200


class MyMainWindow(QtWidgets.QMainWindow):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        central_widget = QtWidgets.QWidget()
        main_layout = QtWidgets.QHBoxLayout()

        self._controls = Controls()
        main_layout.addWidget(self._controls)
        self._canvas_wrapper = CanvasWrapper()
        main_layout.addWidget(self._canvas_wrapper.canvas.native)

        central_widget.setLayout(main_layout)
        self.setCentralWidget(central_widget)


class Controls(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        layout = QtWidgets.QVBoxLayout()
        self.colormap_label = QtWidgets.QLabel("Image Colormap:")
        layout.addWidget(self.colormap_label)
        self.colormap_chooser = QtWidgets.QComboBox()
        self.colormap_chooser.addItems(["viridis", "reds", "blues"])
        layout.addWidget(self.colormap_chooser)

        self.line_color_label = QtWidgets.QLabel("Line color:")
        layout.addWidget(self.line_color_label)
        self.line_color_chooser = QtWidgets.QComboBox()
        self.line_color_chooser.addItems(["black", "red", "blue"])
        layout.addWidget(self.line_color_chooser)

        layout.addStretch(1)
        self.setLayout(layout)


class CanvasWrapper:
    def __init__(self):
        self.canvas = SceneCanvas(size=CANVAS_SIZE)
        self.grid = self.canvas.central_widget.add_grid()

        self.view_top = self.grid.add_view(0, 1, bgcolor='cyan')
        image_data = _generate_random_image_data(IMAGE_SHAPE)
        self.image = visuals.Image(
            image_data,
            texture_format="auto",
            cmap="viridis",
            parent=self.view_top.scene,
        )
        self.view_top.camera = "panzoom"
        self.view_top.camera.set_range(
            x=(0, IMAGE_SHAPE[1]), y=(0, IMAGE_SHAPE[0]), margin=0)

        self.x_axis = AxisWidget(
            axis_label="X Axis Label", orientation='bottom')
        self.x_axis.stretch = (1, 0.1)
        self.grid.add_widget(self.x_axis, row=1, col=1)
        self.grid.padding = 0

        self.x_axis.link_view(self.view_top)
        self.y_axis = AxisWidget(
            axis_label="Y Axis Label", orientation='left')
        self.y_axis.stretch = (0.1, 1)
        self.grid.add_widget(self.y_axis, row=0, col=0)
        self.y_axis.link_view(self.view_top)


def _generate_random_image_data(shape, dtype=np.float32):
    rng = np.random.default_rng()
    data = rng.random(shape, dtype=dtype)
    return data


def _generate_random_line_positions(num_points, dtype=np.float32):
    rng = np.random.default_rng()
    pos = np.empty((num_points, 2), dtype=np.float32)
    pos[:, 0] = np.arange(num_points)
    pos[:, 1] = rng.random((num_points,), dtype=dtype)
    return pos


if __name__ == "__main__":
    app = use_app("pyqt5")
    app.create()
    win = MyMainWindow()
    win.show()
    app.run()

Below is the screenshot of the initial image which is generated.

Wrong Axis for Image

Once we do a pan or zoom on the canvas the axis corrects itself.

Kindly let me know what is to be done to get proper axis for the image.

ViNOJ
  • 15
  • 5
  • Looks like a bug; I tried to manually trigger a canvas update without using the mouse, but it's not fixing the problem, so it seems like some state is not correctly initialized. Could you open an issue on the repo with as small a reproducible example as you can? – Lorenzo Gaifas Apr 11 '23 at 07:55
  • 1
    OKay I will do that – ViNOJ Apr 11 '23 at 08:56
  • https://github.com/vispy/vispy/issues/2468 New issue opened for this – ViNOJ Apr 14 '23 at 06:33

1 Answers1

0

A solution was proposed by David Hoese (@djhoese) as a comment in Github issues:

It really seems it has to do with the order the widgets are added to the grid not when they are created. Here's the new relevant portion of the init method:

    image_data = _generate_random_image_data(IMAGE_SHAPE)
    self.image = visuals.Image(
        image_data,
        texture_format="auto",
        cmap="viridis",
        # parent=self.view_top.scene,
    )

    self.x_axis = AxisWidget(
        axis_label="X Axis Label", orientation='bottom')
    self.x_axis.stretch = (1, 0.1)

    self.y_axis = AxisWidget(
        axis_label="Y Axis Label", orientation='left')
    self.y_axis.stretch = (0.1, 1)

    self.grid.add_widget(self.x_axis, row=1, col=1)
    self.grid.add_widget(self.y_axis, row=0, col=0)
    self.view_top = self.grid.add_view(0, 1, bgcolor='cyan')
    self.image.parent = self.view_top.scene

    self.view_top.camera = "panzoom"
    self.x_axis.link_view(self.view_top)
    self.y_axis.link_view(self.view_top)

    self.view_top.camera.set_range(
        x=(0, IMAGE_SHAPE[1]), y=(0, IMAGE_SHAPE[0]), margin=0)

This works for me because the view_top is added after the axes widgets. Note that the camera has to be declared/set before the views are linked otherwise they are linked/attached to the wrong transform for changes.

If this helps you remember to thank David for his input.

Pawel Kam
  • 1,684
  • 3
  • 14
  • 30
ViNOJ
  • 15
  • 5