Beispiel #1
0
def sisl_files():
    """ Environment catcher for the large files hosted in a different repository.

    If SISL_FILES_TESTS has been defined in the environment variable the directory
    will be used for the tests with this as a fixture.

    If the environment variable is empty and a test has this fixture, it will
    be skipped.
    """
    sisl_files_tests = _environ.get_environ_variable("SISL_FILES_TESTS")
    if not sisl_files_tests.is_dir():

        def _path(*files):
            pytest.skip(
                f"Environment SISL_FILES_TESTS not pointing to a valid directory."
            )

        return _path

    def _path(*files):
        p = sisl_files_tests.joinpath(*files)
        if p.exists():
            return p
        # I expect this test to fail due to the wrong environment.
        # But it isn't an actual fail since it hasn't runned...
        pytest.xfail(
            f"Environment SISL_FILES_TESTS may point to a wrong path(?); file {p} not found"
        )

    return _path
Beispiel #2
0
def run(host=None,
        port=None,
        debug=False,
        app=None,
        socketio=None,
        prelaunch=None,
        async_mode="threading"):

    global SERVER_PORT
    global SERVER_HOST

    if app is None:
        app, socketio = api.create_app(get_session,
                                       set_session,
                                       async_mode=async_mode)

    # Disable all kinds of logging
    if not debug:
        app.logger.disabled = True
        log = logging.getLogger("werkzeug")
        log.disabled = True
        cli = sys.modules["flask.cli"]
        cli.show_server_banner = lambda *x: None

    if prelaunch is not None:
        prelaunch(get_session, set_session)

    if host is None:
        host = get_environ_variable("SISL_PLOTLY_API_HOST")
    if port is None:
        port = get_environ_variable("SISL_PLOTLY_API_PORT")

    SERVER_HOST = host
    SERVER_PORT = port

    print(
        f"\nApi running on {get_server_address()}...\nconnect the GUI to this address or send it to someone for sharing."
    )

    socketio.run(app, debug=debug, host=host, port=port)
Beispiel #3
0
def pytest_collection_modifyitems(config, items):
    sisl_files_tests = _environ.get_environ_variable("SISL_FILES_TESTS")
    if sisl_files_tests.is_dir():
        if (sisl_files_tests / 'sisl').is_dir():
            return
        print(
            f'pytest-sisl: Could not locate sisl directory in: {sisl_files_tests}'
        )
        return

    skip_sisl_files = pytest.mark.skip(
        reason=
        "requires env(SISL_FILES_TESTS) pointing to clone of: https://github.com/zerothi/sisl-files"
    )
    for item in items:
        # Only skip those that have the sisl_files fixture
        # GLOBAL skipping of ALL tests that don't have this fixture
        if 'sisl_files' in item.fixturenames:
            item.add_marker(skip_sisl_files)
Beispiel #4
0
def _pool_procs(pool):
    """
    This is still a bit mysterious to me.

    One have to close/terminate + restart to get a functioning
    pool. Also, the pool's are not existing in a local scope. `pathos`
    have a global list of open pools to not pollute the pools.
    This means that one may accidentially request a pool that the user
    has openened elsewhere.
    """
    if pool is False or pool is None:
        return None
    elif pool is True:
        import pathos as pos
        pool = pos.pools.ProcessPool(nodes=get_environ_variable("SISL_NPROCS"))
    elif isinstance(pool, int):
        import pathos as pos
        pool = pos.pools.ProcessPool(nodes=pool)
    pool.terminate()
    return pool
Beispiel #5
0
        if sile_files:
            files[rule.cls] = sile_files

    return files


#-------------------------------------
#         Multiprocessing
#-------------------------------------

register_environ_variable(
    "SISL_NPROCS_VIZ",
    max(os.cpu_count() - 1, 1),
    description="Maximum number of processors used for parallel plotting",
    process=int)
_MAX_NPROCS = get_environ_variable("SISL_NPROCS_VIZ")


def _apply_method(args_tuple):
    """ Apply a method to an object. This function is meant for multiprocessing """

    method, obj, args, kwargs = args_tuple

    if args is None:
        args = []

    method(obj, *args, **kwargs)

    return obj

