Repository: pyqtgraph/pyqtgraph

Issue:
PyQtGraph 0.1.14 takes approximately twice as long to plot colored points in a ScatterPlotItem that 0.1.13
In PyQtGraph version `0.13.4`, coloring points in a `ScatterPlotItem` with `brush` set to a long index of integers (to rotate over the default number of colors) takes approximately twice as long as in PyQtGraph `0.13.3`.

Example code:

```python
...
self.scatter = pg.ScatterPlotItem(
    size=5,
    pen=pg.mkPen(None),
    brush=pg.mkBrush(255, 255, 255, 128),  # To be overridden in the next call depending on a setting
    hoverable=True,
    hoverSymbol="s",
    hoverSize=5,
    hoverPen=pg.mkPen("w", width=2),
    hoverBrush=None,
)
...
self.scatter.addPoints(x=x, y=y, data=tid, brush=brushes,)  # Here brushes is equal to tid
``` 

For `x`, `y`, and `tid` of about 200,000 elements, and `np.unique(tid)` of approximately 600, on my machine PyQtGrpah `0.1.13` takes approximately **10 seconds** to plot all colored points, whereas `0.1.14` takes approximately **19 seconds**.

_Originally posted by @aarpon in https://github.com/pyqtgraph/pyqtgraph/issues/2719#issuecomment-1997515263_
            


Discussion:
I would guess that #2863 is the one affecting you.
1) Are you able to bisect the code to confirm that #2863 is the relevant PR affecting you?
2) Are you using a hi-dpi display? If yes, in the following lines, if you change self._dpr to your screen device pixel ratio, does it make a difference? https://github.com/pyqtgraph/pyqtgraph/blob/a4bf6061271bac2a69b94f09e577b52183e97681/pyqtgraph/graphicsItems/ScatterPlotItem.py#L151-L153

`ScatterPlotItem` starts off assuming DPR=1.0, and if that turns out to be incorrect, it has to rebuild the symbol cache. Effectively, this means that the time to first render should be slower for users with a hi-dpi display.
Now, `pyqtgraph` library could perhaps try to probe for the _primary screen_'s DPR and use that. That, however, is not entirely foolproof, as the user may have multiple screens with different DPRs.

Indeed, `ScatterPlotItem` does not know the screen on which it will display until just before painting occurs. And furthermore, even after being displayed, the user could drag the window to the other screen.
https://github.com/pyqtgraph/pyqtgraph/blob/a4bf6061271bac2a69b94f09e577b52183e97681/pyqtgraph/graphicsItems/ScatterPlotItem.py#L959-L966
Thanks for the quick reply!

I am indeed on a hi-dpi display and that may explain the slow down on my machine. In general, I am supporting users on Windows, Linux and macOS with any number of screens, so I would indeed need to check for the DPI before I plot. 

I will check that the pull request you mention is indeed the one that affects the rendering performance on my machine and come back to you asap.
The following script takes < 2.5 secs to run on a particular system with hidpi.

```python
import time

import numpy as np
import pyqtgraph as pg

npoints = 200_000
nbrushes = 600

rng = np.random.default_rng(0)
xy = rng.standard_normal(size=(2, npoints))
unique_colors = rng.integers(256, size=(nbrushes, 3))
unique_brushes = [pg.mkBrush(*rgb) for rgb in unique_colors]
random_choice = rng.integers(nbrushes, size=npoints)
random_brushes = [unique_brushes[x] for x in random_choice]

pg.mkQApp()

scatter = pg.ScatterPlotItem(
    size=5,
    pen=pg.mkPen(None),
    brush=pg.mkBrush(255, 255, 255, 128),  # To be overridden in the next call depending on a setting
    hoverable=True,
    hoverSymbol="s",
    hoverSize=5,
    hoverPen=pg.mkPen("w", width=2),
    hoverBrush=None,
)

t0 = time.perf_counter()
# scatter.addPoints(x=xy[0], y=xy[1], brush=random_choice)  # SLOW
scatter.addPoints(x=xy[0], y=xy[1], brush=random_brushes)   # FAST
t1 = time.perf_counter()
print(f'{t1 - t0:.3f}')

pg.mkQApp()
win = pg.PlotWidget()
win.show()
win.addItem(scatter)
pg.exec()
```

The following should explain why:
https://github.com/pyqtgraph/pyqtgraph/blob/a4bf6061271bac2a69b94f09e577b52183e97681/pyqtgraph/graphicsItems/ScatterPlotItem.py#L125-L130


Resolving patch:
diff --git a/pyqtgraph/graphicsItems/ScatterPlotItem.py b/pyqtgraph/graphicsItems/ScatterPlotItem.py
--- a/pyqtgraph/graphicsItems/ScatterPlotItem.py
+++ b/pyqtgraph/graphicsItems/ScatterPlotItem.py
@@ -361,6 +361,8 @@ def __init__(self, *args, **kargs):
 
         self.picture = None   # QPicture used for rendering when pxmode==False
         self.fragmentAtlas = SymbolAtlas()
+        if screen := QtGui.QGuiApplication.primaryScreen():
+            self.fragmentAtlas.setDevicePixelRatio(screen.devicePixelRatio())
 
         dtype = [
             ('x', float),


Test patch: