A script to plot phonon band structure diagrams.

    Args:
        filename (str): Path to phonopy output. Can be a band structure yaml
            file, ``FORCE_SETS``, ``FORCE_CONSTANTS``, or
            ``force_constants.hdf5``.
        poscar (:obj:`str`, optional): Path to POSCAR file of unitcell. Not
            required if plotting the phonon band structure from a yaml file. If
            not specified, the script will search for a POSCAR file in the
            current directory.
        prefix (:obj:`str`, optional): Prefix for file names.
        directory (:obj:`str`, optional): The directory in which to save files.
        born (:obj:`str`, optional): Path to file containing Born effective
            charges. Should be in the same format as the file produced by the
            ``phonopy-vasp-born`` script provided by phonopy.
        qmesh (:obj:`list` of :obj:`int`, optional): Q-point mesh to use for
            calculating the density of state. Formatted as a 3x1 :obj:`list` of
            :obj:`int`.
        spg (:obj:`str` or :obj:`int`, optional): The space group international
            number or symbol to override the symmetry determined by spglib.
            This is not recommended and only provided for testing purposes.
            This option will only take effect when ``mode = 'bradcrack'``.
        primitive_matrix (:obj:`list`, optional): The transformation matrix
            from the conventional to primitive cell. Only required when the
            conventional cell was used as the starting structure. Should be
            provided as a 3x3 :obj:`list` of :obj:`float`.
        line_density (:obj:`int`, optional): Density of k-points along the
            path.
        units (:obj:`str`, optional): Units of phonon frequency. Accepted
            (case-insensitive) values are Thz, cm-1, eV, meV.
        symprec (:obj:`float`, optional): Tolerance for space-group-finding
            operations
        mode (:obj:`str`, optional): Method used for calculating the
            high-symmetry path. The options are:

            bradcrack
                Use the paths from Bradley and Cracknell. See [brad]_.

            pymatgen
                Use the paths from pymatgen. See [curt]_.

            seekpath
                Use the paths from SeeK-path. See [seek]_.

        kpt_list (:obj:`list`, optional): List of k-points to use, formatted as
            a list of subpaths, each containing a list of fractional k-points.
            For example::

                [ [[0., 0., 0.], [0., 0., 0.5]],
                  [[0.5, 0., 0.], [0.5, 0.5, 0.]] ]

            Will return points along ``0 0 0 -> 0 0 1/2 | 1/2 0 0
            -> 1/2 1/2 0``
        path_labels (:obj:`list`, optional): The k-point labels. These should
            be provided as a :obj:`list` of :obj:`str` for each subpath of the
            overall path. For example::

                [ ['Gamma', 'Z'], ['X', 'M'] ]

            combined with the above example for ``kpt_list`` would indicate the
            path: Gamma -> Z | X -> M. If no labels are provided, letters from
            A -> Z will be used instead.
        eigenvectors (:obj:`bool`, optional): Write the eigenvectors to the
            yaml file.
        dos (str): Path to Phonopy total dos .dat file
        height (:obj:`float`, optional): The height of the plot.
        width (:obj:`float`, optional): The width of the plot.
        ymin (:obj:`float`, optional): The minimum energy on the y-axis.
        ymax (:obj:`float`, optional): The maximum energy on the y-axis.
        style (:obj:`list` or :obj:`str`, optional): (List of) matplotlib style
            specifications, to be composed on top of Sumo base style.
        no_base_style (:obj:`bool`, optional): Prevent use of sumo base style.
            This can make alternative styles behave more predictably.
        image_format (:obj:`str`, optional): The image file format. Can be any
            format supported by matplotlib, including: png, jpg, pdf, and svg.
            Defaults to pdf.
        dpi (:obj:`int`, optional): The dots-per-inch (pixel density) for
            the image.
        plt (:obj:`matplotlib.pyplot`, optional): A
            :obj:`matplotlib.pyplot` object to use for plotting.
        fonts (:obj:`list`, optional): Fonts to use in the plot. Can be a
            a single font, specified as a :obj:`str`, or several fonts,
            specified as a :obj:`list` of :obj:`str`.

    Returns:
        A matplotlib pyplot object.

