Example #1
0
    def plot(self, units="eV", fontsize=8, **kwargs):
        """
        Plots the phonon frequencies, if available, along all the directions.
        The lines representing the fitted values will be shown as well.

        Args:
            ax: |matplotlib-Axes| or None if a new figure should be created.
            units: Units for phonon plots. Possible values in ("eV", "meV", "Ha", "cm-1", "Thz"). Case-insensitive.
            fontsize: fontsize for legends and titles

        Returns: |matplotlib-Figure|
        """
        ax, fig, plt = get_ax_fig_plt(ax=None)
        from matplotlib.gridspec import GridSpec

        nrows, ncols = math.ceil(self.n_directions / 2), 2
        gspec = GridSpec(nrows=nrows, ncols=ncols, wspace=0.15, hspace=0.25)

        for i in range(self.n_directions):
            axi = plt.subplot(gspec[i])
            self.plot_fit_freqs_dir(i,
                                    ax=axi,
                                    units=units,
                                    fontsize=fontsize,
                                    show=False)
            if i != self.n_directions - 1:
                set_visible(axi, False, "xlabel")
            if i != 0:
                set_visible(axi, False, "ylabel")

        return fig
Example #2
0
    def gridplot(self,
                 what_list=None,
                 sharex="row",
                 sharey="row",
                 fontsize=8,
                 **kwargs):
        """
        Plot the ``what`` value extracted from multiple HIST.nc_ files on a grid.

        Args:
            what_list: List of quantities to plot.
                Must be in ["energy", "abc", "angles", "volume", "pressure", "forces"]
            sharex: True if xaxis should be shared.
            sharey: True if yaxis should be shared.
            fontsize: fontsize for legend.

        Returns: |matplotlib-Figure|
        """
        what_list = list_strings(
            what_list) if what_list is not None else self.what_list

        # Build grid of plots.
        nrows, ncols = len(what_list), len(self)

        ax_mat, fig, plt = get_axarray_fig_plt(None,
                                               nrows=nrows,
                                               ncols=ncols,
                                               sharex=sharex,
                                               sharey=sharey,
                                               squeeze=False)
        ax_mat = np.reshape(ax_mat, (nrows, ncols))

        for irow, what in enumerate(what_list):
            for icol, hist in enumerate(self.abifiles):
                ax = ax_mat[irow, icol]
                ax.grid(True)
                hist.plot_ax(ax_mat[irow, icol],
                             what,
                             fontsize=fontsize,
                             marker="o")

                if irow == 0:
                    ax.set_title(hist.relpath, fontsize=fontsize)
                if irow != nrows - 1:
                    set_visible(ax, False, "xlabel")
                if icol != 0:
                    set_visible(ax, False, "ylabel")

        return fig
Example #3
0
    def plot(self, eb_ylims=None, **kwargs):
        """
        Plot electrons with possible (phonon-mediated) scattering channels for the CBM and VBM.
        Also plot phonon band structure and phonon PJDOS.

        Args:
            eb_ylims: Set the data limits for the y-axis of the electron band. Accept tuple e.g. ``(left, right)``
                or scalar e.g. ``left``. If None, limits are selected automatically.

        Return: |matplotlib-Figure|
        """
        # Build grid. Share y-axis for Phbands and Phdos
        import matplotlib.pyplot as plt
        fig = plt.figure()
        ax0 = plt.subplot2grid((3, 3), (0, 0), colspan=3, rowspan=2)
        ax1 = plt.subplot2grid((3, 3), (2, 0), colspan=2, rowspan=1)
        ax2 = plt.subplot2grid((3, 3), (2, 2), colspan=1, rowspan=1)
        ax1.get_shared_y_axes().join(ax1, ax2)

        # Plot electrons with possible e-ph scattering channels.
        self.eb_kpath.plot(ax=ax0,
                           with_gaps=True,
                           ylims=eb_ylims,
                           max_phfreq=self.phb_qpath.maxfreq,
                           show=False)

        # Plot phonon bands
        self.phb_qpath.plot(ax=ax1, show=False)
        #ax1.yaxis.set_visible(False)
        #set_visible(ax1, False, "ylabel")

        # Plot phonon PJDOS
        self.phdos_file.plot_pjdos_type(ax=ax2,
                                        fontsize=8,
                                        exchange_xy=True,
                                        show=False)
        set_visible(ax2, False, "ylabel")
        ax2.tick_params("y", left=False, labelleft=False)
        ax2.tick_params("y", right=True, labelright=True)

        # Adjust y-limits for phonons
        ylims = self.phb_qpath.minfreq, self.phb_qpath.maxfreq + 0.1 * abs(
            self.phb_qpath.maxfreq)
        for ax in (ax1, ax2):
            set_axlims(ax, ylims, "y")

        return fig
