Skip to content

pcmi opengl: discard nan fragments#3170

Merged
j9ac9k merged 1 commit intopyqtgraph:masterfrom
pijyoi:pcmi-transparent-nan
Oct 24, 2024
Merged

pcmi opengl: discard nan fragments#3170
j9ac9k merged 1 commit intopyqtgraph:masterfrom
pijyoi:pcmi-transparent-nan

Conversation

@pijyoi
Copy link
Copy Markdown
Contributor

@pijyoi pijyoi commented Oct 17, 2024

#3114 defined nan values in PCMI to be transparent.
Update the OpenGL code-path to have the same behavior.

What this PR doesn't do:

  • In non-OpenGL code-path, cell borders are drawn together with the cell. Thus when a cell containing a nan is not filled, its border doesn't get drawn
  • In OpenGL code-path, cell borders are drawn as a grid using polylines. Thus even if a cell containing a nan is not filled, its border still gets drawn

Arguably, the non-OpenGL code-path behavior was just an accident. Either behavior makes sense.

Sample code adapted from #3090 to demonstrate nan pixels being transparent.

import importlib
import sys

import numpy as np

import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui
from pyqtgraph.examples.utils import FrameCounter

width = 128
pngfile = importlib.resources.files("pyqtgraph.icons.peegee") / f"peegee_{width}px.png"
qimage = QtGui.QImage.fromData(pngfile.read_bytes())
qimage_gray = qimage.convertedTo(QtGui.QImage.Format.Format_Grayscale8)
qimage_alpha = qimage.convertedTo(QtGui.QImage.Format.Format_Alpha8)
z = pg.functions.ndarray_from_qimage(qimage_gray)
a = pg.functions.ndarray_from_qimage(qimage_alpha)

z = z.astype(np.float32)
z[a < 255] = np.nan

Z = z
ny, nx = Z.shape
x = np.linspace(0, nx, nx+1, endpoint=True)
y = np.linspace(0, ny, ny+1, endpoint=True)
X, Y = np.meshgrid(x, y)
X += (ny * 0.025) * np.sin(2*np.pi*2*np.linspace(0, 1, ny+1))[:, np.newaxis]
Y += (nx * 0.025) * np.sin(2*np.pi*2*np.linspace(0, 1, nx+1))

pg.setConfigOptions(useOpenGL=True, enableExperimental=True)
pg.setConfigOption('background', pg.mkColor(0, 0, 100))

pg.mkQApp()
win = pg.PlotWidget()
win.invertY(True)
cmap = pg.colormap.ColorMap(None, [0.0, 1.0])
pcmi = pg.PColorMeshItem(X, Y, Z, colorMap=cmap)
win.addItem(pcmi)
win.setTitle('')
win.show()

cnt = 0
def update():
    global cnt
    cnt = (cnt + 1) % z.shape[1]
    Z = np.roll(z, cnt, axis=1)
    pcmi.setData(None, None, Z)
    framecnt.update()

timer = QtCore.QTimer()
timer.timeout.connect(update)
timer.start()

framecnt = FrameCounter()
framecnt.sigFpsUpdate.connect(lambda fps: win.setTitle(f'{fps:.1f} fps'))

pg.exec()

@j9ac9k
Copy link
Copy Markdown
Member

j9ac9k commented Oct 24, 2024

Thanks @pijyoi for this PR. This LGTM, merging!

@j9ac9k j9ac9k merged commit d760b22 into pyqtgraph:master Oct 24, 2024
@pijyoi pijyoi deleted the pcmi-transparent-nan branch October 24, 2024 21:25
@pijyoi
Copy link
Copy Markdown
Contributor Author

pijyoi commented Dec 10, 2024

https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.pcolormesh.html#differences-pcolor-pcolormesh

With regard to whether edges of nan cells should be rendered,

  • pyqtgraph's PColorMeshItem non-OpenGL codepath behavior is that of Matplotlib's pcolor. (edges are not rendered)
  • pyqtgraph's PColorMeshItem OpenGL codepath behavior is that of Matplotlib's pcolormesh. (edges are rendered)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants