Exemple #1
0
    def delete_kwargs(self, base_key, args=None, kwargs=None):
        """
        Deletes the ``*args`` or ``**kwargs`` part from the parameters section

        Either `args` or `kwargs` must not be None. The resulting key will be
        stored in ``base_key + 'no_args_kwargs'

        Parameters
        ----------
        base_key: str
            The key in the :attr:`params` attribute to use
        args: None or str
            The string for the args to delete
        kwargs: None or str
            The string for the kwargs to delete"""
        if not args and not kwargs:
            warn("Neither args nor kwargs are given. I do nothing for %s" % (
                base_key))
            return
        types = []
        if args is not None:
            types.append('`?`?\*%s`?`?' % args)
        if kwargs is not None:
            types.append('`?`?\*\*%s`?`?' % kwargs)
        self.delete_types(base_key, 'no_args_kwargs', *types)
Exemple #2
0
    def __init__(self, *args, **kwargs):
        """
        Parameters
        ----------
        defaultParams: dict
            The defaultParams to use (see the :attr:`defaultParams` attribute).
            By default, the :attr:`psyplot.config.rcsetup.defaultParams`
            dictionary is used

        Other Parameters
        ----------------
        *args, **kwargs
            Any key-value pair for the initialization of the dictionary
        """
        defaultParams = kwargs.pop('defaultParams', None)
        if defaultParams is not None:
            self.defaultParams = defaultParams
        self._deprecated_map = {}
        self._deprecated_ignore_map = {}
        for k, v in six.iteritems(dict(*args, **kwargs)):
            try:
                self[k] = v
            except (ValueError, RuntimeError):
                # force the issue
                warn(_rcparam_warn_str.format(key=repr(k), value=repr(v),
                                              func='__init__'))
                dict.__setitem__(self, k, v)
Exemple #3
0
 def set_value(self, value, *args, **kwargs):
     # stream plots for circumpolar grids is not supported
     if (value == 'stream' and self.raw_data is not None and
             self.decoder.is_circumpolar(self.raw_data)):
         warn('Cannot make stream plots of circumpolar data!',
              logger=self.logger)
         value = 'quiver'
     super(MapVectorPlot, self).set_value(value, *args, **kwargs)
Exemple #4
0
def start_app(fnames=[], name=[], dims=None, plot_method=None, backend=False,
              output=None, project=None, engine=None, formatoptions=None,
              tight=False, new_instance=False, rc_file=None, rc_gui_file=None):
    """
    Eventually start the QApplication or only make a plot

    Parameters
    ----------
    %(make_plot.parameters)s
    backend: None or str
        The backend to use. By default, the ``'gui.backend'`` key in the
        :attr:`psyplot.rcParams` dictionary is used. Otherwise it can be None
        to use the standard matplotlib backend or a string identifying the
        backend
    new_instance: bool
        If True/set and the `output` parameter is not set, a new application is
        created
    rc_gui_file: str
        The path to a yaml configuration file that can be used to update  the
        :attr:`psyplot_gui.rcParams`
    """

    if project is not None and (name != [] or dims is not None):
        warn('The `name` and `dims` parameter are ignored if the `project`'
             ' parameter is set!')

    if rc_gui_file is not None:
        rcParams.load_from_file(rc_gui_file)

    if dims is not None and not isinstance(dims, dict):
        dims = dict(chain(*map(six.iteritems, dims)))

    if output is not None:
        return make_plot(
            fnames=fnames, name=name, dims=dims, plot_method=plot_method,
            output=output, project=project, engine=engine,
            formatoptions=formatoptions, tight=tight, rc_file=rc_file)

    # Lock file creation
    lock_file = osp.join(get_configdir(), 'psyplot.lock')
    lock = fasteners.InterProcessLock(lock_file)

    # Try to lock psyplot.lock. If it's *possible* to do it, then
    # there is no previous instance running and we can start a
    # new one. If *not*, then there is an instance already
    # running, which is locking that file
    lock_created = lock.acquire(False)

    if lock_created:
        # Start a new instance
        atexit.register(lock.release)
    elif not new_instance:
        send_files_to_psyplot(fnames, project, engine, plot_method, name, dims)
        return
    if backend is not False:
        rcParams['backend'] = backend
    from psyplot_gui.main import run_psyplot
    run_psyplot(fnames, project, engine, plot_method, name, dims)
Exemple #5
0
 def update(self, *args, **kwargs):
     for k, v in six.iteritems(dict(*args, **kwargs)):
         try:
             self[k] = v
         except (ValueError, RuntimeError):
             # force the issue
             warn(_rcparam_warn_str.format(key=repr(k), value=repr(v),
                                           func='update'))
             dict.__setitem__(self, k, v)
Exemple #6
0
 def get_attrs(self):
     from osr import SpatialReference
     attrs = self.ds.GetMetadata()
     try:
         sp = SpatialReference(wkt=self.ds.GetProjection())
         proj4 = sp.ExportToProj4()
     except:
         warn('Could not identify projection')
     else:
         attrs['proj4'] = proj4
     return FrozenOrderedDict(attrs)
