Skip to content

Commit

Permalink
Merge pull request #231 from scipp/to_dict
Browse files Browse the repository at this point in the history
  • Loading branch information
nvaytet authored Aug 4, 2023
2 parents 678f359 + 8565c49 commit d5f7537
Show file tree
Hide file tree
Showing 39 changed files with 251 additions and 305 deletions.
6 changes: 3 additions & 3 deletions docs/about/reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ Graphics

graphics.Camera
graphics.ColorMapper
graphics.FigImage
graphics.FigLine
graphics.FigScatter3d
graphics.figure1d
graphics.figure2d
graphics.figure3d
graphics.ImageView
graphics.LineView
graphics.Scatter3dView
graphics.tiled

Widgets and tools
Expand Down
2 changes: 1 addition & 1 deletion src/plopp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@

from . import data
from .core import Node, View, input_node, node, show_graph, widget_node
from .functions import inspector, plot, scatter3d, slicer, superplot
from .graphics import Camera, figure1d, figure2d, figure3d, tiled
from .plotting import inspector, plot, scatter3d, slicer, superplot


def patch_scipp():
Expand Down
62 changes: 8 additions & 54 deletions src/plopp/backends/matplotlib/figure.py
Original file line number Diff line number Diff line change
@@ -1,85 +1,39 @@
# SPDX-License-Identifier: BSD-3-Clause
# Copyright (c) 2023 Scipp contributors (https://github.com/scipp)

from ...graphics import BaseFig

class Figure:

class Figure(BaseFig):
"""
Mixin class for Matplotlib figures
"""

def __init_figure__(self, FigConstructor, *args, **kwargs):
self._fig = FigConstructor(*args, **kwargs)
def __init_figure__(self, View, *args, **kwargs):
self._view = View(*args, **kwargs)
self._args = args
self._kwargs = kwargs
self._fig_constructor = FigConstructor

@property
def fig(self):
"""
Get the underlying Matplotlib figure.
"""
return self._fig.canvas.fig
return self._view.canvas.fig

@property
def ax(self):
"""
Get the underlying Matplotlib axes.
"""
return self._fig.canvas.ax
return self._view.canvas.ax

@property
def cax(self):
"""
Get the underlying Matplotlib colorbar axes.
"""
return self._fig.canvas.cax

@property
def canvas(self):
return self._fig.canvas

@property
def artists(self):
return self._fig.artists

@property
def graph_nodes(self):
return self._fig.graph_nodes

@property
def id(self):
return self._fig.id

def crop(self, **limits):
"""
Set the axes limits according to the crop parameters.
Parameters
----------
**limits:
Min and max limits for each dimension to be cropped.
"""
return self._fig.crop(**limits)

def save(self, filename, **kwargs):
"""
Save the figure to file.
The default directory for writing the file is the same as the
directory where the script or notebook is running.
Parameters
----------
filename:
Name of the output file. Possible file extensions are ``.jpg``, ``.png``,
``.svg``, and ``.pdf``.
"""
return self._fig.canvas.save(filename, **kwargs)

def update(self, *args, **kwargs):
return self._fig.update(*args, **kwargs)

def notify_view(self, *args, **kwargs):
return self._fig.notify_view(*args, **kwargs)
return self._view.canvas.cax

def __add__(self, other):
from .tiled import hstack
Expand Down
9 changes: 5 additions & 4 deletions src/plopp/backends/matplotlib/interactive.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ class InteractiveFig(Figure, VBox):
Create an interactive Matplotlib figure.
"""

def __init__(self, FigConstructor, *args, **kwargs):
self.__init_figure__(FigConstructor, *args, **kwargs)
def __init__(self, View, *args, **kwargs):
self.__init_figure__(View, *args, **kwargs)
self.toolbar = make_toolbar_canvas2d(
canvas=self._fig.canvas, colormapper=getattr(self._fig, 'colormapper', None)
canvas=self._view.canvas,
colormapper=getattr(self._view, 'colormapper', None),
)
self.left_bar = VBar([self.toolbar])
self.right_bar = VBar()
Expand All @@ -25,7 +26,7 @@ def __init__(self, FigConstructor, *args, **kwargs):
super().__init__(
[
self.top_bar,
HBox([self.left_bar, self._fig.canvas.to_widget(), self.right_bar]),
HBox([self.left_bar, self._view.canvas.to_widget(), self.right_bar]),
self.bottom_bar,
]
)
14 changes: 7 additions & 7 deletions src/plopp/backends/matplotlib/static.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,25 +33,25 @@ class StaticFig(Figure):
canvas.
"""

def __init__(self, FigConstructor, *args, **kwargs):
self.__init_figure__(FigConstructor, *args, **kwargs)
def __init__(self, View, *args, **kwargs):
self.__init_figure__(View, *args, **kwargs)

