Make `PlotItemOverlay` add items inwards->out

Before this axes were being stacked from the outside in (for `'right'`
and 'bottom'` axes) which is somewhat non-intuitive for an `.append()`
operation. As such this change makes a symbol list stack a set of
`'right'` axes from left-to-right.

Details:
- rename `ComposeGridLayout.items` -> `.pitems`
- return `(int, list[AxisItem])` pairs from `.insert/append_plotitem()`
  and the down stream `PlotItemOverlay.add_plotitem()`.
- drop `PlotItemOverlay.overlays` and add it back as `@property` around
  the underlying `.layout.pitems`.
multichartz
Tyler Goodlet 2022-11-15 22:03:20 -05:00
parent 5f5843613e
commit 58a82e7a3f
1 changed files with 36 additions and 22 deletions

View File

@ -92,11 +92,11 @@ class ComposedGridLayout:
''' '''
def __init__( def __init__(
self, self,
item: PlotItem, pi: PlotItem,
) -> None: ) -> None:
self.items: list[PlotItem] = [] self.pitems: list[PlotItem] = []
self._pi2axes: dict[ # TODO: use a ``bidict`` here? self._pi2axes: dict[ # TODO: use a ``bidict`` here?
int, int,
dict[str, AxisItem], dict[str, AxisItem],
@ -125,7 +125,7 @@ class ComposedGridLayout:
layout.setOrientation(orient) layout.setOrientation(orient)
self.insert_plotitem(0, item) self.insert_plotitem(0, pi)
# insert surrounding linear layouts into the parent pi's layout # insert surrounding linear layouts into the parent pi's layout
# such that additional axes can be appended arbitrarily without # such that additional axes can be appended arbitrarily without
@ -135,13 +135,14 @@ class ComposedGridLayout:
# TODO: do we need this? # TODO: do we need this?
# axis should have been removed during insert above # axis should have been removed during insert above
index = _axes_layout_indices[name] index = _axes_layout_indices[name]
axis = item.layout.itemAt(*index) axis = pi.layout.itemAt(*index)
if axis and axis.isVisible(): if axis and axis.isVisible():
assert linlayout.itemAt(0) is axis assert linlayout.itemAt(0) is axis
# item.layout.removeItem(axis) # XXX: see comment in ``.insert_plotitem()``...
item.layout.addItem(linlayout, *index) # pi.layout.removeItem(axis)
layout = item.layout.itemAt(*index) pi.layout.addItem(linlayout, *index)
layout = pi.layout.itemAt(*index)
assert layout is linlayout assert layout is linlayout
def _register_item( def _register_item(
@ -157,14 +158,14 @@ class ComposedGridLayout:
self._pi2axes.setdefault(name, {})[index] = axis self._pi2axes.setdefault(name, {})[index] = axis
# enter plot into list for index tracking # enter plot into list for index tracking
self.items.insert(index, plotitem) self.pitems.insert(index, plotitem)
def insert_plotitem( def insert_plotitem(
self, self,
index: int, index: int,
plotitem: PlotItem, plotitem: PlotItem,
) -> (int, int): ) -> tuple[int, list[AxisItem]]:
''' '''
Place item at index by inserting all axes into the grid Place item at index by inserting all axes into the grid
at list-order appropriate position. at list-order appropriate position.
@ -175,11 +176,14 @@ class ComposedGridLayout:
'`.insert_plotitem()` only supports an index >= 0' '`.insert_plotitem()` only supports an index >= 0'
) )
inserted_axes: list[AxisItem] = []
# add plot's axes in sequence to the embedded linear layouts # add plot's axes in sequence to the embedded linear layouts
# for each "side" thus avoiding graphics collisions. # for each "side" thus avoiding graphics collisions.
for name, axis_info in plotitem.axes.copy().items(): for name, axis_info in plotitem.axes.copy().items():
linlayout, axes = self.sides[name] linlayout, axes = self.sides[name]
axis = axis_info['item'] axis = axis_info['item']
inserted_axes.append(axis)
if axis in axes: if axis in axes:
# TODO: re-order using ``.pop()`` ? # TODO: re-order using ``.pop()`` ?
@ -192,19 +196,20 @@ class ComposedGridLayout:
if ( if (
not axis.isVisible() not axis.isVisible()
# XXX: we never skip moving the axes for the *first* # XXX: we never skip moving the axes for the *root*
# plotitem inserted (even if not shown) since we need to # plotitem inserted (even if not shown) since we need to
# move all the hidden axes into linear sub-layouts for # move all the hidden axes into linear sub-layouts for
# that "central" plot in the overlay. Also if we don't # that "central" plot in the overlay. Also if we don't
# do it there's weird geomoetry calc offsets that make # do it there's weird geomoetry calc offsets that make
# view coords slightly off somehow .. smh # view coords slightly off somehow .. smh
and not len(self.items) == 0 and not len(self.pitems) == 0
): ):
continue continue
# XXX: Remove old axis? No, turns out we don't need this? # XXX: Remove old axis?
# DON'T unlink it since we the original ``ViewBox`` # No, turns out we don't need this?
# to still drive it B) # DON'T UNLINK IT since we need the original ``ViewBox`` to
# still drive it with events/handlers B)
# popped = plotitem.removeAxis(name, unlink=False) # popped = plotitem.removeAxis(name, unlink=False)
# assert axis is popped # assert axis is popped
@ -220,7 +225,7 @@ class ComposedGridLayout:
self._register_item(index, plotitem) self._register_item(index, plotitem)
return index return (index, inserted_axes)
def append_plotitem( def append_plotitem(
self, self,
@ -234,7 +239,7 @@ class ComposedGridLayout:
''' '''
# for left and bottom axes we have to first remove # for left and bottom axes we have to first remove
# items and re-insert to maintain a list-order. # items and re-insert to maintain a list-order.
return self.insert_plotitem(len(self.items), item) return self.insert_plotitem(len(self.pitems), item)
def get_axis( def get_axis(
self, self,
@ -247,7 +252,7 @@ class ComposedGridLayout:
if axis for that name is not shown. if axis for that name is not shown.
''' '''
index = self.items.index(plot) index = self.pitems.index(plot)
named = self._pi2axes[name] named = self._pi2axes[name]
return named.get(index) return named.get(index)
@ -306,10 +311,13 @@ class PlotItemOverlay:
# events/signals. # events/signals.
root_plotitem.vb.setZValue(10) root_plotitem.vb.setZValue(10)
self.overlays: list[PlotItem] = []
self.layout = ComposedGridLayout(root_plotitem) self.layout = ComposedGridLayout(root_plotitem)
self._relays: dict[str, Signal] = {} self._relays: dict[str, Signal] = {}
@property
def overlays(self) -> list[PlotItem]:
return self.layout.pitems
def add_plotitem( def add_plotitem(
self, self,
plotitem: PlotItem, plotitem: PlotItem,
@ -324,11 +332,9 @@ class PlotItemOverlay:
# (0, 1), # link both # (0, 1), # link both
link_axes: tuple[int] = (), link_axes: tuple[int] = (),
) -> None: ) -> tuple[int, list[AxisItem]]:
index = index or len(self.overlays)
root = self.root_plotitem root = self.root_plotitem
self.overlays.insert(index, plotitem)
vb: ViewBox = plotitem.vb vb: ViewBox = plotitem.vb
# TODO: some sane way to allow menu event broadcast XD # TODO: some sane way to allow menu event broadcast XD
@ -476,7 +482,10 @@ class PlotItemOverlay:
# ``PlotItem`` dynamically. # ``PlotItem`` dynamically.
# append-compose into the layout all axes from this plot # append-compose into the layout all axes from this plot
self.layout.insert_plotitem(index, plotitem) if index is None:
insert_index, axes = self.layout.append_plotitem(plotitem)
else:
insert_index, axes = self.layout.insert_plotitem(index, plotitem)
plotitem.setGeometry(root.vb.sceneBoundingRect()) plotitem.setGeometry(root.vb.sceneBoundingRect())
@ -496,6 +505,11 @@ class PlotItemOverlay:
vb.setZValue(100) vb.setZValue(100)
return (
index,
axes,
)
def get_axis( def get_axis(
self, self,
plot: PlotItem, plot: PlotItem,