Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plot update on getting attributes #757

Merged
merged 1 commit into from
Apr 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/sisl/viz/figure/figure.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,17 @@

return fig

@classmethod
def fig_has_attr(cls, key: str) -> bool:
"""Whether the figure that this class generates has a given attribute.

Parameters
-----------
key
the attribute to check for.
"""
return False

Check warning on line 80 in src/sisl/viz/figure/figure.py

View check run for this annotation

Codecov / codecov/patch

src/sisl/viz/figure/figure.py#L80

Added line #L80 was not covered by tests

@staticmethod
def _sanitize_plot_actions(plot_actions):
def _flatten(plot_actions, out, level=0, root_i=0):
Expand Down
9 changes: 8 additions & 1 deletion src/sisl/viz/figure/matplotlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,9 +195,16 @@

yield sanitized_section_actions

@classmethod
def fig_has_attr(cls, key: str) -> bool:
return hasattr(plt.Axes, key) or hasattr(plt.Figure, key)

Check warning on line 200 in src/sisl/viz/figure/matplotlib.py

View check run for this annotation

Codecov / codecov/patch

src/sisl/viz/figure/matplotlib.py#L200

Added line #L200 was not covered by tests

def __getattr__(self, key):
if key != "axes":
return getattr(self.axes, key)
if hasattr(self.axes, key):
return getattr(self.axes, key)
elif key != "figure" and hasattr(self.figure, key):
return getattr(self.figure, key)

Check warning on line 207 in src/sisl/viz/figure/matplotlib.py

View check run for this annotation

Codecov / codecov/patch

src/sisl/viz/figure/matplotlib.py#L204-L207

Added lines #L204 - L207 were not covered by tests
raise AttributeError(key)

def clear(self, layout=False):
Expand Down
5 changes: 5 additions & 0 deletions src/sisl/viz/figure/plotly.py
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,11 @@

self.update_layout(sliders=[slider], updatemenus=updatemenus)

@classmethod
def fig_has_attr(cls, key: str) -> bool:
print(key, hasattr(go.Figure, key))
return hasattr(go.Figure, key)

Check warning on line 408 in src/sisl/viz/figure/plotly.py

View check run for this annotation

Codecov / codecov/patch

src/sisl/viz/figure/plotly.py#L407-L408

Added lines #L407 - L408 were not covered by tests

def __getattr__(self, key):
if key != "figure":
return getattr(self.figure, key)
Expand Down
30 changes: 18 additions & 12 deletions src/sisl/viz/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,31 @@
from sisl.messages import deprecate
from sisl.nodes import Workflow

from .figure import BACKENDS


class Plot(Workflow):
"""Base class for all plots"""

def __getattr__(self, key):
if key != "nodes":
# If an ipython key is requested, get the plot and look
# for the key in the plot. This is simply to enhance
# interactivity in a python notebook environment.
# However, this results in a (maybe undesired) behavior:
# The plot is updated when ipython requests it, without any
# explicit request to update it. This is how it has worked
# from the beggining, so it's probably best to keep it like
# this for now.
if "ipython" in key:
output = self.nodes.output.get()
# From the backend input, we find out which class is the figure going to be
# (even if no figure has been created yet or the latest figure was from a different backend)
# Then we check if the attribute will be available there. If it will, we update the plot and
# get the attribute on the updated plot.
# This is so that things like `plot.show()` work as expected.
# It has the downside that `.get()` is called even when for example a method of the figure is
# retreived to get its docs (e.g. in the helper messages of jupyter notebooks)
selected_backend = self.inputs.get("backend")
figure_cls = BACKENDS.get(selected_backend)
if figure_cls is not None and (

Check warning on line 26 in src/sisl/viz/plot.py

View check run for this annotation

Codecov / codecov/patch

src/sisl/viz/plot.py#L24-L26

Added lines #L24 - L26 were not covered by tests
hasattr(figure_cls, key) or figure_cls.fig_has_attr(key)
):
return getattr(self.nodes.output.get(), key)

Check warning on line 29 in src/sisl/viz/plot.py

View check run for this annotation

Codecov / codecov/patch

src/sisl/viz/plot.py#L29

Added line #L29 was not covered by tests
else:
output = self.nodes.output._output
return getattr(output, key)
raise AttributeError(

Check warning on line 31 in src/sisl/viz/plot.py

View check run for this annotation

Codecov / codecov/patch

src/sisl/viz/plot.py#L31

Added line #L31 was not covered by tests
f"'{key}' not found in {self.__class__.__name__} with backend '{selected_backend}'"
)
else:
return super().__getattr__(key)

Expand Down