Exemple #7
0
def safe_modulo(s, meta, checked='', print_warning=True):
    """Safe version of the modulo operation (%) of strings

    Parameters
    ----------
    s: str
        string to apply the modulo operation with
    meta: dict
        meta informations to insert
    checked: {'KEY', 'VALUE'}, optional
        Security parameter for the recursive structure of this function. It can
        be set to 'VALUE' if an error shall be raised when facing a TypeError
        or ValueError or to 'KEY' if an error shall be raised when facing a
        KeyError
    print_warning: bool
        If True and a key is not existent in `s`, a warning is raised


    Examples
    --------
    The effects are demonstrated by this example::

        >>> from psyplot.docstring import safe_modulo
        >>> s = "That's %(one)s string %(with)s missing 'with' and %s key"
        >>> s % {'one': 1}
        # raises KeyError because of missing 'with'
        >>> s% {'one': 1, 'with': 2}
        # raises TypeError because of '%s'
        >>> safe_modulo(s, {'one': 1})
        "That's 1 string %(with)s missing 'with' and %s key"
    """
    try:
        return s % meta
    except (ValueError, TypeError, KeyError):
        # replace the missing fields by %%
        keys = substitution_pattern.finditer(s)
        for m in keys:
            key = m.group('key')
            if not isinstance(meta, dict) or key not in meta:
                if print_warning:
                    warn("%r is not a valid key!" % key)
                full = m.group()
                s = s.replace(full, '%' + full)
        if 'KEY' not in checked:
            return safe_modulo(s, meta, checked=checked + 'KEY',
                               print_warning=print_warning)
        if not isinstance(meta, dict) or 'VALUE' in checked:
            raise
        s = sub(r"""(?<!%)(%%)*%(?!%) # uneven number of %
                    \s*(\w|$)         # format strings""", '%\g<0>', s,
                flags=VERBOSE)
        return safe_modulo(s, meta, checked=checked + 'VALUE',
                           print_warning=print_warning)
Exemple #8
0
 def _set_quiver_density(self, value):
     if all(val == 1.0 for val in value):
         self.plot._kwargs.pop('regrid_shape', None)
     elif self.decoder.is_unstructured(self.raw_data):
         warn("Quiver plot of unstructered data does not support the "
              "density keyword!", PsyPlotRuntimeWarning, logger=self.logger)
     elif self.decoder.is_circumpolar(self.raw_data):
         warn("Quiver plot of circumpolar data does not support the "
              "density keyword!", PsyPlotRuntimeWarning, logger=self.logger)
     else:
         shape = self.data.shape[-2:]
         value = map(int, [value[0]*shape[0], value[1]*shape[1]])
         self.plot._kwargs['regrid_shape'] = tuple(value)
Exemple #9
0
 def update(self, value):
     if value is None or value:
         # initialize a gridliner to see if we can draw the tick labels
         test_value = True
         try:
             Gridliner(
                 self.ax, self.ax.projection, draw_labels=test_value)
         except TypeError as e:  # labels cannot be drawn
             if value:
                 warn(e.message, PsyPlotRuntimeWarning, logger=self.logger)
             value = False
         else:
             value = True
     for connection in self.connections:
         getattr(self, connection)._kwargs['draw_labels'] = value
Exemple #10
0
 def _get_depreceated(self, key, *args):
     if key in self._deprecated_map:
         alt_key, alt_val = self._deprecated_map[key]
         warn(self.msg_depr % (key, alt_key))
         key = alt_key
         return key, alt_val(args[0]) if args else None
     elif key in self._deprecated_ignore_map:
         alt = self._deprecated_ignore_map[key]
         warn(self.msg_depr_ignore % (key, alt))
         return None, None
     elif key not in self.defaultParams:
         raise KeyError(
             '%s is not a valid rc parameter. See rcParams.keys() for a '
             'list of valid parameters.' % (key,))
     return key, args[0] if args else None
Exemple #11
0
 def _stream_plot(self):
     if self.decoder.is_circumpolar(self.raw_data):
         warn('Cannot make stream plots of circumpolar data!',
              logger=self.logger)
         return
     # update map extent such that it fits to the data limits (necessary
     # because streamplot scales the density based upon it). This however
     # does not work for matplotlib 1.5.0
     if not (mpl.__version__ == '1.5.0' and self.color.colored):
         self.ax.set_extent(self.lonlatbox.lonlatbox,
                            crs=ccrs.PlateCarree())
     else:
         self.ax.set_global()
     # Note that this method uses a bug fix through the
     # :class:`psyplot.plotter.colors.FixedColorMap` class
     # and one through the :class:`psyplot.plotter.colors.FixedBoundaryNorm`
     # class
     x, y, u, v = self._get_data()
     norm = self._kwargs.get('norm')
     if isinstance(norm, BoundaryNorm):
         self._kwargs['norm'] = FixedBoundaryNorm(
             norm.boundaries, norm.Ncmap, norm.clip)
     self._plot = self.ax.streamplot(x, y, u, v, **self._kwargs)
