Beispiel #1
0
    def _sortby_labelfile_list(self, labelfile_list, func_or_string, reverse=False, unpack=False):
        """
        Return: list of (label, abifile, param) tuples where param is obtained via ``func_or_string``.
            or labels, abifiles, params if ``unpack``
        """
        if not func_or_string:
            # Catch None or empty
            items = [(label, abifile, label) for (label, abifile) in labelfile_list]
            if not unpack:
                return items
            else:
                return [t[0] for t in items], [t[1] for t in items], [t[2] for t in items]

        elif callable(func_or_string):
            items = [(label, abifile, func_or_string(abifile)) for (label, abifile) in labelfile_list]

        else:
            # Assume string and attribute with the same name.
            # try in abifile.params if not hasattrd(abifile, func_or_string)
            self.is_sortable(func_or_string, raise_exc=True)
            if duck.hasattrd(self.abifiles[0], func_or_string):
                items = [(label, abifile, duck.getattrd(abifile, func_or_string)) for (label, abifile) in labelfile_list]
            else:
                items = [(label, abifile, abifile.params[func_or_string]) for (label, abifile) in labelfile_list]

        items = sorted(items, key=lambda t: t[2], reverse=reverse)
        if not unpack:
            return items
        else:
            return [t[0] for t in items], [t[1] for t in items], [t[2] for t in items]
Beispiel #2
0
    def group_and_sortby(self, hue, func_or_string):
        """
        Group files by ``hue`` and, inside each group` sort items by ``func_or_string``.

        Args:
            hue: Variable that define subsets of the data, which will be drawn on separate lines.
                Accepts callable or string
                If string, it's assumed that the abifile has an attribute with the same name and getattr is invoked.
                Dot notation is also supported e.g. hue="structure.formula" --> abifile.structure.formula
                If callable, the output of hue(abifile) is used.
            func_or_string: Either None, string, callable defining the quantity to be used for sorting.
                If string, it's assumed that the abifile has an attribute with the same name and getattr is invoked.
                If callable, the output of func_or_string(abifile) is used.
                If None, no sorting is performed.

        Return: List of :class:`HueGroup` instance.
        """
        # Group by hue.
        # This is the section in which we support: callable, abifile.attr.name syntax or abifile.params["key"]
        items = list(self.items())

        if callable(hue):
            key = lambda t: hue(t[1])
        else:
            # Assume string.
            if duck.hasattrd(self.abifiles[0], hue):
                key = lambda t: duck.getattrd(t[1], hue)
            else:
                # Try in abifile.params
                if hasattr(self.abifiles[0],
                           "params") and hue in self.abifiles[0].params:
                    key = lambda t: t[1].params[hue]
                else:
                    raise TypeError("""\
Cannot interpret hue argument of type `%s` and value `%s`.
Expecting callable or attribute name or key in abifile.params""" %
                                    (type(hue), str(hue)))

        groups = []
        for hvalue, labelfile_list in sort_and_groupby(items, key=key):
            # Use func_or_string to sort each group
            labels, abifiles, xvalues = self._sortby_labelfile_list(
                labelfile_list, func_or_string, unpack=True)
            groups.append(HueGroup(hvalue, xvalues, abifiles, labels))

        return groups
Beispiel #3
0
    def is_sortable(self, aname, raise_exc=False):
        """
        Return True if ``aname`` is an attribute of the netcdf file
        If raise_exc is True, AttributeError with an explicit message is raised.
        """
        try:
            obj = None
            try:
                # abiifile.foo.bar?
                obj = duck.getattrd(self.abifiles[0], aname)
            except AttributeError:
                # abifile.params[aname] ?
                if hasattr(self.abifiles[0],
                           "params") and aname in self.abifiles[0].params:
                    obj = self.abifiles[0].params[aname]

            # Let's try to convert obj to scalar.
            float(obj)
            return True

        except Exception:
            if not raise_exc: return False
            attrs = []
            for key, obj in inspect.getmembers(self.abifiles[0]):
                # Ignores anything starting with underscore
                if key.startswith('_') or callable(obj) or hasattr(
                        obj, "__len__"):
                    continue
                attrs.append(key)

            # Add entries in params.
            if hasattr(self.abifiles[0], "params") and hasattr(
                    self.abifiles[0].params, "keys"):
                attrs.extend(self.abifiles[0].params.keys())

            raise AttributeError("""\
`%s` object has no attribute `%s`. Choose among:

    %s

Note that this list is automatically generated.
Not all entries are sortable (Please select number-like quantities)""" %
                                 (self.__class__.__name__, aname, str(attrs)))
Beispiel #4
0
    def plot_convergence_items(self, items, sortby=None, hue=None, fontsize=6, **kwargs):
        """
        Plot the convergence of a list of ``items`` wrt to the ``sortby`` parameter.
        Values can optionally be grouped by ``hue``.

        Args:
            items: List of attributes (or callables) to be analyzed.
            sortby: Define the convergence parameter, sort files and produce plot labels.
                Can be None, string or function. If None, no sorting is performed.
                If string and not empty it's assumed that the abifile has an attribute
                with the same name and `getattr` is invoked.
                If callable, the output of sortby(abifile) is used.
            hue: Variable that define subsets of the data, which will be drawn on separate lines.
                Accepts callable or string
                If string, it's assumed that the abifile has an attribute with the same name and getattr is invoked.
                Dot notation is also supported e.g. hue="structure.formula" --> abifile.structure.formula
                If callable, the output of hue(abifile) is used.
            fontsize: legend and label fontsize.
            kwargs: keyword arguments are passed to ax.plot

        Returns: |matplotlib-Figure|
        """
        # Note: in principle one could call plot_convergence inside a loop but
        # this one is faster as sorting is done only once.

        # Build grid plot.
        nrows, ncols = len(items), 1
        ax_list, fig, plt = get_axarray_fig_plt(None, nrows=nrows, ncols=ncols,
                                                sharex=True, sharey=False, squeeze=False)
        ax_list = ax_list.ravel()

        # Sort and group files if hue.
        if hue is None:
            labels, ncfiles, params = self.sortby(sortby, unpack=True)
        else:
            groups = self.group_and_sortby(hue, sortby)

        marker = kwargs.pop("marker", "o")
        for i, (ax, item) in enumerate(zip(ax_list, items)):
            if hue is None:
                # Extract data.
                if callable(item):
                    yvals = [float(item(gsr)) for gsr in self.abifiles]
                else:
                    yvals = [duck.getattrd(gsr, item) for gsr in self.abifiles]

                if not is_string(params[0]):
                    ax.plot(params, yvals, marker=marker, **kwargs)
                else:
                    # Must handle list of strings in a different way.
                    xn = range(len(params))
                    ax.plot(xn, yvals, marker=marker, **kwargs)
                    ax.set_xticks(xn)
                    ax.set_xticklabels(params, fontsize=fontsize)
            else:
                for g in groups:
                    # Extract data.
                    if callable(item):
                        yvals = [float(item(gsr)) for gsr in g.abifiles]
                    else:
                        yvals = [duck.getattrd(gsr, item) for gsr in g.abifiles]
                    label = "%s: %s" % (self._get_label(hue), g.hvalue)
                    ax.plot(g.xvalues, yvals, label=label, marker=marker, **kwargs)

            ax.grid(True)
            ax.set_ylabel(self._get_label(item))
            if i == len(items) - 1:
                ax.set_xlabel("%s" % self._get_label(sortby))
                if sortby is None: rotate_ticklabels(ax, 15)
            if i == 0 and hue is not None:
                ax.legend(loc="best", fontsize=fontsize, shadow=True)

        return fig