Beispiel #6
0
        sile_files = find_files(dir_path,
                                search_string,
                                depth,
                                case_insensitive=True)

        if sile_files:
            files[rule.cls] = sile_files

    return files


#-------------------------------------
#         Multiprocessing
#-------------------------------------

_MAX_NPROCS = get_environ_variable("SISL_VIZ_NUM_PROCS")


def _apply_method(args_tuple):
    """ Apply a method to an object. This function is meant for multiprocessing """

    method, obj, args, kwargs = args_tuple

    if args is None:
        args = []

    method(obj, *args, **kwargs)

    return obj

Beispiel #7
0
# This makes one able to get files through:
#  import sisl
#  sisl.io.tbtgfSileTBtrans
# or
#  sisl.get_sile
# This will reduce the cluttering of the separate entities
# that sisl is made of.
import sisl.io as io
from .io.sile import (add_sile, get_sile_class, get_sile, get_siles,
                      get_sile_rules, SileError, BaseSile, Sile, SileCDF,
                      SileBin)

# Allow geometry to register siles
# Ensure BaseSile works as a str
# We have to do it after loading BaseSile and Geometry
# Since __getitem__ always instantiate the class, we have to use the
# contained lookup table.
Geometry.new.register(BaseSile, Geometry.new._dispatchs[str])

# Import the default geom structure
# This enables:
# import sisl
# sisl.geom.graphene
import sisl.geom as geom

if _environ.get_environ_variable("SISL_VIZ_AUTOLOAD"):
    from . import viz

# Make these things publicly available
__all__ = [s for s in dir() if not s.startswith('_')]
Beispiel #8
0
class Session(Configurable):
    """ Represents a session of the graphical interface

    Plots are organized in different tabs and each tab has a layout
    that defines how plots are displayed in the dashboard.

    Contains different methods that help managing the session and that are
    directly called by the front end of the graphical interface.
    Therefore: IF A METHOD NAME IS CHANGED, THE SAME CHANGE MUST BE DONE
    IN THE GUI FILE "apis/PythonApi".

    Parameters
    -----------
    root_dir: str, optional

    file_storage_dir: str, optional
        Directory where files uploaded in the GUI will be stored
    keep_uploaded: bool, optional
        Whether uploaded files should be kept in disk or directly removed
        after plotting them.
    search_depth: array-like of shape (2,), optional
        Determines the depth limits of the search for structures (from the
        root directory).
    showTooltips: bool, optional
        Tooltips help you understand how something works or what something
        will do.If you are already familiar with the interface, you can
        turn this off.
    listenForUpdates: bool, optional
        Determines whether the session updates plots when files change 
        This is very useful to track progress. It is only meaningful in the
        GUI.
    updateInterval: int, optional
        The time in ms between consecutive checks for updates.
    plot_dims: array-like, optional
        The initial width and height of a new plot.  Width is in columns
        (out of a total of 12). For height, you really should try what works
        best for you
    plot_preset: str, optional
        Preset that is passed directly to each plot initialization
    plotly_template: str, optional
        Plotly template that should be used as the default for this session
    """

    _param_groups = ({
        "key":
        "gui",
        "name":
        "Interface tweaks",
        "icon":
        "aspect_ratio",
        "description":
        "There's a spanish saying that goes something like: <i>for each taste there's a color</i>. Since we know this is true, you can tweak these parameters too <b>make the interface feel as comfortable as possible</b>. "
    }, {
        "key":
        "filesystem",
        "name":
        "File system settings",
        "icon":
        "folder",
        "description":
        "Your computer is pretty big and most of it is not important for the analysis of simulations (e.g. the folder with your holidays pictures). Also, everyone likes to store things differently. Please <b>indicate how exactly do you want the interface to look for simulations results</b> in your filesystem. "
    }, {
        "key":
        None,
        "name":
        "Other settings",
        "icon":
        "settings",
        "description":
        "Here are some unclassified settings. Even if they don't belong to any group, they might still be important :) They may be here just because the developer was too lazy to categorize them or forgot to do so. <b>If you are the developer</b> and it's the first case, <b>shame on you<b>."
    })

    _parameters = (
        TextInput(key="root_dir",
                  name="Root directory",
                  group="filesystem",
                  default=os.getcwd(),
                  width="s100% l50%",
                  params={"placeholder": "Write the path here..."}),
        FilePathInput(
            key="file_storage_dir",
            name="File storage directory",
            group="filesystem",
            default=get_environ_variable("SISL_TMP"),
            width="s100% l50%",
            params={"placeholder": "Write the path here..."},
            help="Directory where files uploaded in the GUI will be stored"),
        SwitchInput(
            key="keep_uploaded",
            name="Keep uploaded files",
            group="filesystem",
            default=False,
            width="s100% l50%",
            help=
            "Whether uploaded files should be kept in disk or directly removed after plotting them."
        ),
        RangeSlider(
            key="search_depth",
            name="Search depth",
            group="filesystem",
            default=[0, 3],
            width="s100% l50%",
            params={
                "min": 0,
                "max": 15,
                "allowCross": False,
                "step":
                1,
                "marks": {i: str(i)
                          for i in range(0, 16)},
                "updatemode": "drag",
                "units": "eV",
            },
            help=
            "Determines the depth limits of the search for structures (from the root directory)."
        ),
        SwitchInput(
            key="showTooltips",
            name="Show Tooltips",
            group="gui",
            default=True,
            params={
                "offLabel": "No",
                "onLabel": "Yes"
            },
            help=
            "Tooltips help you understand how something works or what something will do.<br>If you are already familiar with the interface, you can turn this off."
        ),
        SwitchInput(
            key="listenForUpdates",
            name="Listen for updates",
            group="gui",
            default=True,
            params={
                "offLabel": "No",
                "onLabel": "Yes"
            },
            help=
            "Determines whether the session updates plots when files change <br> This is very useful to track progress. It is only meaningful in the GUI."
        ),
        Array1DInput(
            key="plot_dims",
            name="Initial plot dimensions",
            default=[4, 30],
            group="gui",
            help=
            """The initial width and height of a new plot. <br> Width is in columns (out of a total of 12). For height, you really should try what works best for you"""
        ),
        TextInput(
            key="plot_preset",
            name="Plot presets",
            default=None,
            help="Preset that is passed directly to each plot initialization"),
        TextInput(
            key="plotly_template",
            name="Plotly template",
            default=None,
            help=
            "Plotly template that should be used as the default for this session"
        ))

    @vizplotly_settings('before', init=True)
    def __init__(self, *args, **kwargs):
        self.id = str(uuid.uuid4())

        self.before_plot_update = None
        self.on_plot_change = None
        self.on_plot_change_error = None

        self.warehouse = Warehouse()

        call_method_if_present(self, "_after_init")

    #-----------------------------------------
    #            PLOT MANAGEMENT
    #-----------------------------------------

    @property
    def plots(self):
        """ The plots that this session contains """
        return self.warehouse["plots"]

    def plot(self, plotID):
        """ Method to get a plot that is already in the session's warehouse

        Arguments
        -----------
        plotID: str
            The ID of the desired plot

        Returns
        ---------
        plot: sisl.viz.plotly.Plot()
            The instance of the desired plot
        """
        plot = self.plots[plotID]

        if not hasattr(plot, "grid_dims"):
            plot.grid_dims = self.get_setting("plot_dims")

        return plot

    @staticmethod
    def get_plot_classes():
        """ This method provides all the plot subclasses, even the nested ones

        Returns
        -------
        list
            all the plot classes that the module is aware of.
        """
        return get_plot_classes()

    def add_plot(self, plot, tabID=None, noTab=False):
        """ Adds an already initialized plot object to the session

        Parameters
        -----
        plot: Plot()
            the plot object that we want to add to the session
        tab: str, optional
            the name of the tab where we want to add the plot or
            the ID of the tab where we want to add the plot.

            If neither tab or tabID are provided, it will be appended to the first tab
        noTab: boolean, optional
            if set to true, prevents the plot from being added to a tab
        """
        self.warehouse["plots"][plot.id] = plot

        if not noTab:
            tabID = self._tab_id(
                tabID) if tabID is not None else self.tabs[0]["id"]

            self._add_plot_to_tab(plot.id, tabID)

        call_method_if_present(self, "_on_plot_added", plot, tabID)

        return self

    def new_plot(self,
                 plotClass=None,
                 tabID=None,
                 structID=None,
                 plotable_path=None,
                 animation=False,
                 **kwargs):
        """ Get a new plot from the specified class

        Arguments
        -----------
        plotClass: str, optional
            The name of the desired class.
            If not provided, the session will try to initialize from the `Plot` parent class. 
            This may be useful if the keyword argument filename is provided, for example, to let
            `Plot` guess which type of plot to use. 
        tabID: str, optional
            Tab where the plot should be stored
        structID: str, optional
            The ID of the structure for which we want the plot.
        plotableID: str, optional
            The ID of the plotable file that we want to plot.
        animation: bool, optional
            Whether the initialized plot should be an animation.

            If true, it uses the `Plot.animated` method to initialize the plot
        **kwargs:
            Passed directly to plot initialization

        Returns
        -----------
        new_plot: sisl.viz.plotly.Plot()
            The initialized new plot
        """
        args = []

        if plotClass is None:
            ReqPlotClass = Plot
        else:
            for PlotClass in self.get_plot_classes():
                if PlotClass.__name__ == plotClass:
                    ReqPlotClass = PlotClass
                    break
            else:
                raise ValueError(
                    f"Didn't find the desired plot class: {plotClass}")

        if plotable_path is not None:
            args = (plotable_path, )
        if structID:
            kwargs = {
                **kwargs, "root_fdf":
                self.warehouse["structs"][structID]["path"]
            }

        if animation:
            wdir = self.warehouse["structs"][structID][
                "path"].parent if structID else self.get_setting("root_dir")
            new_plot = ReqPlotClass.animated(wdir=wdir)
        else:
            plot_preset = self.get_setting("plot_preset")
            if plot_preset is not None:
                kwargs["presets"] = [
                    *[plot_preset], *kwargs.get("presets", [])
                ]
            plotly_template = self.get_setting("plotly_template")
            if plotly_template is not None:
                layout = kwargs.get("layout", {})
                template = layout.get("template", "")
                kwargs["layout"] = {
                    "template":
                    f'{plotly_template}{"+" + template if template else ""}',
                    **layout
                }
            new_plot = ReqPlotClass(*args, **kwargs)

        self.add_plot(new_plot, tabID)

        return self.plot(new_plot.id)

    def update_plot(self, plotID, newSettings):
        """ Method to update the settings of a plot that is in the session's warehouse

        Arguments
        -----------
        plotID: str
            The ID of the plot whose settings need to be updated
        newSettings: dict
            Dictionary with the key and new value of all the settings that need to be updated.

        Returns
        ---------
        plot: sisl.viz.plotly.Plot()
            The instance of the updated plot
        """
        return self.plot(plotID).update_settings(**newSettings)

    def undo_plot_settings(self, plotID):
        """ Method undo the settings of a plot that is in the session's warehouse

        Arguments
        -----------
        plotID: str
            The ID of the plot whose settings need to be undone

        Returns
        ---------
        plot: sisl.viz.plotly.Plot()
            The instance of the plot with the settings rolled back.
        """
        return self.plot(plotID).undo_settings()

    def remove_plot_from_tab(self, plotID, tab):
        """ Method to remove a plot only from a given tab.

        Parameters
        -----------
        plotID: str
            the ID of the plot that you want to remove.
        tab: str
            the ID or name of the tab that you want to remove the plot from.
        """
        tab = self.tab(tab)

        tab["plots"] = [plot for plot in tab["plots"] if plot != plotID]

    def remove_plot(self, plotID):
        """ Method to remove a plot from all tabs.

        Parameters
        ----------
        plotID: str
            the ID of the plot that you want to remove.
        """
        plot = self.plot(plotID)

        self.warehouse["plots"] = {
            ID: plot
            for ID, plot in self.plots.items() if ID != plotID
        }

        self.remove_plot_from_all_tabs(plotID)

        call_method_if_present(self, "_on_plot_removed", plot)

        return self

    def merge_plots(self,
                    plots,
                    to="multiple",
                    tab=None,
                    remove=True,
                    **kwargs):
        """ Merges two or more plots present in the session using `Plot.merge`.

        Parameters
        -----------
        plots: array-like of (str and/or Plot)
            A list with the ids of the plots (or the actual plots) that you want to merge.
            Note that THE PLOTS PASSED HERE ARE NOT NECESSARILY IN THE SESSION beforehand.
        to: {"multiple", "subplots", "animation"}, optional
            the merge method. Each option results in a different way of putting all the plots
            together:
            - "multiple": All plots are shown in the same canvas at the same time. Useful for direct
            comparison.
            - "subplots": The layout is divided in different subplots.
            - "animation": Each plot is converted into the frame of an animation.
        tab: str, optional
            the name or id of the tab where you want the new plot to go. 
            If not provided it will go to the tab where the first plot belongs.
        remove: boolean, optional
            whether the plots used to do the merging should be removed from the session's layout.
            Remember that you are always in time to split the merged plots into individual plots
            again.
        **kwargs: 
            go directly extra arguments that are directly passed to `MultiplePlot`, `Subplots`
            or `Animation` initialization. (see `Plot.merge`)
        """
        # Get the plots if ids where passed. Note that we can accept plots that are not in the warehouse yet
        plots = [
            self.plot(plot) if isinstance(plot, str) else plot
            for plot in plots
        ]

        merged = plots[0].merge(plots[1:], to=to, **kwargs)

        if tab is None:
            for session_tab in self.tabs:
                if plots[0].id in session_tab["plots"]:
                    tab = session_tab["id"]
                    break

        if remove:
            for plot in plots:
                self.remove_plot(plot.id)

        self.add_plot(merged, tabID=tab)

        return self

    def updates_available(self):
        """ Checks if the session's plots have pending updates due to changes in files.

        Returns
        ---------
        list
            the ids of the plots where an update is available.
        """
        updates_avail = [
            plotID for plotID, plot in self.plots.items()
            if plot.updates_available()
        ]

        return updates_avail

    def commit_updates(self):
        """ Updates the plots that can be updated according to `updates_available`.

        Note that this method can be safely called since it has no effect when no updates are available.
        """
        for plotID in self.updates_available():
            try:
                self.plots[plotID].read_data(update_fig=True)
            except Exception as e:
                warn(f"Could not update plot {plotID}.\nError: {e}")

        return self

    def listen(self, forever=False):
        """ Listens for updates in the followed files (see the `updates_available` method)

        Parameters
        ---------
        forever: boolean, optional
            whether to keep listening after the first plot updates.
        """
        from threading import Event

        exit_event = Event()

        while exit_event.is_set():

            exit_event.wait(1)

            updates_avail = self.updates_available()

            if len(updates_avail) != 0:

                for plotID in updates_avail:
                    self.plots[plotID].read_data(update_fig=True)

                if not forever:
                    exit_event.set()

    def figures_only(self):
        """ Removes all plot data from this session's plots except the actual figure.

        This is very useful to save just for display, since it can decrease the size of the session
        DRAMATICALLY.
        """
        for plotID, plot in self.plots.items():

            plot = Plot.from_plotly(plot.figure)
            plot.id = plotID

            self.warehouse["plots"][plotID] = plot

    def _run_plot_method(self, plotID, method_name, *args, **kwargs):
        """ Generic private method to run methods on plots that belong to this session.

        Any public method that runs plot methods should use this private method under the hood.

        In this way, the session will be able to consistently respond to plot updates. E.g. 
        """
        plot = self.plot(plotID)

        method = getattr(plot.autosync, method_name)

        return method(*args, **kwargs)

    #-----------------------------------------
    #            TABS MANAGEMENT
    #-----------------------------------------
    @property
    def tabs(self):
        """ The tabs that this session contains """
        return self.warehouse["tabs"]

    def tab(self, tab):
        """ Get a tab by its name or ID. 

        If it does not exist, it will be created (this acts as a shortcut for add_tab in that case)

        Parameters
        --------
        tab: str
            The name or ID of the tab you want to get
        """
        tab_str = tab

        tabID = self._tab_id(tab_str)

        for tab in self.tabs:
            if tab["id"] == tabID:
                return tab
        else:
            self.add_tab(tab_str)
            return self.tab(tab_str)

    def add_tab(self, name="New tab", plots=[]):
        """ Adds a new tab to the session

        Arguments
        ----------
        name: optional, str ("New tab")
            The name of the new tab
        plots: optional, array-like
            Array of ids (as strings) that identify the plots that you want to put inside your tab.
            Keep in mind that the plots with these ids must be present in self.plots.
        """
        new_tab = {
            "id": str(uuid.uuid4()),
            "name": name,
            "plots": deepcopy(plots),
            "layouts": {
                "lg": []
            }
        }

        self.tabs.append(new_tab)

        return self

    def update_tab(self, tabID, newParams={}, **kwargs):
        """ Method to update the parameters of a given tab """
        tab = self.tab(tabID)

        for key, val in {**newParams, **kwargs}.items():
            tab[key] = val

        return self

    def remove_tab(self, tabID):
        """ Removes a tab from the current session """
        tabID = self._tab_id(tabID)

        for iTab, tab in enumerate(self.warehouse["tabs"]):
            if tab["id"] == tabID:
                del self.warehouse["tabs"][iTab]
                break

        return self

    def move_plot(self, plot, tab, keep=False):
        """ Moves a plot to a tab

        Parameters
        ----------
        plot: str or sisl.viz.plotly.Plot
            the plot's ID or the plot's instance
        tab: str
            the tab's id or the tab's name.
        keep: boolean, optional
            if True the plot is also kept in the previous tab.
            This doesn't waste any additional memory,
            since the tabs only hold references of the plots they have,
            each plot is stored only once
        """
        plotID = plot
        if isinstance(plot, Plot):
            plotID = plot.id

        if not keep:
            self.remove_plot_from_all_tabs(plotID)

        self._add_plot_to_tab(plotID, tab)

        return self

    def _add_plot_to_tab(self, plot, tab):
        """ Adds a plot to the requested tab.

        If the plot is not part of the session already, it will be added.

        Parameters
        ----------
        plot: str or sisl.viz.plotly.Plot
            the plot's ID or the plot's instance
        tab: str
            the tab's id or the tab's name.
        """
        if isinstance(plot, Plot):
            plotID = plot.id
            if plotID not in self.plots:
                self.add_plot(plot, tab)
        else:
            plotID = plot

        tab = self.tab(tab)

        tab["plots"] = [*tab["plots"], plotID]

        return self

    def remove_plot_from_all_tabs(self, plotID):
        """ Removes a given plot from all tabs where it is located.

        Parameters
        -----------
        plotID: str
            the id of the plot you want to remove.
        """
        for tab in self.tabs:
            self.remove_plot_from_tab(plotID, tab["id"])

        return self

    def get_tab_plots(self, tab):
        """ Returns all the plots of a given tab.

        Parameters
        ------------
        tab: str
            the id or name of the tab.
        """
        tab = self.tab(tab)

        return [self.plot(plotID) for plotID in tab["plots"]] if tab else None

    def set_tab_plots(self, tab, plots):
        """ Sets the plots list of a tab

        Parameters
        --------
        tab: str
            tab's id or name
        plots: array-like of str or sisl.viz.plotly.Plot (or combination of the two)
            plots ids or plot instances.
        """
        tab = self.tab(tab)

        tab["plots"] = []

        for plot in plots:
            self.add_plot(plot, tab)

    def tab_id(self, tab_name):
        """ Gets the id of a given tab.

        Parameters
        -----------
        tab_name: str
            the name of the tab

        Returns
        ---------
        str or None.
            the ID of the tab. None if there's no such tab.
        """
        for tab in self.tabs:
            if tab["name"] == tab_name:
                return tab["id"]

    def _tab_id(self, tab_id_or_name):
        """ Gets the id of a given tab.

        Parameters
        -----------
        tab_id_or_name: str
            the id or name of the tab.

        Returns
        ---------
        str or None.
            the ID of the tab. None if there's no such tab.
        """
        try:
            uuid.UUID(str(tab_id_or_name))
            return tab_id_or_name
        except Exception:
            return self.tab_id(tab_id_or_name)

    #-----------------------------------------
    #         STRUCTURES MANAGEMENT
    #-----------------------------------------

    def get_structures(self, path=None, root_dir=".", search_depth=None):
        """ Gets all the structures that are in the scope of this session

        Parameters
        -----------
        path: str, optional
            the path where to start looking for structures.

            If not provided, the session's "root_dir" will be used.

        Returns
        ----------
        dict
            keys are the structure ID and values are info about each structure.
        """
        path = Path(path or root_dir)

        #Get the structures
        self.warehouse["structs"] = {
            str(uuid.uuid4()): {
                "name": path.name,
                "path": path
            }
            for path in find_files(root_dir, "*fdf", search_depth)
        }

        #Avoid passing unnecessary info to the browser.
        return {
            structID: {
                "id": structID,
                **{k: struct[k]
                   for k in ["name", "path"]}
            }
            for structID, struct in self.warehouse["structs"].items()
        }

    def get_plotables(self, path=None, root_dir=".", search_depth=None):
        """ Gets all the plotables that are in the scope of this session.

        Parameters
        -----------
        path: str, optional
            the path where to start looking for plotables.

            If not provided, the session's "root_dir" will be used.

        Returns
        ----------
        dict
            keys are the plotable ID and values are info about each structure.
        """
        # Empty the plotables dictionary
        self.warehouse["plotables"] = {}
        path = Path(path or root_dir)

        # Get all the files that correspond to registered plotable siles
        files = find_plotable_siles(path, search_depth)

        for SileClass, filepaths in files.items():

            avail_plots = list(SileClass.plot.plotly._raw_methods)
            default_plot = SileClass.plot.plotly._default

            # Extend the plotables dict with the files that we find that belong to this sile
            self.warehouse["plotables"] = {
                **self.warehouse["plotables"],
                **{
                    str(uuid.uuid4()): {
                        "name": path.name,
                        "path": path,
                        "plots": avail_plots,
                        "default_plot": default_plot
                    }
                    for path in filepaths
                }
            }

        #Avoid passing unnecessary info to the browser.
        return {
            id: {
                "id": id,
                **{
                    k: plotable[k]
                    for k in ["name", "path", "plots", "default_plot"]
                }, "chosenPlots": [plotable["default_plot"]]
            }
            for id, plotable in self.warehouse["plotables"].items()
        }

    def save(self, path, figs_only=False):
        """ Stores the session in disk.

        Parameters
        ----------
        path: str
            Path where the session should be saved.
        figs_only: boolean, optional
            Whether only figures should be saved, the rest of plot's data will be ignored.
        """
        session = copy(self)

        if figs_only:
            session.figures_only()

        for plotID, plot in session.plots.items():
            plot._get_pickleable()

        with open(path, 'wb') as handle:
            dill.dump(session, handle, protocol=dill.HIGHEST_PROTOCOL)

        return self