Exemple #12
0
    def lola_from_pattern(self, s):
        """
        Calculate the longitude-latitude box based upon a pattern

        This method uses the psyplot.rcParams ``'extents.boxes'`` item to find
        longitude that match `s` and takes the surrounding box.

        Parameters
        ----------
        s: str
            The pattern to use for the keys in the
            :attr:`psyplot.plotter.maps.lonlatboxes` dictionary and the
            ``'extents.boxes'`` item in the :attr:`psyplot.rcParams`

        Returns
        -------
        float: lonmin, lonmax, latmin, latmax or None
            The surrounding longitude-latitude box of all items in
            ``psyplot.rcParams['extents.boxes']`` whose key match `s` if there
            was any match. Otherwise None is returned
        """
        patt = re.compile(s)
        boxes = np.array([
            box for key, box in chain(*map(
                six.iteritems, [lonlatboxes, rcParams['lonlatbox.boxes']]))
            if patt.search(key)])
        if len(boxes) == 0:
            similar_keys = get_close_matches(s, rcParams['lonlatbox.boxes'])
            message = "Did not find any matches for %s!" % s
            if similar_keys:
                message += " Maybe you mean on of " + ', '.join(
                    similar_keys)
            warn(message, PsyPlotRuntimeWarning,
                 logger=self.logger)
            return
        return [boxes[:, 0].min(), boxes[:, 1].max(),
                boxes[:, 2].min(), boxes[:, 3].max()]
Exemple #13
0
    def load_plugins(self, raise_error=False):
        """
        Load the plotters and defaultParams from the plugins

        This method loads the `plotters` attribute and `defaultParams`
        attribute from the plugins that use the entry point specified by
        `group`. Entry points must be objects (or modules) that have a
        `defaultParams` and a `plotters` attribute.

        Parameters
        ----------
        raise_error: bool
            If True, an error is raised when multiple plugins define the same
            plotter or rcParams key. Otherwise only a warning is raised"""

        pm_env = os.getenv('PSYPLOT_PLOTMETHODS', '').split('::')
        include_pms = [s[4:] for s in pm_env if s.startswith('yes:')]
        exclude_pms = [s[3:] for s in pm_env if s.startswith('no:')]

        logger = logging.getLogger(__name__)

        plotters = self['project.plotters']
        def_plots = {'default': list(plotters)}
        defaultParams = self.defaultParams
        def_keys = {'default': defaultParams}

        def register_pm(ep, name):
            full_name = '%s:%s' % (ep.module, name)
            ret = True
            if pm_env == ['no']:
                ret = False
            elif name in exclude_pms or full_name in exclude_pms:
                ret = False
            elif include_pms and (name not in include_pms and
                                  full_name not in include_pms):
                ret = False
            if not ret:
                logger.debug('Skipping plot method %s', full_name)
            return ret

        for ep in self._load_plugin_entrypoints():
            try:
                plugin_mod = ep.load()
            except (ModuleNotFoundError, ImportError):
                logger.debug("Failed to import %s!" % (ep, ), exc_info=True)
                logger.warning("Failed to import %s!" % (ep, ))
                continue
            rc = plugin_mod.rcParams

            # load the plotters
            plugin_plotters = {
                key: val for key, val in rc.get('project.plotters', {}).items()
                if register_pm(ep, key)}
            already_defined = set(plotters).intersection(plugin_plotters)
            if already_defined:
                msg = ("Error while loading psyplot plugin %s! The "
                       "following plotters have already been "
                       "defined") % ep
                msg += 'and will be overwritten:' if not raise_error else ':'
                msg += '\n' + '\n'.join(chain.from_iterable(
                    (('%s by %s' % (key, plugin)
                      for plugin, keys in def_plots.items() if key in keys)
                     for key in already_defined)))
                if raise_error:
                    raise ImportError(msg)
                else:
                    warn(msg)
            for d in plugin_plotters.values():
                d['plugin'] = ep.module
            plotters.update(plugin_plotters)
            def_plots[ep] = list(plugin_plotters)

            # load the defaultParams keys
            plugin_defaultParams = rc.defaultParams
            already_defined = set(defaultParams).intersection(
                plugin_defaultParams) - {'project.plotters'}
            if already_defined:
                msg = ("Error while loading psyplot plugin %s! The "
                       "following default keys have already been "
                       "defined:") % ep
                msg += '\n' + '\n'.join(chain.from_iterable(
                    (('%s by %s' % (key, plugin)
                      for plugin, keys in def_keys.items() if key in keys)
                     for key in already_defined)))
                if raise_error:
                    raise ImportError(msg)
                else:
                    warn(msg)
            update_keys = set(plugin_defaultParams) - {'project.plotters'}
            def_keys[ep] = update_keys
            self.defaultParams.update(
                {key: plugin_defaultParams[key] for key in update_keys})

            # load the rcParams (without validation)
            super(RcParams, self).update({key: rc[key] for key in update_keys})

            # add the deprecated keys
            self._deprecated_ignore_map.update(rc._deprecated_ignore_map)
            self._deprecated_map.update(rc._deprecated_map)
