def expanded_items(self):
     "Create a mapping from dataset numbers to variables that are expanded."
     ret = {}
     for item in map(self.topLevelItem, range(self.topLevelItemCount())):
         if item.isExpanded() and item.ds() is not None:
             ds = item.ds()
             ret[ds.psy.num] = d = {}
             for child in map(item.child, range(item.childCount())):
                 if child.childCount() and child.isExpanded():
                     d[child.text(0)] = variables = []
                     for vchild in map(child.child,
                                       range(child.childCount())):
                         if vchild.childCount() and vchild.isExpanded():
                             variables.append(vchild.text(0))
     return ret
Exemple #2
0
    def get_files(self, pattern):
        """Get input and output notebooks

        This method gets the files from the input directory that matches
        `pattern` and returns both, input files and output files

        Parameters
        ----------
        pattern: str or re pattern
            The pattern that has to match the filenames

        Returns
        -------
        dict
            A mapping from filenames in the :attr:`in_dir` to the corresponding
            filenames in the :attr:`out_dir`"""
        def get_ofile(odir, indir, infile):
            return infile.replace(indir, odir)
        if isinstance(pattern, six.string_types):
            pattern = re.compile(pattern)
        ret = defaultdict(dict)
        for indir, odir, paths in zip(self.in_dir, self.out_dir,
                                      map(os.walk, self.in_dir)):
            for file_dir, dirs, files in paths:
                if 'README.rst' not in files:
                    continue
                foutdir = file_dir.replace(indir, odir + os.path.sep)
                for f in filter(pattern.match, files):
                    ret[(file_dir, foutdir)][os.path.join(file_dir, f)] = \
                        os.path.join(foutdir, f)
        return ret
Exemple #3
0
def validate_line_xlim(val):
    if isinstance(val, six.string_types):
        val = (val, val)
    val = asarray(safe_list(val))
    if val.ndim == 1:
        val = asarray([val])
    return list(map(validate_limits, val.tolist()))
Exemple #4
0
def _get_abs_names(fnames):
    """Return the absolute paths of the given filenames"""
    if fnames is None:
        return
    for i, fname in enumerate(fnames):
        fnames[i] = ','.join(map(osp.abspath, fname.split(',')))
    return fnames
Exemple #5
0
    def __call__(self, l):
        """Validate whether `l` is a list with contents of :attr:`dtype`

        Parameters
        ----------
        l: list-like

        Returns
        -------
        list
            list with values of dtype :attr:`dtype`

        Raises
        ------
        ValueError"""
        try:
            if self.dtype is None:
                l = self.listtype(l)
            else:
                l = self.listtype(map(self.dtype, l))
        except TypeError:
            if self.dtype is None:
                raise ValueError(
                    "Could not convert to list!")
            else:
                raise ValueError(
                    "Could not convert to list of type %s!" % str(self.dtype))
        if self.length is not None and len(l) != self.length:
            raise ValueError('List with length %i is required! Not %i!' % (
                self.length, len(l)))
        return l
Exemple #6
0
 def setup_fmt_completion_model(self):
     fmtos = list(unique_everseen(map(
         self.get_name, chain.from_iterable(self.fmtos))))
     model = self.fmto_completer.model()
     model.setRowCount(len(fmtos))
     for i, name in enumerate(fmtos):
         model.setItem(i, QStandardItem(name))
 def refresh_items(self, item=None):
     if item is not None:
         item.add_variables()
     else:
         for item in map(self.topLevelItem,
                         range(self.topLevelItemCount())):
             item.add_variables()
Exemple #8
0
def _get_abs_names(fnames):
    """Return the absolute paths of the given filenames"""
    if fnames is None:
        return
    for i, fname in enumerate(fnames):
        if fname:
            fnames[i] = ','.join(map(osp.abspath, fname.split(',')))
    return fnames
 def setup_fmt_completion_model(self):
     fmtos = list(
         unique_everseen(map(self.get_name,
                             chain.from_iterable(self.fmtos))))
     model = self.fmto_completer.model()
     model.setRowCount(len(fmtos))
     for i, name in enumerate(fmtos):
         model.setItem(i, QStandardItem(name))
Exemple #10
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 #11
0
    def expand_items(self, expanded_items):
        """Expand tree items

        Parameters
        ----------
        expanded_items: dict
            A mapping as returned by the :meth:`expanded_items` method"""
        for top in map(self.topLevelItem, range(self.topLevelItemCount())):
            ds = top.ds()
            if ds.psy.num in expanded_items:
                self.expandItem(top)
                d = expanded_items[ds.psy.num]
                for child in map(top.child, range(top.childCount())):
                    if child.text(0) in d:
                        self.expandItem(child)
                        for vchild in map(child.child,
                                          range(child.childCount())):
                            if vchild.text(0) in d[child.text(0)]:
                                self.expandItem(vchild)
Exemple #12
0
 def fmto(self, value):
     name = self.get_name(value)
     for i, fmtos in enumerate(self.fmtos):
         if i == 1:  # all formatoptions
             continue
         if name in map(self.get_name, fmtos):
             with self.no_fmtos_update:
                 self.group_combo.setCurrentIndex(i)
             self.fill_fmt_combo(i, name)
             return
 def fmto(self, value):
     name = self.get_name(value)
     for i, fmtos in enumerate(self.fmtos):
         if i == 1:  # all formatoptions
             continue
         if name in map(self.get_name, fmtos):
             with self.no_fmtos_update:
                 self.group_combo.setCurrentIndex(i)
             self.fill_fmt_combo(i, name)
             return
Exemple #14
0
 def fill_fmt_combo(self, i):
     """Fill the :attr:`fmt_combo` combobox based on the current group name
     """
     if not self.no_fmtos_update:
         with self.no_fmtos_update:
             current_text = self.fmt_combo.currentText()
             self.fmt_combo.clear()
             self.fmt_combo.addItems(list(map(self.get_name,
                                              self.fmtos[i])))
             ind = self.fmt_combo.findText(current_text)
             self.fmt_combo.setCurrentIndex(ind if ind >= 0 else 0)
         self.show_fmt_info(self.fmt_combo.currentIndex())
Exemple #15
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)
 def add_figures_from_cp(self, project):
     """Add the items in this tree based upon the figures in the given
     project"""
     if project is None or not project.is_main:
         return
     for item in map(self.takeTopLevelItem, [0] * self.topLevelItemCount()):
         for child in item.takeChildren():
             child.disconnect_from_array()
     for fig, arrays in six.iteritems(project.figs):
         item = QTreeWidgetItem(0)
         item.setText(0, fig.canvas.get_window_title())
         item.addChildren([FiguresTreeItem(arr, 0) for arr in arrays])
         self.addTopLevelItem(item)
Exemple #17
0
 def update(self, value):
     for fmto in map(lambda key: getattr(self, key), self.dependencies):
         try:
             gl = fmto._gridliner
         except AttributeError:
             continue
         if self.plotter._initializing or self.plotter.has_changed(
                 fmto.key):
             gl.xlabel_style['size'] = value
             gl.ylabel_style['size'] = value
         else:
             for text in chain(gl.xlabel_artists, gl.ylabel_artists):
                 text.set_size(value)
 def add_figures_from_cp(self, project):
     """Add the items in this tree based upon the figures in the given
     project"""
     if project is None or not project.is_main:
         return
     for item in map(self.takeTopLevelItem, [0] * self.topLevelItemCount()):
         for child in item.takeChildren():
             child.disconnect_from_array()
     for fig, arrays in six.iteritems(project.figs):
         item = QTreeWidgetItem(0)
         item.setText(0, fig.canvas.get_window_title())
         item.addChildren(
             [FiguresTreeItem(weakref.ref(arr), 0) for arr in arrays])
         self.addTopLevelItem(item)
Exemple #19
0
    def add_base_str(self,
                     base_str,
                     pattern='.+',
                     pattern_base=None,
                     append=True):
        """
        Add further base string to this instance

        Parameters
        ----------
        base_str: str or list of str
            Strings that are used as to look for keys to get and set keys in
            the :attr:`base` dictionary. If a string does not contain
            ``'%(key)s'``, it will be appended at the end. ``'%(key)s'`` will
            be replaced by the specific key for getting and setting an item.
        pattern: str
            Default: ``'.+'``. This is the pattern that is inserted for
            ``%(key)s`` in a base string to look for matches (using the
            :mod:`re` module) in the `base` dictionary. The default `pattern`
            matches everything without white spaces.
        pattern_base: str or list or str
            If None, the whatever is given in the `base_str` is used.
            Those strings will be used for generating the final search
            patterns. You can specify this parameter by yourself to avoid the
            misinterpretation of patterns. For example for a `base_str` like
            ``'my.str'`` it is recommended to additionally provide the
            `pattern_base` keyword with ``'my\.str'``.
            Like for `base_str`, the ``%(key)s`` is appended if not already in
            the string.
        append: bool
            If True, the given `base_str` are appended (i.e. it is first
            looked for them in the :attr:`base` dictionary), otherwise they are
            put at the beginning"""
        base_str = safe_list(base_str)
        pattern_base = safe_list(pattern_base or [])
        for i, s in enumerate(base_str):
            if '%(key)s' not in s:
                base_str[i] += '%(key)s'
        if pattern_base:
            for i, s in enumerate(pattern_base):
                if '%(key)s' not in s:
                    pattern_base[i] += '%(key)s'
        else:
            pattern_base = base_str
        self.base_str = base_str + self.base_str
        self.patterns = list(map(lambda s: re.compile(s.replace(
            '%(key)s', '(?P<key>%s)' % pattern)), pattern_base)) + \
            self.patterns
Exemple #20
0
def validate_fit(val):
    def validate(val):
        if isinstance(val, six.string_types) and val.startswith('poly'):
            try:
                int(val[4:])
            except ValueError:
                raise ValueError("Polynomials must be of the form 'poly<deg>' "
                                 "(e.g. 'poly3'), not %s!" % val)
            else:
                return val
        elif hasattr(val, 'fit') and hasattr(val, 'predict'):
            return val
        return try_and_error(
            validate_callable, validate_none,
            ValidateInStrings('fit', ['fit', 'linear', 'robust'], True))(val)
    return list(map(validate, safe_list(val)))
Exemple #21
0
    def fill_combos_from_project(self, project):
        """Fill :attr:`group_combo` and :attr:`fmt_combo` from a project

        Parameters
        ----------
        project: psyplot.project.Project
            The project to use"""
        current_text = self.group_combo.currentText()
        with self.no_fmtos_update:
            self.group_combo.clear()
            if project is None or project.is_main or not len(project.plotters):
                self.fmt_combo.clear()
                self.groups = []
                self.fmtos = []
                self.line_edit.setEnabled(False)
                return
            self.line_edit.setEnabled(True)
            # get dimensions
            coords = sorted(project.coords_intersect)
            coords_name = [COORDSGROUP] if coords else []
            coords_verbose = ['Dimensions'] if coords else []
            coords = [coords] if coords else []

            # get formatoptions and group them alphabetically
            grouped_fmts = defaultdict(list)
            for fmto in project._fmtos:
                grouped_fmts[fmto.group].append(fmto)
            for val in six.itervalues(grouped_fmts):
                val.sort(key=self.get_name)
            grouped_fmts = OrderedDict(
                sorted(six.iteritems(grouped_fmts),
                       key=lambda t: psyp.groups.get(t[0], t[0])))
            fmt_groups = list(grouped_fmts.keys())
            # save original names
            self.groups = coords_name + [ALLGROUP] + fmt_groups
            # save verbose group names (which are used in the combo box)
            self.groupnames = coords_verbose + ['All formatoptions'] + list(
                map(lambda s: psyp.groups.get(s, s), fmt_groups))
            # save formatoptions
            fmtos = list(grouped_fmts.values())
            self.fmtos = coords + [sorted(chain(*fmtos), key=self.get_name)
                                   ] + fmtos
            self.group_combo.addItems(self.groupnames)
            ind = self.group_combo.findText(current_text)
            self.group_combo.setCurrentIndex(ind if ind >= 0 else 0)
        self.fill_fmt_combo(self.group_combo.currentIndex())
Exemple #22
0
 def fill_fmt_combo(self, i, current_text=None):
     """Fill the :attr:`fmt_combo` combobox based on the current group name
     """
     if not self.no_fmtos_update:
         with self.no_fmtos_update:
             if current_text is None:
                 current_text = self.fmt_combo.currentText()
             self.fmt_combo.clear()
             self.fmt_combo.addItems(
                 list(map(self.get_name, self.fmtos[i])))
             ind = self.fmt_combo.findText(current_text)
             self.fmt_combo.setCurrentIndex(ind if ind >= 0 else 0)
             # update completer model
             self.setup_fmt_completion_model()
         idx = self.fmt_combo.currentIndex()
         self.show_fmt_info(idx)
         self.load_fmt_widget(idx)
         self.set_current_fmt_value(idx)
 def fill_fmt_combo(self, i, current_text=None):
     """Fill the :attr:`fmt_combo` combobox based on the current group name
     """
     if not self.no_fmtos_update:
         with self.no_fmtos_update:
             if current_text is None:
                 current_text = self.fmt_combo.currentText()
             self.fmt_combo.clear()
             self.fmt_combo.addItems(list(map(self.get_name,
                                              self.fmtos[i])))
             ind = self.fmt_combo.findText(current_text)
             self.fmt_combo.setCurrentIndex(ind if ind >= 0 else 0)
             # update completer model
             self.setup_fmt_completion_model()
         idx = self.fmt_combo.currentIndex()
         self.show_fmt_info(idx)
         self.load_fmt_widget(idx)
         self.set_current_fmt_value(idx)
Exemple #24
0
 def filter_members(self, *args, **kwargs):
     ret = super(AutoSummClassDocumenter, self).filter_members(
         *args, **kwargs)
     if self.options.get('show-formatoptions') and hasattr(
             self.object, '_get_formatoptions'):
         fmt_members = defaultdict(set)
         all_fmt = set(self.object._get_formatoptions())
         for i, (mname, member, isattr) in enumerate(ret):
             if isinstance(member, Formatoption):
                 fmt_members[member.group].add((mname, member, isattr))
                 all_fmt.remove(mname)
         for fmt in all_fmt:
             fmto = getattr(self.object, fmt)
             fmt_members[fmto.group].add((fmt, fmto, True))
         ret.extend(
             (tup for tup in chain(*map(sorted, fmt_members.values()))
              if tup not in ret))
     return ret
Exemple #25
0
def validate_fix(val):
    if val is None:
        return [None]
    try:
        val = validate_float(val)
        return [[0, val]]
    except ValueError:
        pass
    msg = 'Values for the fix formatoptions must be of length 2!'
    validator = try_and_error(validate_none, validate_list(float))
    try:
        val = validator(val)
    except ValueError:
        val = list(map(validator, val))
        if not all(v is None or len(v) == 2 for v in val):
            raise ValueError(msg)
    else:
        if val is not None and len(val) != 2:
            raise ValueError(msg)
    return val
Exemple #26
0
 def create_py(self, nb, force=False):
     """Create the python script from the notebook node"""
     # Although we would love to simply use ``nbconvert.export_python(nb)``
     # this causes troubles in other cells processed by the ipython
     # directive. Instead of getting something like ``Out [5]:``, we get
     # some weird like '[0;31mOut[5]: ' which look like
     # color information if we allow the call of nbconvert.export_python
     if list(map(int, re.findall('\d+', nbconvert.__version__))) >= [4, 2]:
         py_file = os.path.basename(self.py_file)
     else:
         py_file = self.py_file
     spr.call(['jupyter', 'nbconvert', '--to=python',
               '--output=' + py_file, '--log-level=%s' % logger.level,
               self.outfile])
     with open(self.py_file) as f:
         py_content = f.read()
     # comment out ipython magics
     py_content = re.sub('^\s*get_ipython\(\).magic.*', '# \g<0>',
                         py_content, flags=re.MULTILINE)
     with open(self.py_file, 'w') as f:
         f.write(py_content)
