ImageView setPxMode - Am I doing it wrong?

128 views
Skip to first unread message

Kevin Dunphy

unread,
Apr 30, 2021, 2:17:23 PM4/30/21
to pyqtgraph
Hey guys,

I am creating a program to visualize spectrograms of audio files with different processing parameters (i.e. fft size, overlap, etc.). I have a test file that shows some whale sounds, and so far everything is working as I expect. Here is a screenshot of things working as intended:

spectrogram_working_as_intended.png

I would like to have the option of displaying the data in a 1:1 pixel format, that is for each data point in the underlying image data, I want to display a single pixel. In the above example, the image is 2048 x 1163. I tried using the setPxMode(True) for the ImageItem I am using, however that does not appear to do what I expect. See the output:

spectrogram_one_to_one_broken.png

I expected the axes to change scale, with the X and Y axes showing only a fraction of the full range. I have tried changing the ImageItem's transform  from the current scale (freq_res, time_res) to a transform of (1, 1) however that also does not appear to change anything. I feel like I am close to what I want to do, but I am a bit stumped - Can anyone help out here?

Patrick

unread,
May 1, 2021, 2:13:23 AM5/1/21
to pyqtgraph
Hi,

I think the behaviour you are wanting is actually a little harder to implement than you may think, because the pixel indices aren't the same as your x or y-axis labels. That is, setPxMode(True) ignores the image scaling (which is used to make the image pixels line up with the correct values on the axes labels). To keep the image data mapping 1:1 with screen pixels you may need to hook into the plot's view box resize signals, get the new size of the view area (in screen pixel units), then use a plot.setLimits(....) to set the plot axes viewport (in time/frequency units). You can also set the maxXRange equal to minXRange etc of setLimits() so that the viewport can be panned, but not zoomed, to preserve the pixel size.
You'll need to hook the viewbox resize signal because if the user changes the window size, the plot area will change and you'll need to recalculate the correct axis limits etc again.
You may be able to use setPxMode(True) to keep the 1:1 pixel mapping, but you'll still have the problem of keeping the axes labels aligned with the image data when the axes are zoomed/resized.

Additionally, why setPxMode(True) is making the image small and at the bottom of the screen is, again, that it ignores the image transform, which includes an inversion of the y-axis so that the image data gets plotted "upwards" to match the direction of the y-axis. Your image is there, just that it extends downwards off the plot instead of upwards into that blank space. If you use the setPxMode(True) method, then you'll need to position your image accordingly.

Maybe there's an easier way to do this that I haven't thought of, but hopefully the above should give you something that works...

Patrick
Reply all
Reply to author
Forward
0 new messages