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)
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)
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)
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)
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)
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)
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)
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)
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
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
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)
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()]
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)
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
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
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
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)
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
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