Source code for nodefinder.identify.plot

# -*- coding: utf-8 -*-

# © 2017-2019, ETH Zurich, Institut für Theoretische Physik
# Author: Dominik Gresch <greschd@gmx.ch>
"""
Defines functions for plotting the results of the identify step.
"""

from functools import singledispatch

import numpy as np
import scipy.linalg as la
from fsc.export import export

from .result import NodalPoint, NodalLine

from .._common_plot import _setup_plot


[docs]@export def result(res, *, axis=None): """Plot the result of the identify step. Arguments --------- res : IdentificationResultContainer Result of the identify step. axis : matplotlib.axes.Axes, optional Axes on which the result is plotted. """ fig, axis, _ = _setup_plot(res.coordinate_system.limits, axis=axis) feature_size = res.feature_size for identification_result in res: shape = identification_result.shape color = axis._get_lines.get_next_color() # pylint: disable=protected-access if shape is None: _plot_positions( identification_result.positions, axis=axis, color=color ) else: _plot_result( shape, axis=axis, color=color, feature_size=feature_size ) return fig, axis
def _plot_positions(positions, *, axis, color): coordinates = list(np.array(list(positions)).T) axis.scatter(*coordinates, color=color) @singledispatch def _plot_result(shape, axis, color, feature_size): raise NotImplementedError
[docs]@export @_plot_result.register(NodalPoint) def nodal_point(shape, *, axis, color, feature_size=None): """ Plot a nodal point. Arguments --------- shape : NodalPoint Nodal point to be plotted. axis : matplotlib.axes.Axes Axes on which to plot. color : str Color of the point. feature_size : float Distance between two nodal points at which they are considered distinct. This argument is not used in this function. """ coordinates = [[val] for val in shape.position] axis.scatter(*coordinates, color=color)
[docs]@export @_plot_result.register(NodalLine) def nodal_line(shape, *, axis, color, feature_size=None): """ Plot a nodal line. Arguments --------- shape : NodalLine Nodal line to be plotted. axis : matplotlib.axes.Axes Axes on which to plot. color : str Color of the nodal line. feature_size : float Distance between two nodal points at which they are considered distinct. Used for cutting the line when it goes across periodic boundaries. """ if feature_size is None: feature_size = np.inf graph = shape.graph paths = _get_graph_paths(graph, feature_size=feature_size) if paths: for path in paths: axis.plot(*np.array(path).T, color=color) # pylint: disable=not-an-iterable else: axis.scatter(*np.array(list(graph.nodes)).T, color=color) # pylint: disable=not-an-iterable
def _get_graph_paths(graph, feature_size): """ Separate a graph into paths, breaking when there is no neighbor or when passing across the periodic boundary. """ working_graph = graph.copy() paths = [] while working_graph.edges: curr_node = _get_next_starting_point(working_graph) curr_path = [curr_node] while True: try: next_node = next(working_graph.neighbors(curr_node)) except StopIteration: paths.append(curr_path) break if la.norm( np.array(next_node) - np.array(curr_node) ) > 2 * feature_size: paths.append(curr_path) curr_path = [next_node] else: curr_path.append(next_node) working_graph.remove_edge(curr_node, next_node) curr_node = next_node return paths def _get_next_starting_point(graph): nonzero_degree = [(node, degree) for node, degree in graph.degree if degree > 0] return min( nonzero_degree, key=lambda val: val[1] if val[1] != 2 else float('inf') )[0]