Exemple #14
0
def make_plot(fnames=[], name=[], dims=None, plot_method=None,
              output=None, project=None, engine=None, formatoptions=None,
              tight=False, rc_file=None):
    """
    Eventually start the QApplication or only make a plot

    Parameters
    ----------
    fnames: list of str
        Either the filenames to show, or, if the `project` parameter is set,
        the a list of `,`-separated filenames to make a mapping from the
        original filename to a new one
    name: list of str
        The variable names to plot if the `output` parameter is set
    dims: dict
        A mapping from coordinate names to integers if the `project` is not
        given
    plot_method: str
        The name of the plot_method to use
    output: str or list of str
        If set, the data is loaded and the figures are saved to the specified
        filename and now graphical user interface is shown
    project: str
        If set, the project located at the given file name is loaded
    engine: str
        The engine to use for opening the dataset (see
        :func:`psyplot.data.open_dataset`)
    formatoptions: dict
        A dictionary of formatoption that is applied to the data visualized by
        the chosen `plot_method`
    tight: bool
        If True/set, it is tried to figure out the tight bbox of the figure and
        adjust the paper size of the `output` to it
    rc_file: str
        The path to a yaml configuration file that can be used to update  the
        :attr:`psyplot.rcParams`
    """

    if project is not None and (name != [] or dims is not None):
        warn('The `name` and `dims` parameter are ignored if the `project`'
             ' parameter is set!')
    if rc_file is not None:
        psyplot.rcParams.load_from_file(rc_file)

    if dims is not None and not isinstance(dims, dict):
        dims = dict(chain(*map(six.iteritems, dims)))

    if len(output) == 1:
        output = output[0]
    if not fnames and not project:
        raise ValueError(
            "Either a filename or a project file must be provided if "
            "the output parameter is set!")
    elif project is None and plot_method is None:
        raise ValueError(
            "A plotting method must be provided if the output parameter "
            "is set and not the project!")
    import psyplot.project as psy
    if project is not None:
        fnames = [s.split(',') for s in fnames]
        single_files = (l[0] for l in fnames if len(l) == 1)
        alternative_paths = defaultdict(lambda: next(single_files, None))
        alternative_paths.update([l for l in fnames if len(l) == 2])
        p = psy.Project.load_project(
            project, alternative_paths=alternative_paths,
            engine=engine)
        if formatoptions is not None:
            p.update(fmt=formatoptions)
        p.export(output, tight=tight)
    else:
        pm = getattr(psy.plot, plot_method, None)
        if pm is None:
            raise ValueError("Unknown plot method %s!" % plot_method)
        p = pm(
            fnames, name=name, dims=dims or {}, engine=engine,
            fmt=formatoptions or {}, mf_mode=True)
        p.export(output, tight=tight)
    return
Exemple #15
0
def start_app(fnames=[], name=[], dims=None, plot_method=None,
              output=None, project=None, engine=None, formatoptions=None,
              tight=False, encoding=None, enable_post=False,
              seaborn_style=None,
              concat_dim=get_default_value(xr.open_mfdataset, 'concat_dim'),
              backend=False, new_instance=False, rc_file=None,
              rc_gui_file=None, include_plugins=rcParams['plugins.include'],
              exclude_plugins=rcParams['plugins.exclude'], offline=False,
              pwd=None, script=None, command=None, exec_=True, callback=None):
    """
    Eventually start the QApplication or only make a plot

    Parameters
    ----------
    %(make_plot.parameters)s
    backend: None or str
        The backend to use. By default, the ``'gui.backend'`` key in the
        :attr:`psyplot.rcParams` dictionary is used. Otherwise it can be None
        to use the standard matplotlib backend or a string identifying the
        backend
    new_instance: bool
        If True/set and the `output` parameter is not set, a new application is
        created
    rc_gui_file: str
        The path to a yaml configuration file that can be used to update  the
        :attr:`psyplot_gui.rcParams`
    include_plugins: list of str
        The plugin widget to include. Can be either None to load all that are
        not explicitly excluded by `exclude_plugins` or a list of
        plugins to include. List items can be either module names, plugin
        names or the module name and widget via ``'<module_name>:<widget>'``
    exclude_plugins: list of str
        The plugin widgets to exclude. Can be either ``'all'`` to exclude
        all plugins or a list like in `include_plugins`.
    offline: bool
        If True/set, psyplot will be started in offline mode without
        intersphinx and remote access for the help explorer
    pwd: str
        The path to the working directory to use. Note if you do not provide
        any `fnames` or `project`, but set the `pwd`, it will switch the
        `pwd` of the current GUI.
    script: str
        The path to a python script that shall be run in the GUI. If the GUI
        is already running, the commands will be executed in this GUI.
    command: str
        Python commands that shall be run in the GUI. If the GUI is already
        running, the commands will be executed in this GUI
    exec_: bool
        If True, the main loop is entered.
    callback: str
        A unique identifier for the method that should be used if psyplot is
        already running. Set this parameter to None to avoid sending

    Returns
    -------
    None or :class:`psyplot_gui.main.MainWindow`
        ``None`` if `exec_` is True, otherwise the created
        :class:`~psyplot_gui.main.MainWindow` instance
    """
    if pwd is not None:
        os.chdir(pwd)
    if script is not None:
        script = osp.abspath(script)

    if project is not None and (name != [] or dims is not None):
        warn('The `name` and `dims` parameter are ignored if the `project`'
             ' parameter is set!')

    # load rcParams from file
    if rc_gui_file is not None:
        rcParams.load_from_file(rc_gui_file)

    # set plugins
    rcParams['plugins.include'] = include_plugins
    rcParams['plugins.exclude'] = exclude_plugins

    if offline:
        rcParams['help_explorer.online'] = False
        rcParams['help_explorer.use_intersphinx'] = False

    if dims is not None and not isinstance(dims, dict):
        dims = dict(chain(*map(six.iteritems, dims)))

    if output is not None:
        return make_plot(
            fnames=fnames, name=name, dims=dims, plot_method=plot_method,
            output=output, project=project, engine=engine,
            formatoptions=formatoptions, tight=tight, rc_file=rc_file,
            encoding=encoding, enable_post=enable_post,
            seaborn_style=seaborn_style, concat_dim=concat_dim)

    # Lock file creation
    lock_file = osp.join(get_configdir(), 'psyplot.lock')
    lock = fasteners.InterProcessLock(lock_file)

    # Try to lock psyplot.lock. If it's *possible* to do it, then
    # there is no previous instance running and we can start a
    # new one. If *not*, then there is an instance already
    # running, which is locking that file
    lock_created = lock.acquire(False)

    if lock_created:
        # Start a new instance
        atexit.register(lock.release)
    elif not new_instance:
        if callback is None:
            if fnames or project:
                callback = 'new_plot'
            elif pwd is not None:
                callback = 'change_cwd'
                fnames = [pwd]
            elif script is not None:
                callback = 'run_script'
                fnames = [script]
            elif command is not None:
                callback = 'command'
                engine = command
        if callback:
            send_files_to_psyplot(
                callback, fnames, project, engine, plot_method, name, dims,
                encoding, enable_post, seaborn_style, concat_dim)
        return
    elif new_instance:
        rcParams['main.listen_to_port'] = False
    if backend is not False:
        rcParams['backend'] = backend
    from psyplot_gui.main import MainWindow
    fnames = _get_abs_names(fnames)
    if project is not None:
        project = _get_abs_names([project])[0]
    if exec_:
        from psyplot_gui.compat.qtcompat import QApplication
        app = QApplication(sys.argv)
    mainwindow = MainWindow.run(fnames, project, engine, plot_method, name,
                                dims, encoding, enable_post, seaborn_style,
                                concat_dim)
    if script is not None:
        mainwindow.console.run_script_in_shell(script)
    if command is not None:
        mainwindow.console.kernel_manager.kernel.shell.run_code(command)
    if exec_:
        sys.exit(app.exec_())
    else:
        return mainwindow
