# PyQtGraph Optimization Examples

Real-world optimization case studies from piker.

## Case Study: Gap Annotations (1285 gaps)

### Before: Individual `pg.ArrowItem` + `SelectRect`

```
Total creation time: 6.6 seconds
Per-item overhead: ~5ms
Memory: 1285 ArrowItem + 1285 SelectRect objects
```

Each gap was rendered as two separate
`QGraphicsItem` instances (arrow + highlight rect),
resulting in 2570 Qt objects.

### After: Single `GapAnnotations` batch renderer

```
Total creation time:
  104ms (server) + 376ms (client)
Effective per-item: ~0.08ms
Speedup: ~36x client, ~180x server
Memory: 1 GapAnnotations object
```

All 1285 gaps rendered via:
- One `PrimitiveArray` for all rectangles
- One `QPainterPath` for all arrows
- Shared pen/brush across all items

### Profiler Output (Client)

```
> Entering markup_gaps() for 1285 gaps
  initial redraw: 0.20ms, tot:0.20
  built annotation specs: 256.48ms, tot:256.68
  batch IPC call complete: 119.26ms, tot:375.94
  final redraw: 0.07ms, tot:376.02
< Exiting markup_gaps(), total: 376.04ms
```

### Profiler Output (Server)

```
> Entering Batch annotate 1285 gaps
  `np.searchsorted()` complete!: 0.81ms, tot:0.81
  `time_to_row` creation: 98.45ms, tot:99.28
  created GapAnnotations item: 2.98ms, tot:102.26
< Exiting Batch annotate, total: 104.15ms
```

## Positioning/Update Pattern

For annotations that need repositioning when the
view scrolls or zooms:

```python
def reposition(self, array):
    '''
    Update positions based on new array data.

    '''
    # vectorized timestamp lookups (not linear!)
    time_to_row = self._build_lookup(array)

    # update rect array in-place
    rect_memory = self._rectarray.ndarray()
    for i, spec in enumerate(self._specs):
        row = time_to_row.get(spec['time'])
        if row:
            rect_memory[i, 0] = row['index']
            rect_memory[i, 1] = row['close']
            # ... width, height

    # trigger repaint (single call, not per-item)
    self.update()
```

**Key insight:** Update the underlying memory
arrays directly, then call `.update()` once.
Never create/destroy Qt objects during reposition.