Example #4
0
    def plot_emass(self, acc=4, fontsize=6, colormap="viridis", **kwargs):
        """
        Plot electronic dispersion and quadratic curve based on the
        effective masses computed along each segment.

        Args:
            acc:
            fontsize: legend and title fontsize.
            colormap: matplotlib colormap
        """
        self._consistency_check()

        # Build grid of plots for this spin.
        num_plots, ncols, nrows = len(self.segments), 1, 1
        if num_plots > 1:
            ncols = 2
            nrows = (num_plots // ncols) + (num_plots % ncols)

        ax_list, fig, plt = get_axarray_fig_plt(None,
                                                nrows=nrows,
                                                ncols=ncols,
                                                sharex=False,
                                                sharey=True,
                                                squeeze=False)
        ax_list = ax_list.ravel()

        for iseg, (segment, ax) in enumerate(zip(self.segments, ax_list)):
            irow, icol = divmod(iseg, ncols)
            segment.plot_emass(ax=ax,
                               acc=acc,
                               fontsize=fontsize,
                               colormap=colormap,
                               show=False)
            if iseg != 0: set_visible(ax, False, "ylabel")
            if irow != nrows - 1: set_visible(ax, False, "xticklabels")

        # don't show the last ax if numeb is odd.
        if num_plots % ncols != 0: ax_list[-1].axis("off")

        return fig
Example #5
0
    def gridplot(self, what_list=None, sharex="row", sharey="row", fontsize=8, **kwargs):
        """
        Plot the ``what`` value extracted from multiple HIST.nc_ files on a grid.

        Args:
            what_list: List of quantities to plot.
                Must be in ["energy", "abc", "angles", "volume", "pressure", "forces"]
            sharex: True if xaxis should be shared.
            sharey: True if yaxis should be shared.
            fontsize: fontsize for legend.

        Returns: |matplotlib-Figure|
        """
        what_list = list_strings(what_list) if what_list is not None else self.what_list

        # Build grid of plots.
        nrows, ncols = len(what_list), len(self)

        ax_mat, fig, plt = get_axarray_fig_plt(None, nrows=nrows, ncols=ncols,
                                               sharex=sharex, sharey=sharey, squeeze=False)
        ax_mat = np.reshape(ax_mat, (nrows, ncols))

        for irow, what in enumerate(what_list):
            for icol, hist in enumerate(self.abifiles):
                ax = ax_mat[irow, icol]
                ax.grid(True)
                hist.plot_ax(ax_mat[irow, icol], what, fontsize=fontsize, marker="o")

                if irow == 0:
                    ax.set_title(hist.relpath, fontsize=fontsize)
                if irow != nrows - 1:
                    set_visible(ax, False, "xlabel")
                if icol != 0:
                    set_visible(ax, False, "ylabel")

        return fig
Example #6
0
    def plot_lattice_convergence(self,
                                 what_list=None,
                                 sortby=None,
                                 hue=None,
                                 fontsize=8,
                                 **kwargs):
        """
        Plot the convergence of the lattice parameters (a, b, c, alpha, beta, gamma).
        wrt the``sortby`` parameter. Values can optionally be grouped by ``hue``.

        Args:
            what_list: List of strings with the quantities to plot e.g. ["a", "alpha", "beta"].
                None means all.
            item: Define the quantity to plot. Accepts callable or string
                If string, it's assumed that the abifile has an attribute
                with the same name and `getattr` is invoked.
                If callable, the output of item(abifile) is used.
            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.
            ax: |matplotlib-Axes| or None if a new figure should be created.
            fontsize: legend and label fontsize.

        Returns: |matplotlib-Figure|

        Example:

             robot.plot_lattice_convergence()

             robot.plot_lattice_convergence(sortby="nkpt")

             robot.plot_lattice_convergence(sortby="nkpt", hue="tsmear")
        """
        if not self.abifiles: return None

        # The majority of AbiPy files have a structure object
        # whereas Hist.nc defines final_structure. Use geattr and key to extract structure object.
        key = "structure"
        if not hasattr(self.abifiles[0], "structure"):
            if hasattr(self.abifiles[0], "final_structure"):
                key = "final_structure"
            else:
                raise TypeError("Don't know how to extract structure from %s" %
                                type(self.abifiles[0]))

        # Define callbacks. docstrings will be used as ylabels.
        def a(afile):
            "a (Ang)"
            return getattr(afile, key).lattice.a

        def b(afile):
            "b (Ang)"
            return getattr(afile, key).lattice.b

        def c(afile):
            "c (Ang)"
            return getattr(afile, key).lattice.c

        def volume(afile):
            r"$V$"
            return getattr(afile, key).lattice.volume

        def alpha(afile):
            r"$\alpha$"
            return getattr(afile, key).lattice.alpha

        def beta(afile):
            r"$\beta$"
            return getattr(afile, key).lattice.beta

        def gamma(afile):
            r"$\gamma$"
            return getattr(afile, key).lattice.gamma

        items = [a, b, c, volume, alpha, beta, gamma]
        if what_list is not None:
            locs = locals()
            items = [locs[what] for what in list_strings(what_list)]

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

        marker = kwargs.pop("marker", "o")
        for i, (ax, item) in enumerate(zip(ax_list.ravel(), items)):
            self.plot_convergence(item,
                                  sortby=sortby,
                                  hue=hue,
                                  ax=ax,
                                  fontsize=fontsize,
                                  marker=marker,
                                  show=False)
            if i != 0:
                set_visible(ax, False, "legend")
            if i != len(items) - 1:
                set_visible(ax, False, "xlabel")

        return fig
Example #7
0
    def plot_uiso(self,
                  tstart=0,
                  tstop=600,
                  num=50,
                  what="displ",
                  view="inequivalent",
                  select_symbols=None,
                  colormap="jet",
                  xlims=None,
                  ylims=None,
                  sharey=False,
                  fontsize=10,
                  verbose=0,
                  **kwargs):
        """
        Plot phonon PJDOS for each atom in the unit cell.
        One subplot for each component, each subplot show all inequivalent sites.
        By default, only "inequivalent" atoms are shown.

        comparison of Ueq values, which
        are calculated as the mean of the diagonal elements of the harmonic ADP tensor, (d)
        comparison of the ADP anisotropy factor, which is defined as the ratio between maximum Uii
        and minimum Uii values. A ratio of 1 would correspond to an isotropic displacement.

        Args:
            tstart: The starting value (in Kelvin) of the temperature mesh.
            tstop: The end value (in Kelvin) of the mesh.
            num: int, optional Number of samples to generate.
            components: "all" for all components. "diag" for diagonal elements, "offdiag" for off-diagonal terms only.
            what: "displ" for displament, "vel" for velocity.
            view: "inequivalent" to show only inequivalent atoms. "all" for all sites.
            select_symbols: String or list of strings with chemical symbols. Used to select only atoms of this type.
            colormap: matplotlib colormap.
            xlims: Set the data limits for the x-axis. Accept tuple e.g. ``(left, right)``
                   or scalar e.g. ``left``. If left (right) is None, default values are used.
            ylims: Set the data limits for the y-axis. Accept tuple e.g. ``(left, right)``
                   or scalar e.g. ``left``. If left (right) is None, default values are used
            sharey: True if y-axis should be shared.
            fontsize: Legend and title fontsize.
            verbose: Verbosity level.

        Returns: |matplotlib-Figure|
        """
        # Select atoms.
        aview = self._get_atomview(view,
                                   select_symbols=select_symbols,
                                   verbose=verbose)

        ax_list, fig, plt = get_axarray_fig_plt(None,
                                                nrows=2,
                                                ncols=1,
                                                sharex=True,
                                                sharey=sharey,
                                                squeeze=True)
        cmap = plt.get_cmap(colormap)

        # Compute U(T)
        tmesh = np.linspace(tstart, tstop, num=num)
        msq = self.get_msq_tmesh(tmesh,
                                 iatom_list=aview.iatom_list,
                                 what_list=what)
        # [natom, 3, 3, nt]
        values = getattr(msq, what)
        ntemp = len(msq.tmesh)

        for ix, ax in enumerate(ax_list):
            ax.grid(True)
            set_axlims(ax, xlims, "x")
            set_axlims(ax, ylims, "y")
            if what == "displ":
                ylabel = r"$U_{iso}\;(\AA^2)$" if ix == 0 else \
                         r"Anisotropy factor ($\dfrac{\epsilon_{max}}{\epsilon_{min}}}$)"
            elif what == "vel":
                ylabel = r"$V_{iso}\;(m/s)^2$" if ix == 0 else \
                         r"Anisotropy factor ($\dfrac{\epsilon_{max}}{\epsilon_{min}}}$)"
            else:
                raise ValueError("Unknown value for what: `%s`" % str(what))
            ax.set_ylabel(ylabel, fontsize=fontsize)

            # Plot this component for all inequivalent atoms on the same subplot.
            for ii, (iatom, site_label) in enumerate(
                    zip(aview.iatom_list, aview.site_labels)):
                color = cmap(float(ii) / max((len(aview.iatom_list) - 1), 1))
                #msq.displ[iatom, 3, 3, nt]
                if ix == 0:
                    # ISO calculated as the mean of the diagonal elements of the harmonic ADP tensor
                    ys = np.trace(values[iatom]) / 3.0
                elif ix == 1:
                    # Ratio between maximum Uii and minimum Uii values.
                    # A ratio of 1 would correspond to an isotropic displacement.
                    ys = np.empty(ntemp)
                    for itemp in range(ntemp):
                        eigs = np.linalg.eigvalsh(values[iatom, :, :, itemp],
                                                  UPLO='U')
                        ys[itemp] = eigs.max() / eigs.min()
                else:
                    raise ValueError("Invalid ix index: `%s" % ix)

                ax.plot(msq.tmesh,
                        ys,
                        label=site_label if ix == 0 else None,
                        color=color)  #, marker="o")
                if ix == 0:
                    ax.legend(loc="best", fontsize=fontsize, shadow=True)

            if ix == len(ax_list) - 1:
                ax.set_xlabel("Temperature (K)")
            else:
                set_visible(ax, False, "xlabel", "xticklabels")

        return fig
Example #8
0
    def plot_tensor(self,
                    tstart=0,
                    tstop=600,
                    num=50,
                    components="all",
                    what="displ",
                    view="inequivalent",
                    select_symbols=None,
                    colormap="jet",
                    xlims=None,
                    ylims=None,
                    fontsize=10,
                    verbose=0,
                    **kwargs):
        """
        Plot tensor(T) for each atom in the unit cell.
        One subplot for each component, each subplot show all inequivalent sites.
        By default, only "inequivalent" atoms are shown.

        Args:
            tstart: The starting value (in Kelvin) of the temperature mesh.
            tstop: The end value (in Kelvin) of the mesh.
            num: int, optional Number of samples to generate.
            components: "all" for all components. "diag" for diagonal elements, "offdiag" for off-diagonal terms only.
            what: "displ" for displament, "vel" for velocity.
            view: "inequivalent" to show only inequivalent atoms. "all" for all sites.
            select_symbols: String or list of strings with chemical symbols. Used to select only atoms of this type.
            colormap: matplotlib colormap.
            xlims: Set the data limits for the x-axis. Accept tuple e.g. ``(left, right)``
                   or scalar e.g. ``left``. If left (right) is None, default values are used.
            ylims: Set the data limits for the y-axis. Accept tuple e.g. ``(left, right)``
                   or scalar e.g. ``left``. If left (right) is None, default values are used
            fontsize: Legend and title fontsize.
            verbose: Verbosity level.

        Returns: |matplotlib-Figure|
        """
        # Select atoms.
        aview = self._get_atomview(view,
                                   select_symbols=select_symbols,
                                   verbose=verbose)

        # One subplot for each component
        diag = ["xx", "yy", "zz"]
        offdiag = ["xy", "xz", "yz"]
        components = {
            "all": diag + offdiag,
            "diag": diag,
            "offdiag": offdiag,
        }[components]

        components = self._get_components(components)
        shape = np.reshape(components, (-1, 3)).shape
        nrows, ncols = shape[0], shape[1]

        ax_list, fig, plt = get_axarray_fig_plt(None,
                                                nrows=nrows,
                                                ncols=ncols,
                                                sharex=True,
                                                sharey=True,
                                                squeeze=True)
        ax_list = np.reshape(ax_list, (nrows, ncols)).ravel()
        cmap = plt.get_cmap(colormap)

        # Compute U(T)
        tmesh = np.linspace(tstart, tstop, num=num)
        msq = self.get_msq_tmesh(tmesh,
                                 iatom_list=aview.iatom_list,
                                 what_list=what)
        # [natom,3,3,nt] array
        values = getattr(msq, what)

        for ix, (ax, comp) in enumerate(zip(ax_list, components)):
            irow, icol = divmod(ix, ncols)
            ax.grid(True)
            set_axlims(ax, xlims, "x")
            set_axlims(ax, ylims, "y")
            ylabel = comp.get_tavg_label(what, with_units=True)
            ax.set_ylabel(ylabel, fontsize=fontsize)

            # Plot this component for all inequivalent atoms on the same subplot.
            for ii, (iatom, site_label) in enumerate(
                    zip(aview.iatom_list, aview.site_labels)):
                color = cmap(float(ii) / max((len(aview.iatom_list) - 1), 1))
                ys = comp.eval33w(values[iatom])
                ax.plot(msq.tmesh,
                        ys,
                        label=site_label if ix == 0 else None,
                        color=color)  #, marker="o")
                if ix == 0:
                    ax.legend(loc="best", fontsize=fontsize, shadow=True)

            if irow == 1:
                ax.set_xlabel('Temperature (K)')
            else:
                set_visible(ax, False, "xlabel", "xticklabels")

        return fig
Example #9
0
    def plot(self,
             components="upper",
             view="inequivalent",
             units="eV",
             select_symbols=None,
             xlims=None,
             ylims=None,
             sharey=False,
             fontsize=8,
             verbose=0,
             **kwargs):
        """
        Plot the generalized phonon DOS g_ij(omega, atom) for each atom in the unit cell.
        One subplot per atom. Each subplot shows the 9 independent components of the symmetric tensor.
        as a function of frequency. By default, only "inequivalent" atoms are shown.

        Args:
            view: "inequivalent" to show only inequivalent atoms. "all" for all sites.
            components: List of cartesian tensor components to plot e.g. ["xx", "xy"].
                "all" for all components. "upper" for the upper triangle, "diag" for diagonal elements.
            units: Units energy axis. Possible values in ("eV", "meV", "Ha", "cm-1", "Thz").
                Case-insensitive.
            select_symbols: String or list of strings with chemical symbols. Used to select only atoms of this type.
            xlims: Set the data limits for the x-axis. Accept tuple e.g. ``(left, right)``
                   or scalar e.g. ``left``. If left (right) is None, default values are used.
            ylims: Set the data limits for the y-axis.
            sharey: True if y-axis should be shared.
            fontsize: Legend and title fontsize.
            verbose: Verbosity level.

        Returns: |matplotlib-Figure|
        """
        # TODO Decide units for internal arrays.
        factor = abu.phfactor_ev2units(units)

        # Select atoms.
        aview = self._get_atomview(view, select_symbols, verbose=verbose)

        num_plots = len(aview.iatom_list)
        nrows, ncols = 1, 1
        if num_plots > 1:
            ncols = 2
            nrows = num_plots // ncols + num_plots % ncols

        ax_list, fig, plt = get_axarray_fig_plt(None,
                                                nrows=nrows,
                                                ncols=ncols,
                                                sharex=True,
                                                sharey=sharey,
                                                squeeze=True)
        ax_list = np.reshape(ax_list, (nrows, ncols)).ravel()
        # don't show the last ax if num_plots is odd.
        if num_plots % ncols != 0: ax_list[-1].axis("off")

        xx = self.wmesh * factor
        components = self._get_components(components)

        # For each atom in the view.
        for ix, (ax, iatom, site_label) in enumerate(
                zip(ax_list, aview.iatom_list, aview.site_labels)):
            irow, icol = divmod(ix, ncols)
            ax.grid(True)
            set_axlims(ax, xlims, "x")
            set_axlims(ax, ylims, "y")
            ax.set_title(site_label, fontsize=fontsize)
            #site = self.structure[iatom]
            #color = cmap(float(iatom) / max((len(iatom_list) - 1), 1))

            # Plot components for this atom on the same ax.
            for c in components:
                yw = c.eval33w(self.values[iatom])
                label = r"$G_{%s}$" % c.name if ix == 0 else None
                ax.plot(xx, yw / factor, label=label, **c.plot_kwargs)

            # Handle labels.
            if irow == nrows - 1:
                ax.set_xlabel('Frequency %s' % abu.phunit_tag(units))
            else:
                set_visible(ax, False, "xlabel", "xticklabels")

            if ix == 0:
                ax.set_ylabel(r"$g_{ij}(\omega)$ 1/%s (Cart coords)" %
                              abu.phunit_tag(units))
                ax.legend(loc="best", fontsize=fontsize, shadow=True)

        return fig
Example #10
0
    def plot_lattice_convergence(self, what_list=None, sortby=None, hue=None, fontsize=8, **kwargs):
        """
        Plot the convergence of the lattice parameters (a, b, c, alpha, beta, gamma).
        wrt the``sortby`` parameter. Values can optionally be grouped by ``hue``.

        Args:
            what_list: List of strings with the quantities to plot e.g. ["a", "alpha", "beta"].
                None means all.
            item: Define the quantity to plot. Accepts callable or string
                If string, it's assumed that the abifile has an attribute
                with the same name and `getattr` is invoked.
                If callable, the output of item(abifile) is used.
            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.
            ax: |matplotlib-Axes| or None if a new figure should be created.
            fontsize: legend and label fontsize.

        Returns: |matplotlib-Figure|

        Example:

             robot.plot_lattice_convergence()

             robot.plot_lattice_convergence(sortby="nkpt")

             robot.plot_lattice_convergence(sortby="nkpt", hue="tsmear")
        """
        if not self.abifiles: return None

        # The majority of AbiPy files have a structure object
        # whereas Hist.nc defines final_structure. Use geattr and key to extract structure object.
        key = "structure"
        if not hasattr(self.abifiles[0], "structure"):
            if hasattr(self.abifiles[0], "final_structure"):
                key = "final_structure"
            else:
                raise TypeError("Don't know how to extract structure from %s" % type(self.abifiles[0]))

        # Define callbacks. docstrings will be used as ylabels.
        def a(afile):
            "a (Ang)"
            return getattr(afile, key).lattice.a
        def b(afile):
            "b (Ang)"
            return getattr(afile, key).lattice.b
        def c(afile):
            "c (Ang)"
            return getattr(afile, key).lattice.c
        def volume(afile):
            r"$V$"
            return getattr(afile, key).lattice.volume
        def alpha(afile):
            r"$\alpha$"
            return getattr(afile, key).lattice.alpha
        def beta(afile):
            r"$\beta$"
            return getattr(afile, key).lattice.beta
        def gamma(afile):
            r"$\gamma$"
            return getattr(afile, key).lattice.gamma

        items = [a, b, c, volume, alpha, beta, gamma]
        if what_list is not None:
            locs = locals()
            items = [locs[what] for what in list_strings(what_list)]

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

        marker = kwargs.pop("marker", "o")
        for i, (ax, item) in enumerate(zip(ax_list.ravel(), items)):
            self.plot_convergence(item, sortby=sortby, hue=hue, ax=ax, fontsize=fontsize,
                                  marker=marker, show=False)
            if i != 0:
                set_visible(ax, False, "legend")
            if i != len(items) - 1:
                set_visible(ax, False, "xlabel")

        return fig