Exemple #16
0
def start_app(fnames=[], name=[], dims=None, plot_method=None,
              output=None, project=None, engine=None, formatoptions=None,
              tight=False, encoding=None, enable_post=False,
              seaborn_style=None, output_project=None,
              concat_dim=get_default_value(xr.open_mfdataset, 'concat_dim'),
              chname={},
              backend=False, new_instance=False, rc_file=None,
              rc_gui_file=None, include_plugins=rcParams['plugins.include'],
              exclude_plugins=rcParams['plugins.exclude'], offline=False,
              pwd=None, script=None, command=None, exec_=True, use_all=False,
              callback=None, preset=None,
              opengl_implementation=None, webengineview=True):
    """
    Eventually start the QApplication or only make a plot

    Parameters
    ----------
    %(make_plot.parameters)s
    backend: None or str
        The backend to use. By default, the ``'gui.backend'`` key in the
        :attr:`~psyplot_gui.config.rcsetup.rcParams` dictionary is used.
        Otherwise it can be None to use the standard matplotlib backend or a
        string identifying the backend
    new_instance: bool
        If True/set and the `output` parameter is not set, a new application is
        created
    rc_gui_file: str
        The path to a yaml configuration file that can be used to update  the
        :attr:`~psyplot_gui.config.rcsetup.rcParams`
    include_plugins: list of str
        The plugin widget to include. Can be either None to load all that are
        not explicitly excluded by `exclude_plugins` or a list of
        plugins to include. List items can be either module names, plugin
        names or the module name and widget via ``'<module_name>:<widget>'``
    exclude_plugins: list of str
        The plugin widgets to exclude. Can be either ``'all'`` to exclude
        all plugins or a list like in `include_plugins`.
    offline: bool
        If True/set, psyplot will be started in offline mode without
        intersphinx and remote access for the help explorer
    pwd: str
        The path to the working directory to use. Note if you do not provide
        any `fnames` or `project`, but set the `pwd`, it will switch the
        `pwd` of the current GUI.
    script: str
        The path to a python script that shall be run in the GUI. If the GUI
        is already running, the commands will be executed in this GUI.
    command: str
        Python commands that shall be run in the GUI. If the GUI is already
        running, the commands will be executed in this GUI
    use_all: bool
        If True, use all variables. Note that this is the default if the
        `output` is specified and not `name`
    exec_: bool
        If True, the main loop is entered.
    callback: str
        A unique identifier for the method that should be used if psyplot is
        already running. Set this parameter to None to avoid sending
    opengl_implementation: {'software', 'desktop', 'gles', 'automatic'}
        OpenGL implementation to pass to Qt. Possible options are
        'software', 'desktop', 'gles' and 'automatic' (which let's PyQt
        decide).
    webengineview: bool
        If True (default), use an HTML help widget. This might not be available
        for all builds of PyQt5 under all circumstances. If not set, the
        rcParams key ``'help_explorer.use_webengineview'`` is used.

    Returns
    -------
    None or :class:`psyplot_gui.main.MainWindow`
        ``None`` if `exec_` is True, otherwise the created
        :class:`~psyplot_gui.main.MainWindow` instance
    """
    if pwd is not None:
        os.chdir(pwd)
    if script is not None:
        script = osp.abspath(script)

    if project is not None and (name != [] or dims is not None):
        warn('The `name` and `dims` parameter are ignored if the `project`'
             ' parameter is set!')

    # load rcParams from file
    if rc_gui_file is not None:
        rcParams.load_from_file(rc_gui_file)

    # set plugins
    rcParams['plugins.include'] = include_plugins
    rcParams['plugins.exclude'] = exclude_plugins
    if webengineview is not None:
        rcParams['help_explorer.use_webengineview'] = webengineview

    if offline:
        rcParams['help_explorer.online'] = False
        rcParams['help_explorer.use_intersphinx'] = False

    if dims is not None and not isinstance(dims, dict):
        dims = dict(chain(*map(six.iteritems, dims)))

    if output is not None:
        return make_plot(
            fnames=fnames, name=name, dims=dims, plot_method=plot_method,
            output=output, project=project, engine=engine,
            formatoptions=formatoptions, tight=tight, rc_file=rc_file,
            encoding=encoding, enable_post=enable_post,
            seaborn_style=seaborn_style, output_project=output_project,
            concat_dim=concat_dim, chname=chname, preset=preset)
    if use_all:
        name = 'all'
    else:
        name = safe_list(name)

    if formatoptions is not None:
        if not isinstance(formatoptions, dict):
            # list of dicts
            for fmt in formatoptions[1:]:
                formatoptions[0].update(fmt)
            formatoptions = formatoptions[0]
        if preset is not None:
            import psyplot.project as psy
            preset_data = psy.Project._load_preset(preset)
        else:
            preset_data = {}
        preset_data.update(formatoptions)
        preset = tempfile.NamedTemporaryFile(prefix='psy_', suffix='.yml').name
        with open(preset, 'w') as f:
            yaml.dump(preset_data, f)

    # make preset path absolute
    if preset is not None and not isinstance(preset, dict) and \
            osp.exists(preset):
        preset = osp.abspath(preset)

    # Lock file creation
    if not new_instance:
        lock_file = osp.join(get_configdir(), 'psyplot.lock')
        lock = fasteners.InterProcessLock(lock_file)

        # Try to lock psyplot.lock. If it's *possible* to do it, then
        # there is no previous instance running and we can start a
        # new one. If *not*, then there is an instance already
        # running, which is locking that file
        lock_created = lock.acquire(False)
    else:
        lock_created = False

    chname = dict(chname)

    if lock_created:
        # Start a new instance
        atexit.register(lock.release)
    elif not new_instance:
        if callback is None:
            if fnames or project:
                callback = 'new_plot'
            elif pwd is not None:
                callback = 'change_cwd'
                fnames = [pwd]
            elif script is not None:
                callback = 'run_script'
                fnames = [script]
            elif command is not None:
                callback = 'command'
                engine = command
        if callback:
            send_files_to_psyplot(
                callback, fnames, project, engine, plot_method, name, dims,
                encoding, enable_post, seaborn_style, concat_dim, chname,
                preset)
        return
    elif new_instance:
        rcParams['main.listen_to_port'] = False
    if backend is not False:
        rcParams['backend'] = backend
    from psyplot_gui.main import MainWindow
    fnames = _get_abs_names(fnames)
    if project is not None:
        project = _get_abs_names([project])[0]
    if exec_:
        from psyplot_gui.compat.qtcompat import QApplication
        app = QApplication(sys.argv)

    _set_opengl_implementation(opengl_implementation)

    if isinstance(new_instance, MainWindow):
        mainwindow = new_instance
    else:
        mainwindow = MainWindow.run(fnames, project, engine, plot_method, name,
                                    dims, encoding, enable_post, seaborn_style,
                                    concat_dim, chname, preset)
    if script is not None:
        mainwindow.console.run_script_in_shell(script)
    if command is not None:
        mainwindow.console.run_command_in_shell(command)
    if exec_:
        sys.excepthook = mainwindow.excepthook
        sys.exit(app.exec_())
    else:
        return mainwindow