def phonon_bandplot(filename, poscar=None, prefix=None, directory=None,
                    dim=None, born=None, qmesh=None, spg=None,
                    primitive_axis=None, line_density=60, units='THz',
                    symprec=0.01, mode='bradcrack', kpt_list=None,
                    eigenvectors=False, labels=None, height=6., width=6.,
                    style=None, no_base_style=False,
                    ymin=None, ymax=None, image_format='pdf', dpi=400,
                    plt=None, fonts=None, dos=None):
    """A script to plot phonon band structure diagrams.

    Args:
        filename (str): Path to phonopy output. Can be a band structure yaml
            file, ``FORCE_SETS``, ``FORCE_CONSTANTS``, or
            ``force_constants.hdf5``.
        poscar (:obj:`str`, optional): Path to POSCAR file of unitcell. Not
            required if plotting the phonon band structure from a yaml file. If
            not specified, the script will search for a POSCAR file in the
            current directory.
        prefix (:obj:`str`, optional): Prefix for file names.
        directory (:obj:`str`, optional): The directory in which to save files.
        born (:obj:`str`, optional): Path to file containing Born effective
            charges. Should be in the same format as the file produced by the
            ``phonopy-vasp-born`` script provided by phonopy.
        qmesh (:obj:`list` of :obj:`int`, optional): Q-point mesh to use for
            calculating the density of state. Formatted as a 3x1 :obj:`list` of
            :obj:`int`.
        spg (:obj:`str` or :obj:`int`, optional): The space group international
            number or symbol to override the symmetry determined by spglib.
            This is not recommended and only provided for testing purposes.
            This option will only take effect when ``mode = 'bradcrack'``.
        primitive_matrix (:obj:`list`, optional): The transformation matrix
            from the conventional to primitive cell. Only required when the
            conventional cell was used as the starting structure. Should be
            provided as a 3x3 :obj:`list` of :obj:`float`.
        line_density (:obj:`int`, optional): Density of k-points along the
            path.
        units (:obj:`str`, optional): Units of phonon frequency. Accepted
            (case-insensitive) values are Thz, cm-1, eV, meV.
        symprec (:obj:`float`, optional): Tolerance for space-group-finding
            operations
        mode (:obj:`str`, optional): Method used for calculating the
            high-symmetry path. The options are:

            bradcrack
                Use the paths from Bradley and Cracknell. See [brad]_.

            pymatgen
                Use the paths from pymatgen. See [curt]_.

            seekpath
                Use the paths from SeeK-path. See [seek]_.

        kpt_list (:obj:`list`, optional): List of k-points to use, formatted as
            a list of subpaths, each containing a list of fractional k-points.
            For example::

                [ [[0., 0., 0.], [0., 0., 0.5]],
                  [[0.5, 0., 0.], [0.5, 0.5, 0.]] ]

            Will return points along ``0 0 0 -> 0 0 1/2 | 1/2 0 0
            -> 1/2 1/2 0``
        path_labels (:obj:`list`, optional): The k-point labels. These should
            be provided as a :obj:`list` of :obj:`str` for each subpath of the
            overall path. For example::

                [ ['Gamma', 'Z'], ['X', 'M'] ]

            combined with the above example for ``kpt_list`` would indicate the
            path: Gamma -> Z | X -> M. If no labels are provided, letters from
            A -> Z will be used instead.
        eigenvectors (:obj:`bool`, optional): Write the eigenvectors to the
            yaml file.
        dos (str): Path to Phonopy total dos .dat file
        height (:obj:`float`, optional): The height of the plot.
        width (:obj:`float`, optional): The width of the plot.
        ymin (:obj:`float`, optional): The minimum energy on the y-axis.
        ymax (:obj:`float`, optional): The maximum energy on the y-axis.
        style (:obj:`list` or :obj:`str`, optional): (List of) matplotlib style
            specifications, to be composed on top of Sumo base style.
        no_base_style (:obj:`bool`, optional): Prevent use of sumo base style.
            This can make alternative styles behave more predictably.
        image_format (:obj:`str`, optional): The image file format. Can be any
            format supported by matplotlib, including: png, jpg, pdf, and svg.
            Defaults to pdf.
        dpi (:obj:`int`, optional): The dots-per-inch (pixel density) for
            the image.
        plt (:obj:`matplotlib.pyplot`, optional): A
            :obj:`matplotlib.pyplot` object to use for plotting.
        fonts (:obj:`list`, optional): Fonts to use in the plot. Can be a
            a single font, specified as a :obj:`str`, or several fonts,
            specified as a :obj:`list` of :obj:`str`.

    Returns:
        A matplotlib pyplot object.
    """
    if '.yaml' in filename:
        yaml_file = filename
    elif ('FORCE_SETS' == filename or 'FORCE_CONSTANTS' == filename or
            '.hdf5' in filename):
        try:
            poscar = poscar if poscar else 'POSCAR'
            poscar = Poscar.from_file(poscar)
        except IOError:
            msg = "Cannot find POSCAR file, cannot generate symmetry path."
            logging.error("\n {}".format(msg))
            sys.exit()

        if not dim:
            logging.info("Supercell size (--dim option) not provided.\n"
                         "Attempting to guess supercell dimensions.\n")
            try:
                sposcar = Poscar.from_file("SPOSCAR")
            except IOError:
                msg = "Could not determine supercell size (use --dim flag)."
                logging.error("\n {}".format(msg))
                sys.exit()

            dim = (sposcar.structure.lattice.matrix *
                   poscar.structure.lattice.inv_matrix)

            # round due to numerical noise error
            dim = np.around(dim, 5)

        elif len(dim) == 9:
            dim = np.array(dim).reshape(3, 3)

        elif np.array(dim).shape != (3, 3):
            dim = np.diagflat(dim)

        logging.info("Using supercell with dimensions:")
        logging.info('\t' + str(dim).replace('\n', '\n\t')+'\n')

        factors = {'ev': VaspToEv, 'thz': VaspToTHz, 'mev': VaspToEv * 1000,
                   'cm-1': VaspToCm}

        phonon = load_phonopy(filename, poscar.structure, dim, symprec=symprec,
                              primitive_matrix=primitive_axis,
                              factor=factors[units.lower()],
                              symmetrise=True, born=born,
                              write_fc=False)

        # calculate band structure
        kpath, kpoints, labels = get_path_data(poscar.structure, mode=mode,
                                               symprec=symprec, spg=spg,
                                               kpt_list=kpt_list,
                                               labels=labels, phonopy=True)

        # todo: calculate dos and plot also
        # phonon.set_mesh(mesh, is_gamma_center=False, is_eigenvectors=True,
        #                 is_mesh_symmetry=False)
        # phonon.set_partial_DOS()

        phonon.set_band_structure(kpoints, is_eigenvectors=eigenvectors)
        yaml_file = 'sumo_band.yaml'
        phonon._band_structure.write_yaml(labels=labels, filename=yaml_file)

    else:
        msg = "Do not recognise file type of {}".format(filename)
        logging.error("\n {}".format(msg))
        sys.exit()

    save_files = False if plt else True  # don't save if pyplot object provided

    bs = get_ph_bs_symm_line(yaml_file, has_nac=False,
                             labels_dict=kpath.kpoints)

    # Replace dos filename with data array
    if dos is not None:
        if isfile(dos):
            dos = np.genfromtxt(dos, comments='#')
        elif dos:
            phonon.set_mesh(qmesh, is_gamma_center=False, is_eigenvectors=True,
                            is_mesh_symmetry=False)
            phonon.set_total_DOS()
            dos_freq, dos_val = phonon.get_total_DOS()
            dos = np.zeros((len(dos_freq), 2))
            dos[:, 0], dos[:, 1] = dos_freq, dos_val

    plotter = SPhononBSPlotter(bs)
    plt = plotter.get_plot(units=units, ymin=ymin, ymax=ymax, height=height,
                           width=width, plt=plt, fonts=fonts, dos=dos)

    if save_files:
        basename = 'phonon_band.{}'.format(image_format)
        filename = '{}_{}'.format(prefix, basename) if prefix else basename

        if directory:
            filename = os.path.join(directory, filename)

        if dpi is None:
            dpi = rcParams['figure.dpi']
        plt.savefig(filename, format=image_format, dpi=dpi,
                    bbox_inches='tight')

        filename = save_data_files(bs, prefix=prefix, directory=directory)
    else:
        return plt