Exemple #27
0
    def add_datasets_from_cp(self, project=None):
        """Clear the tree and add the datasets based upon the given `project`

        Parameters
        ----------
        project: psyplot.project.Project
            The project containing the data array. If the project is not a main
            project, it's main project is used.
        """
        if project is None:
            project = gcp(True)
            sp_arrs = ArrayList().arrays
        elif project.is_main:
            sp_arrs = gcp().arrays
        else:
            sp_arrs = project.arrays
            project = project.main

        expanded_items = self.expanded_items()
        # remove items from the tree
        self.clear()
        for i, ds_desc in six.iteritems(
                project._get_ds_descriptions(
                    project.array_info(ds_description='all'))):
            top_item = DatasetTreeItem(ds_desc['ds'], self.attr_columns, 0)
            if ds_desc['fname'] is not None and not all(
                    s is None for s in ds_desc['fname']):
                ds_desc['fname'] = ', '.join(
                    map(osp.basename, safe_list(ds_desc['fname'])))
            else:
                ds_desc['fname'] = None
            top_item.setText(
                0, '%s%i: %s' % ('*' if any(
                    any(arr is arr2 for arr2 in sp_arrs)
                    for arr in ds_desc['arr']) else '', i, ds_desc['fname']))
            for arr in ds_desc['arr']:
                arr.psy.onbasechange.connect(self.add_datasets_from_cp)
            self.addTopLevelItem(top_item)
        self.expand_items(expanded_items)
Exemple #28
0
def validate_stringlist(s):
    """Validate a list of strings

    Parameters
    ----------
    val: iterable of strings

    Returns
    -------
    list
        list of str

    Raises
    ------
    ValueError"""
    if isinstance(s, six.string_types):
        return [six.text_type(v.strip()) for v in s.split(',') if v.strip()]
    else:
        try:
            return list(map(validate_str, s))
        except TypeError as e:
            raise ValueError(e.message)
Exemple #29
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 #30
0
    def fill_combos_from_project(self, project):
        """Fill :attr:`group_combo` and :attr:`fmt_combo` from a project

        Parameters
        ----------
        project: psyplot.project.Project
            The project to use"""
        if rcParams['fmt.sort_by_key']:
            def sorter(fmto):
                return fmto.key
        else:
            sorter = self.get_name

        current_text = self.group_combo.currentText()
        with self.no_fmtos_update:
            self.group_combo.clear()
            if project is None or project.is_main or not len(project):
                self.fmt_combo.clear()
                self.groups = []
                self.fmtos = []
                self.line_edit.setEnabled(False)
                return
            self.line_edit.setEnabled(True)
            # get dimensions
            it_vars = chain.from_iterable(
                arr.psy.iter_base_variables for arr in project.arrays)
            dims = next(it_vars).dims
            sdims = set(dims)
            for var in it_vars:
                sdims.intersection_update(var.dims)
            coords = [d for d in dims if d in sdims]
            coords_name = [COORDSGROUP] if coords else []
            coords_verbose = ['Dimensions'] if coords else []
            coords = [coords] if coords else []

            if len(project.plotters):
                # get formatoptions and group them alphabetically
                grouped_fmts = defaultdict(list)
                for fmto in project._fmtos:
                    grouped_fmts[fmto.group].append(fmto)
                for val in six.itervalues(grouped_fmts):
                    val.sort(key=sorter)
                grouped_fmts = OrderedDict(
                    sorted(six.iteritems(grouped_fmts),
                           key=lambda t: psyp.groups.get(t[0], t[0])))
                fmt_groups = list(grouped_fmts.keys())
                # save original names
                self.groups = coords_name + [ALLGROUP] + fmt_groups
                # save verbose group names (which are used in the combo box)
                self.groupnames = (
                    coords_verbose + ['All formatoptions'] + list(
                        map(lambda s: psyp.groups.get(s, s), fmt_groups)))
                # save formatoptions
                fmtos = list(grouped_fmts.values())
                self.fmtos = coords + [sorted(
                    chain(*fmtos), key=sorter)] + fmtos
            else:
                self.groups = coords_name
                self.groupnames = coords_verbose
                self.fmtos = coords
            self.group_combo.addItems(self.groupnames)
            ind = self.group_combo.findText(current_text)
            self.group_combo.setCurrentIndex(ind if ind >= 0 else 0)
        self.fill_fmt_combo(self.group_combo.currentIndex())