Exemple #17
0
def show_colormaps(*args, **kwargs):
    """Function to show standard colormaps from pyplot

    Parameters
    ----------
    ``*args``: str or :class:`matplotlib.colors.Colormap`
        If a colormap, it returned unchanged.
        %(cmap_note)s
    N: int, optional
        Default: 11. The number of increments in the colormap.
    show: bool, optional
        Default: True. If True, show the created figure at the end with
        pyplot.show(block=False)

    Notes
    -----
    This function has been taken from [1]_ and enhanced in November 2014.

    References
    ----------
    .. [1] http://matplotlib.org/1.2.1/examples/pylab_examples/show_colormaps.html
    """
    import matplotlib.pyplot as plt
    # This example comes from the Cookbook on www.scipy.org.  According to the
    # history, Andrew Straw did the conversion from an old page, but it is
    # unclear who the original author is.
    a = np.vstack((np.linspace(0, 1, 256).reshape(1, -1)))
    # Get a list of the colormaps in matplotlib.  Ignore the ones that end with
    # '_r' because these are simply reversed versions of ones that don't end
    # with '_r'
    available_cmaps = list(
        chain(plt.cm.cmap_d, _cmapnames, rcParams['colors.cmaps']))
    args = list(args)
    wrongs = []
    for arg in (arg for arg in args if (not isinstance(arg, Colormap) and
                                        arg not in available_cmaps)):
        if isinstance(arg, str):
            similarkeys = get_close_matches(arg, available_cmaps)
        if similarkeys != []:
            warn("Colormap %s not found in standard colormaps.\n"
                 "Similar colormaps are %s." % (arg, ', '.join(similarkeys)))
        else:
            warn("Colormap %s not found in standard colormaps.\n"
                 "Run function without arguments to see all colormaps" % arg)
        args.remove(arg)
        wrongs.append(arg)
    if not args and not wrongs:
        args = sorted(m for m in available_cmaps if not m.endswith("_r"))
    nargs = len(args) + 1
    fig = plt.figure(figsize=(5, 10))
    fig.subplots_adjust(top=0.99, bottom=0.01, left=0.2, right=0.99)
    N = kwargs.pop('N', 11)
    show = kwargs.pop('show', True)
    if kwargs:
        raise TypeError(
            'show_colormaps() got an unexpected keyword argument %s' % (
                kwargs.keys[0]))

    for i, m in enumerate(args):
        ax = plt.subplot(nargs, 1, i+1)
        plt.axis("off")
        plt.pcolormesh(a, cmap=get_cmap(m, N))
        pos = list(ax.get_position().bounds)
        fig.text(pos[0] - 0.01, pos[1], m, fontsize=10,
                 horizontalalignment='right')
    fig.canvas.set_window_title("Figure %i: Predefined colormaps" % fig.number)
    if show:
        plt.show(block=False)
