pythongpuvispy

Plot 1d histogram data using vispy


First, I tried plotting histogram using visuals.HistogramVisual, I am getting some weird window. Here is the code :

from vispy import app, visuals
import numpy as np
import sys
import time
from PyQt5.QtWidgets import *

class snrHistogram(app.Canvas):
    def __init__(self, *args, **kwargs):
        app.Canvas.__init__(self, title='histogram fail',
                            keys="interactive", size=(300, 300))

        self.snr_hist = visuals.HistogramVisual(
    np.repeat([0, 1, 1, 20, 20, 40, 40, 80, 80, 90], 400), bins=1, color='r', orientation='h')
        self.label = visuals.TextVisual("hi", color='blue', pos=[50, 50, 0])
        self.configure_transforms()
        #self.show()

    def configure_transforms(self):
        vp = (0, 0, self.physical_size[0], self.physical_size[1])
        self.context.set_viewport(*vp)
        self.label.transforms.configure(canvas=self, viewport=vp)
        self.snr_hist.transforms.configure(canvas=self, viewport=vp)

    def on_resize(self, event):
        self.configure_transforms()

    def on_mouse_wheel(self, event):
        self.update()

    def on_draw(self, event):
        self.snr_hist.draw()
        self.label.draw()
        self.update()

    def on_close(self, event):
        self.close()

class Window(QWidget):
    def __init__(self):
        super().__init__()
        self.layout = QHBoxLayout(self)
        start_time= time.time()
        s = snrHistogram()
        self.layout.addWidget(s.native)
        self.setLayout(self.layout)
        end_time = time.time()
        elapsed_time = end_time-start_time
        print("Elapsed time to plot hist is: ", elapsed_time)
        #self.setCentralWidget(self)
        self.show()

App= QApplication(sys.argv)
window = Window()
sys.exit(App.exec_())

here is the output of it, Why I am getting like this? Where am I wrong?, enter image description here

Further, I have 1D data which was computed in GPU and stored in GPU memory and I want to plot histogram using the same data(which stored in GPU memory). since vispy has access to GPU, is it directly take data or should I download data to GPU and plot again? How exactly it will work?

Any leads will be appreciated.

UPDATE I want to plot something like this, two histogram plots in single figure. I can do it in matplot and also in pyqtgraph. Here is the sample of it, sample histogram want in vispy


Solution

  • Do you have an example of what you're expecting to see?

    I ran your example code and it looks like VisPy's histogram orientation is actually backwards. This is drawing a vertical histogram (bins axis on the bottom, number on the side). I just filed a bug in the VisPy repository on this here. I'm not sure how it went this long without being noticed...unless I'm missing something.

    Anyway, the main issue seems to be the transform(s) of your Visual. What you're seeing is actually one large single bin histogram that starts in the lower-left and goes outside the Canvas/viewport. I'll be honest that I rarely use the HistogramVisual or numpy's histogram functions (which the Visual is using underneath). It is possible that since this Visual was written things have changed in numpy.

    Anyway, here are the changes I made:

    1. Add from vispy.visuals.transforms import STTransform
    2. Change bins to 5 and orientation to v`.
    3. Add the following line to the bottom of configure_transforms:
            self.snr_hist.transform = STTransform(scale=(300 / 1200.0, 300 / 90.0, 1.0))
    

    The 300 values in this line come from the size of your canvas. The 1200.0 and 90.0 I got from printing out the values that numpy gave from calling np.histogram here: https://github.com/vispy/vispy/blob/main/vispy/visuals/histogram.py

    In my opinion this Visual needs a major rewrite so that you can control more of the histogram keyword arguments, but probably most importantly control the normalization of the bin sizes.

    Further, I have 1D data which was computed in GPU and stored in GPU memory and I want to plot histogram using the same data(which stored in GPU memory). since vispy has access to GPU, is it directly take data or should I download data to GPU and plot again? How exactly it will work?

    How was your data computed/generated in the GPU? CUDA? OpenCL? The short answer is that no there is no way to draw with vispy without copying the data to the CPU and resending it to the GPU through VisPy. The longer answer is that this is something I'm working on with PyCUDA in my free time...I just don't have much free time.

    Update

    Here's the top part of my updated code

    from vispy import app, visuals
    import numpy as np
    import sys
    import time
    from PyQt5.QtWidgets import *
    from vispy.visuals.transforms import STTransform
    
    class snrHistogram(app.Canvas):
        def __init__(self, *args, **kwargs):
            app.Canvas.__init__(self, title='histogram fail',
                                keys="interactive", size=(300, 300))
    
            self.snr_hist = visuals.HistogramVisual(
                np.repeat([0, 1, 1, 20, 20, 40, 40, 80, 80, 90], 400), bins=5, color='r', orientation='v')
                #np.repeat([0, 1, 1, 20, 20, 40, 40, 80, 80, 90], 400), bins=5, color='r', orientation='h')
            self.label = visuals.TextVisual("hi", color='blue', pos=[50, 50, 0])
            self.configure_transforms()
            #self.show()
    
        def configure_transforms(self):
            vp = (0, 0, self.physical_size[0], self.physical_size[1])
            self.context.set_viewport(*vp)
            self.label.transforms.configure(canvas=self, viewport=vp)
            self.snr_hist.transforms.configure(canvas=self, viewport=vp)
            self.snr_hist.transform = STTransform(scale=(300 / 1200.0, 300 / 90.0, 1.0))
    

    Running this (with the bottom portion of your original code) gives me:

    Histogram screenshots

    Where the red portion on the top is the first "bin", the portion below that is the second bin, and so on for a total of 5 bins. So the "bin" axis is "Y" axis, the quantity/amount axis is the "X" axis.