def _repr_mimebundle_(self, include=None, exclude=None) -> dict:
"""
Mimebundle display representation for jupyter notebooks.
"""
str_repr = str(self.fig)
out = {'text/plain': str_repr[:-1] + f', {len(self.artists)} artists)'}
if self._fig._repr_format is not None:
repr_maker = get_repr_maker(form=self._fig._repr_format)
if self._view._repr_format is not None:
repr_maker = get_repr_maker(form=self._view._repr_format)
else:
npoints = sum(len(line.get_xdata()) for line in self._fig.canvas.ax.lines)
npoints = sum(len(line.get_xdata()) for line in self._view.canvas.ax.lines)
repr_maker = get_repr_maker(npoints=npoints)
out.update(repr_maker(self._fig.canvas.fig))
out.update(repr_maker(self._view.canvas.fig))
return out

def to_widget(self):
"""
Convert the Matplotlib figure to an image widget.
"""
return self._fig.canvas.to_image()
return self._view.canvas.to_image()
2 changes: 1 addition & 1 deletion src/plopp/backends/matplotlib/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def is_sphinx_build() -> bool:

def copy_figure(fig: FigureLike, **kwargs) -> FigureLike:
out = fig.__class__(
fig._fig_constructor,
fig._view.__class__,
*fig._args,
**{**fig._kwargs, **kwargs},
)
Expand Down
58 changes: 6 additions & 52 deletions src/plopp/backends/plotly/figure.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,18 @@

from ipywidgets import HBox, VBox

from ...graphics import BaseFig
from ...widgets import HBar, VBar, make_toolbar_canvas2d


class Figure(VBox):
class Figure(BaseFig, VBox):
"""
Create an interactive figure to represent one-dimensional data.
"""

def __init__(self, FigConstructor, *args, **kwargs):
self._fig = FigConstructor(*args, **kwargs)
self.toolbar = make_toolbar_canvas2d(canvas=self._fig.canvas)
def __init__(self, View, *args, **kwargs):
self._view = View(*args, **kwargs)
self.toolbar = make_toolbar_canvas2d(canvas=self._view.canvas)
self.left_bar = VBar([self.toolbar])
self.right_bar = VBar()
self.bottom_bar = HBar()
Expand All @@ -22,54 +23,7 @@ def __init__(self, FigConstructor, *args, **kwargs):
super().__init__(
[
self.top_bar,
HBox([self.left_bar, self._fig.canvas.to_widget(), self.right_bar]),
HBox([self.left_bar, self._view.canvas.to_widget(), self.right_bar]),
self.bottom_bar,
]
)

@property
def canvas(self):
return self._fig.canvas

@property
def artists(self):
return self._fig.artists

@property
def graph_nodes(self):
return self._fig.graph_nodes

@property
def id(self):
return self._fig.id

def crop(self, **limits):
"""
Set the axes limits according to the crop parameters.
Parameters
----------
**limits:
Min and max limits for each dimension to be cropped.
"""
return self._fig.crop(**limits)

def save(self, filename, **kwargs):
"""
Save the figure to file.
The default directory for writing the file is the same as the
directory where the script or notebook is running.
Parameters
----------
filename:
Name of the output file. Possible file extensions are ``.jpg``, ``.png``,
``.svg``, ``.pdf``, and ``html``.
"""
return self._fig.canvas.save(filename, **kwargs)

def update(self, *args, **kwargs):
return self._fig.update(*args, **kwargs)

def notify_view(self, *args, **kwargs):
return self._fig.notify_view(*args, **kwargs)
42 changes: 34 additions & 8 deletions src/plopp/core/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

import uuid
from abc import abstractmethod
from typing import Any, Dict

import scipp as sc


class View:
Expand All @@ -23,19 +26,42 @@ def __init__(self, *nodes):
self.graph_nodes = {}
for node in nodes:
node.add_view(self)
self.artists = {}

@property
def id(self):
"""
The unique id of the view.
"""
return self._id

def notify_view(self, message: Dict[str, Any]):
"""
When a notification is received, request data from the corresponding parent node
and update the relevant artist.
Parameters
----------
*message:
The notification message containing the node id it originated from.
"""
node_id = message["node_id"]
new_values = self.graph_nodes[node_id].request_data()
self.update(new_values=new_values, key=node_id)

@abstractmethod
def notify_view(self, _):
def update(self, new_values: sc.DataArray, key: str, draw: bool):
"""
The function that will be called when a parent node is told to notify its
children and its views.
Update function which is called when a notification is received.
This has to be overridden by any child class.
"""
return
...

@property
def id(self):
def render(self):
"""
The unique id of the view.
At the end of figure creation, this function is called to request data from
all parent nodes and draw the figure.
"""
return self._id
for node in self.graph_nodes.values():
new_values = node.request_data()
self.update(new_values=new_values, key=node.id)
7 changes: 4 additions & 3 deletions src/plopp/graphics/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@

# flake8: noqa E402, F401

from .basefig import BaseFig
from .camera import Camera
from .colormapper import ColorMapper
from .figimage import FigImage
from .figline import FigLine
from .figscatter3d import FigScatter3d
from .figure import figure1d, figure2d, figure3d
from .imageview import ImageView
from .lineview import LineView
from .scatter3dview import Scatter3dView
from .tiled import tiled
Loading

0 comments on commit d5f7537

Please sign in to comment.