Exemple #18
0
def make_plot(fnames=[],
              name=[],
              dims=None,
              plot_method=None,
              output=None,
              project=None,
              engine=None,
              formatoptions=None,
              tight=False,
              rc_file=None,
              encoding=None,
              enable_post=False,
              seaborn_style=None,
              output_project=None,
              concat_dim=get_default_value(xr.open_mfdataset, 'concat_dim'),
              chname={}):
    """
    Eventually start the QApplication or only make a plot

    Parameters
    ----------
    fnames: list of str
        Either the filenames to show, or, if the `project` parameter is set,
        the a list of `,`-separated filenames to make a mapping from the
        original filename to a new one
    name: list of str
        The variable names to plot if the `output` parameter is set
    dims: dict
        A mapping from coordinate names to integers if the `project` is not
        given
    plot_method: str
        The name of the plot_method to use
    output: str or list of str
        If set, the data is loaded and the figures are saved to the specified
        filename and now graphical user interface is shown
    project: str
        If set, the project located at the given file name is loaded
    engine: str
        The engine to use for opening the dataset (see
        :func:`psyplot.data.open_dataset`)
    formatoptions: dict
        A dictionary of formatoption that is applied to the data visualized by
        the chosen `plot_method`
    tight: bool
        If True/set, it is tried to figure out the tight bbox of the figure and
        adjust the paper size of the `output` to it
    rc_file: str
        The path to a yaml configuration file that can be used to update  the
        :attr:`~psyplot.config.rcsetup.rcParams`
    encoding: str
        The encoding to use for loading the project. If None, it is
        automatically determined by pickle. Note: Set this to ``'latin1'``
        if using a project created with python2 on python3.
    enable_post: bool
        Enable the :attr:`~psyplot.plotter.Plotter.post` processing
        formatoption. If True/set, post processing scripts are enabled in the
        given `project`. Only set this if you are sure that you can trust the
        given project file because it may be a security vulnerability.
    seaborn_style: str
        The name of the style of the seaborn package that can be used for
        the :func:`seaborn.set_style` function
    output_project: str
        The name of a project file to save the project to
    concat_dim: str
        The concatenation dimension if multiple files in `fnames` are
        provided
    chname: dict
        A mapping from variable names in the project to variable names in the
        datasets that should be used instead
    """
    if project is not None and (name != [] or dims is not None):
        warn('The `name` and `dims` parameter are ignored if the `project`'
             ' parameter is set!')
    if rc_file is not None:
        rcParams.load_from_file(rc_file)

    if dims is not None and not isinstance(dims, dict):
        dims = dict(chain(*map(six.iteritems, dims)))

    if len(output) == 1:
        output = output[0]
    if not fnames and not project:
        raise ValueError(
            "Either a filename or a project file must be provided if "
            "the output parameter is set!")
    elif project is None and plot_method is None:
        raise ValueError(
            "A plotting method must be provided if the output parameter "
            "is set and not the project!")
    if seaborn_style is not None:
        import seaborn as sns
        sns.set_style(seaborn_style)
    import psyplot.project as psy
    if project is not None:
        fnames = [s.split(',') for s in fnames]
        chname = dict(chname)
        single_files = (l[0] for l in fnames if len(l) == 1)
        alternative_paths = defaultdict(lambda: next(single_files, None))
        alternative_paths.update([l for l in fnames if len(l) == 2])
        p = psy.Project.load_project(project,
                                     alternative_paths=alternative_paths,
                                     engine=engine,
                                     encoding=encoding,
                                     enable_post=enable_post,
                                     chname=chname)
        if formatoptions is not None:
            p.update(fmt=formatoptions)
        p.export(output, tight=tight)
    else:
        pm = getattr(psy.plot, plot_method, None)
        if pm is None:
            raise ValueError("Unknown plot method %s!" % plot_method)
        kwargs = {'name': name} if name else {}
        p = pm(fnames,
               dims=dims or {},
               engine=engine,
               fmt=formatoptions or {},
               mf_mode=True,
               concat_dim=concat_dim,
               **kwargs)
        p.export(output, tight=tight)
    if output_project is not None:
        p.save_project(output_project)
    return