Beispiel #9
0
from sisl._environ import register_environ_variable, get_environ_variable

__all__ = [
    "import_user_presets", "import_user_plots", "import_user_sessions",
    "import_user_plugins"
]

# Define the folder where the user will store their stuff
register_environ_variable(
    "SISL_USER",
    Path.home() / ".sisl",
    "Path to the directory where the user stores their custom scripts "
    "to extend sisl.",
    process=Path)
USER_CUSTOM_FOLDER = (get_environ_variable("SISL_USER") / "viz") / "plotly"

# Here we let python know that there are importable files
# in USER_CUSTOM_FOLDER
sys.path.append(str(USER_CUSTOM_FOLDER.resolve()))


def import_user_extension(extension_file):
    """
    Basis for importing users extensions.

    Parameters
    ------------
    extension_file: str
        the name of the file that you want to import (NOT THE FULL PATH).
    """
Beispiel #10
0
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
import os
from pathlib import Path
import sys
import importlib

from sisl.messages import warn
from sisl._environ import get_environ_variable

__all__ = [
    "import_user_presets", "import_user_plots", "import_user_sessions",
    "import_user_plugins"
]

USER_CUSTOM_FOLDER = get_environ_variable("SISL_CONFIGDIR") / "viz" / "plotly"

# Here we let python know that there are importable files
# in USER_CUSTOM_FOLDER
sys.path.append(str(USER_CUSTOM_FOLDER.resolve()))


def import_user_extension(extension_file):
    """
    Basis for importing users extensions.

    Parameters
    ------------
    extension_file: str
        the name of the file that you want to import (NOT THE FULL PATH).
    """