Exemple #31
0
 def _iter_base_and_pattern(self, key):
     return zip(
         map(lambda s: safe_modulo(s, {'key': key}), self.base_str),
         self.patterns)
Exemple #32
0
 def process_directories(self):
     """Create the rst files from the input directories in the
     :attr:`in_dir` attribute"""
     for base_dir, target_dir, paths in zip(self.in_dir, self.out_dir, map(
             os.walk, self.in_dir)):
         self.recursive_processing(base_dir, target_dir, paths)
Exemple #33
0
    def recursive_processing(self, base_dir, target_dir, it):
        """Method to recursivly process the notebooks in the `base_dir`

        Parameters
        ----------
        base_dir: str
            Path to the base example directory (see the `examples_dir`
            parameter for the :class:`Gallery` class)
        target_dir: str
            Path to the output directory for the rst files (see the
            `gallery_dirs` parameter for the :class:`Gallery` class)
        it: iterable
            The iterator over the subdirectories and files in `base_dir`
            generated by the :func:`os.walk` function"""
        try:
            file_dir, dirs, files = next(it)
        except StopIteration:
            return '', []
        readme_files = {'README.md', 'README.rst', 'README.txt'}
        if readme_files.intersection(files):
            foutdir = file_dir.replace(base_dir, target_dir)
            create_dirs(foutdir)
            this_nbps = [
                NotebookProcessor(
                    infile=f,
                    outfile=os.path.join(foutdir, os.path.basename(f)),
                    disable_warnings=self.disable_warnings,
                    preprocess=(
                        (self.preprocess is True or f in self.preprocess) and
                        not (self.dont_preprocess is True or
                             f in self.dont_preprocess)),
                    clear=((self.clear is True or f in self.clear) and not
                           (self.dont_clear is True or f in self.dont_clear)))
                for f in map(lambda f: os.path.join(file_dir, f),
                             filter(self.pattern.match, files))]
            readme_file = next(iter(readme_files.intersection(files)))
        else:
            return '', []
        labels = OrderedDict()
        this_label = 'gallery_' + foutdir.replace(os.path.sep, '_')
        if this_label.endswith('_'):
            this_label = this_label[:-1]
        for d in dirs:
            label, nbps = self.recursive_processing(
                base_dir, target_dir, it)
            if label:
                labels[label] = nbps
        s = ".. _%s:\n\n" % this_label
        with open(os.path.join(file_dir, readme_file)) as f:
            s += f.read().rstrip() + '\n\n'

        s += "\n\n.. toctree::\n\n"
        s += ''.join('    %s\n' % os.path.splitext(os.path.basename(
            nbp.get_out_file()))[0] for nbp in this_nbps)
        for d in dirs:
            findex = os.path.join(d, 'index.rst')
            if os.path.exists(os.path.join(foutdir, findex)):
                s += '    %s\n' % os.path.splitext(findex)[0]

        s += '\n'

        for nbp in this_nbps:
                s += nbp.thumbnail_div + '\n'
        s += "\n.. raw:: html\n\n    <div style='clear:both'></div>\n"
        for label, nbps in labels.items():
            s += '\n.. only:: html\n\n    .. rubric:: :ref:`%s`\n\n' % (
                label)
            for nbp in nbps:
                s += nbp.thumbnail_div + '\n'
            s += "\n.. raw:: html\n\n    <div style='clear:both'></div>\n"

        s += '\n'

        with open(os.path.join(foutdir, 'index.rst'), 'w') as f:
            f.write(s)
        return this_label, list(chain(this_nbps, *labels.values()))