Exemple #19
0
def start_app(fnames=[], name=[], dims=None, plot_method=None,
              output=None, project=None, engine=None, formatoptions=None,
              tight=False, encoding=None, enable_post=False,
              seaborn_style=None, output_project=None,
              concat_dim=get_default_value(xr.open_mfdataset, 'concat_dim'),
              chname={},
              backend=False, new_instance=False, rc_file=None,
              rc_gui_file=None, include_plugins=rcParams['plugins.include'],
              exclude_plugins=rcParams['plugins.exclude'], offline=False,
              pwd=None, script=None, command=None, exec_=True, use_all=False,
              callback=None):
    """
    Eventually start the QApplication or only make a plot

    Parameters
    ----------
    %(make_plot.parameters)s
    backend: None or str
        The backend to use. By default, the ``'gui.backend'`` key in the
        :attr:`~psyplot_gui.config.rcsetup.rcParams` dictionary is used.
        Otherwise it can be None to use the standard matplotlib backend or a
        string identifying the backend
    new_instance: bool
        If True/set and the `output` parameter is not set, a new application is
        created
    rc_gui_file: str
        The path to a yaml configuration file that can be used to update  the
        :attr:`~psyplot_gui.config.rcsetup.rcParams`
    include_plugins: list of str
        The plugin widget to include. Can be either None to load all that are
        not explicitly excluded by `exclude_plugins` or a list of
        plugins to include. List items can be either module names, plugin
        names or the module name and widget via ``'<module_name>:<widget>'``
    exclude_plugins: list of str
        The plugin widgets to exclude. Can be either ``'all'`` to exclude
        all plugins or a list like in `include_plugins`.
    offline: bool
        If True/set, psyplot will be started in offline mode without
        intersphinx and remote access for the help explorer
    pwd: str
        The path to the working directory to use. Note if you do not provide
        any `fnames` or `project`, but set the `pwd`, it will switch the
        `pwd` of the current GUI.
    script: str
        The path to a python script that shall be run in the GUI. If the GUI
        is already running, the commands will be executed in this GUI.
    command: str
        Python commands that shall be run in the GUI. If the GUI is already
        running, the commands will be executed in this GUI
    use_all: bool
        If True, use all variables. Note that this is the default if the
        `output` is specified and not `name`
    exec_: bool
        If True, the main loop is entered.
    callback: str
        A unique identifier for the method that should be used if psyplot is
        already running. Set this parameter to None to avoid sending

    Returns
    -------
    None or :class:`psyplot_gui.main.MainWindow`
        ``None`` if `exec_` is True, otherwise the created
        :class:`~psyplot_gui.main.MainWindow` instance
    """
    if pwd is not None:
        os.chdir(pwd)
    if script is not None:
        script = osp.abspath(script)

    if project is not None and (name != [] or dims is not None):
        warn('The `name` and `dims` parameter are ignored if the `project`'
             ' parameter is set!')

    # load rcParams from file
    if rc_gui_file is not None:
        rcParams.load_from_file(rc_gui_file)

    # set plugins
    rcParams['plugins.include'] = include_plugins
    rcParams['plugins.exclude'] = exclude_plugins

    if offline:
        rcParams['help_explorer.online'] = False
        rcParams['help_explorer.use_intersphinx'] = False

    if dims is not None and not isinstance(dims, dict):
        dims = dict(chain(*map(six.iteritems, dims)))

    if output is not None:
        return make_plot(
            fnames=fnames, name=name, dims=dims, plot_method=plot_method,
            output=output, project=project, engine=engine,
            formatoptions=formatoptions, tight=tight, rc_file=rc_file,
            encoding=encoding, enable_post=enable_post,
            seaborn_style=seaborn_style, output_project=output_project,
            concat_dim=concat_dim, chname=chname)
    if use_all:
        name = 'all'
    else:
        name = safe_list(name)

    # Lock file creation
    if not new_instance:
        lock_file = osp.join(get_configdir(), 'psyplot.lock')
        lock = fasteners.InterProcessLock(lock_file)

        # Try to lock psyplot.lock. If it's *possible* to do it, then
        # there is no previous instance running and we can start a
        # new one. If *not*, then there is an instance already
        # running, which is locking that file
        lock_created = lock.acquire(False)
    else:
        lock_created = False

    chname = dict(chname)

    if lock_created:
        # Start a new instance
        atexit.register(lock.release)
    elif not new_instance:
        if callback is None:
            if fnames or project:
                callback = 'new_plot'
            elif pwd is not None:
                callback = 'change_cwd'
                fnames = [pwd]
            elif script is not None:
                callback = 'run_script'
                fnames = [script]
            elif command is not None:
                callback = 'command'
                engine = command
        if callback:
            send_files_to_psyplot(
                callback, fnames, project, engine, plot_method, name, dims,
                encoding, enable_post, seaborn_style, concat_dim, chname)
        return
    elif new_instance:
        rcParams['main.listen_to_port'] = False
    if backend is not False:
        rcParams['backend'] = backend
    from psyplot_gui.main import MainWindow
    fnames = _get_abs_names(fnames)
    if project is not None:
        project = _get_abs_names([project])[0]
    if exec_:
        from psyplot_gui.compat.qtcompat import QApplication
        app = QApplication(sys.argv)
    if isinstance(new_instance, MainWindow):
        mainwindow = new_instance
    else:
        mainwindow = MainWindow.run(fnames, project, engine, plot_method, name,
                                    dims, encoding, enable_post, seaborn_style,
                                    concat_dim, chname)
    if script is not None:
        mainwindow.console.run_script_in_shell(script)
    if command is not None:
        mainwindow.console.run_command_in_shell(command)
    if exec_:
        sys.excepthook = mainwindow.excepthook
        sys.exit(app.exec_())
    else:
        return mainwindow