Exemple #34
0
from sphinx.ext.autodoc import (
    ClassDocumenter, ModuleDocumenter, ALL, AutoDirective, PycodeError,
    ModuleAnalyzer, bool_option, DataDocumenter, AttributeDocumenter,
    is_builtin_class_method, formatargspec, getargspec, force_decode,
    prepare_docstring)
import inspect
import sphinx.ext.autodoc as ad
from sphinx.ext.autosummary import Autosummary, ViewList, mangle_signature
from docutils import nodes
from psyplot.compat.pycompat import OrderedDict, map, filterfalse
try:
    from psyplot.plotter import Formatoption
except ImportError:
    pass

sphinx_version = list(map(float, re.findall('\d+', sphinx.__version__)[:3]))


class AutosummaryDocumenter(object):
    """Abstract class for for extending Documenter methods

    This classed is used as a base class for Documenters in order to provide
    the necessary methods for the :class:`AutoSummDirective`."""

    def __init__(self):
        raise NotImplementedError

    def get_grouped_documenters(self, all_members=False):
        """Method to return the member documenters

        This method is somewhat like a combination of the
Exemple #35
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 #36
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
Exemple #37
0
    def __init__(self, examples_dirs=['../examples'], gallery_dirs=None,
                 pattern='example_.+.ipynb', disable_warnings=True,
                 dont_preprocess=[], preprocess=True, clear=True,
                 dont_clear=[]):
        """
        Parameters
        ----------
        examples_dirs
            list containing the directories to loop through. Default:
            ``['../examples']``
        gallerys_dirs
            None or list of directories where the rst files shall be created.
            If None, the current working directory and the name of the
            corresponding directory in the `examples_dirs` is used. Default:
            ``None``
        pattern
            str. The pattern to use to find the ipython  notebooks.
            Default: ``'example_.+.ipynb'``
        disable_warnings
            Boolean controlling whether warnings shall be disabled when
            processing the examples. Defaultt: True
        preprocess
            If True, all examples (except those specified in the
            `dont_preprocess` item) will be preprocessed when creating the rst
            files. Otherwise it might be a list of files that shall be preprocessed.
        dont_preprocess
            If True, no example will be preprocessed when creating the rst
            files. Otherwise it might be a list of files that shall not be
            preprocessed
        clear
            If True, the output in all notebooks to download will be cleared.
            Otherwise it might be a list of notebook files of whom to clear the
            output
        dont_clear
            If True, the output in all notebooks to download will not be
            cleared. Otherwise it might be a list of notebook files  of whom
            not to clear the output"""

        if isinstance(examples_dirs, six.string_types):
            examples_dirs = [examples_dirs]
        if gallery_dirs is None:
            gallery_dirs = list(map(os.path.basename, examples_dirs))
        if isinstance(gallery_dirs, six.string_types):
            gallery_dirs = [gallery_dirs]

        for i, s in enumerate(examples_dirs):
            if not s.endswith(os.path.sep):
                examples_dirs[i] += os.path.sep

        for i, s in enumerate(gallery_dirs):
            if not s.endswith(os.path.sep):
                gallery_dirs[i] += os.path.sep

        self.in_dir = examples_dirs
        self.out_dir = gallery_dirs

        if isinstance(pattern, six.string_types):
            pattern = re.compile(pattern)
        self.pattern = pattern
        self.disable_warnings = disable_warnings
        self.dont_preprocess = dont_preprocess
        self.preprocess = preprocess
        self.clear = clear
        self.dont_clear = dont_clear
 def array_items(self):
     """Iterable of :class:`ArrayItem` items in this list"""
     return filter(lambda i: i is not None,
                   map(self.item, range(self.count())))
Exemple #39
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
 def array_items(self):
     """Iterable of :class:`ArrayItem` items in this list"""
     return filter(lambda i: i is not None,
                   map(self.item, range(self.count())))
Exemple #41
0
 def get_plots_item(self, item):
     for child in map(item.child, range(item.childCount())):
         if child.text(0) == 'Plots':
             return child