# Path: onecodex/lib/enums.py
# class Rank(BaseEnum):
#     """Python does not allow extending enums so we have to repeat the ranks."""
# 
#     Superkingdom = "superkingdom"
#     Kingdom = "kingdom"
#     Phylum = "phylum"
#     Class = "class"
#     Order = "order"
#     Family = "family"
#     Genus = "genus"
#     Species = "species"
#     Auto = "auto"
# 
# Path: onecodex/viz/_primitives.py
# def interleave_palette(domain, palette="ocx"):
#     from onecodex.viz import DEFAULT_PALETTES
# 
#     if palette in DEFAULT_PALETTES:
#         colors = DEFAULT_PALETTES[palette]
#     elif isinstance(palette, list):
#         colors = palette
#     else:
#         raise OneCodexException("A valid palette name or list of colors must be passed")
# 
#     n_rows = len(set(domain))
#     if n_rows == 0:
#         return []
# 
#     # We do some shuffling to optimize the range of colours with our own palette
#     if palette == "ocx":
#         hues, shades = 6, 4
# 
#         # Calculate how many shades to show of each hue
#         period = min(ceil(n_rows / hues), shades)
# 
#         # Save the darkest hue for last
#         offset = 0
#         if period < shades:
#             offset = 1
# 
#         # Generate a sub-palette with each hue, at each shade
#         sub_palettes = [colors[ix::shades] for ix in range(offset, period + offset)]
# 
#         # Interleave the sub-palettes so the individuals colors are ordered by hue, then shade
#         colors = list(chain.from_iterable(zip(*sub_palettes)))
# 
#     # Repeat the palette to extend it to the length of the domain
#     extended_palette = colors * (n_rows // len(colors)) + colors[: n_rows % len(colors)]
# 
#     return extended_palette
# 
# def prepare_props(title=None, height=None, width=None):
#     """Prepare key plotting kwargs for passing to Altair, which d/n like None values."""
#     props = {}
#     if title:
#         props["title"] = title  # None gets rendered as `None`
#     if height:
#         props["height"] = height  # None violates Vega JSON Schema
#     if width:
#         props["width"] = width  # None violates Vega JSON Schema
#     return props
# 
# def get_base_classification_url():
#     return os.environ.get("ONE_CODEX_API_BASE", "https://app.onecodex.com") + "/classification/"
# 
# Path: onecodex/exceptions.py
# class OneCodexException(Exception):
#     pass
# 
# class PlottingException(OneCodexException):
#     """User-facing plotting error for cases when the user may take action to resolve the issue."""
# 
#     pass
# 
# Path: onecodex/utils.py
# def is_continuous(series):
#     import pandas as pd
# 
#     return not (
#         pd.api.types.is_bool_dtype(series)
#         or pd.api.types.is_categorical_dtype(series)  # noqa
#         or pd.api.types.is_object_dtype(series)  # noqa
#     )
# 
# def has_missing_values(dataframe_or_series):
#     return dataframe_or_series.isnull().values.any()


from onecodex.lib.enums import Rank
from onecodex.viz._primitives import interleave_palette, prepare_props, get_base_classification_url
from onecodex.exceptions import OneCodexException, PlottingException
from onecodex.utils import is_continuous, has_missing_values
        from sklearn.decomposition import PCA
        import altair as alt
        import numpy as np
        import pandas as pd
        Examples
        --------
        Perform PCA on relative abundances at the species-level and color the resulting points by
        'geo_loc_name', a metadata field representing the geographical origin of each sample.

        >>> plot_pca(rank='species', normalize=True, color='geo_loc_name')

        Change the size of each point in the plot based on the abundance of Bacteroides.

        >>> plot_pca(size='Bacteroides')

        Display the abundances of Bacteroides, Prevotella, and Bifidobacterium in each sample when
        hovering over points in the plot.

        >>> plot_pca(tooltip=['Bacteroides', 'Prevotella', 'Bifidobacterium'])
        """
        # Deferred imports

        if rank is None:
            raise OneCodexException("Please specify a rank or 'auto' to choose automatically")

        if len(self._results) < 3:
            raise PlottingException(
                "There are too few samples for PCA after filtering. Please select 3 or more "
                "samples to plot."
            )

        df = self.to_df(rank=rank, normalize=normalize)

        if len(df.columns) < 2:

# Path: onecodex/lib/enums.py
# class Rank(BaseEnum):
#     """Python does not allow extending enums so we have to repeat the ranks."""
# 
#     Superkingdom = "superkingdom"
#     Kingdom = "kingdom"
#     Phylum = "phylum"
#     Class = "class"
#     Order = "order"
#     Family = "family"
#     Genus = "genus"
#     Species = "species"
#     Auto = "auto"
# 
# Path: onecodex/viz/_primitives.py
# def interleave_palette(domain, palette="ocx"):
#     from onecodex.viz import DEFAULT_PALETTES
# 
#     if palette in DEFAULT_PALETTES:
#         colors = DEFAULT_PALETTES[palette]
#     elif isinstance(palette, list):
#         colors = palette
#     else:
#         raise OneCodexException("A valid palette name or list of colors must be passed")
# 
#     n_rows = len(set(domain))
#     if n_rows == 0:
#         return []
# 
#     # We do some shuffling to optimize the range of colours with our own palette
#     if palette == "ocx":
#         hues, shades = 6, 4
# 
#         # Calculate how many shades to show of each hue
#         period = min(ceil(n_rows / hues), shades)
# 
#         # Save the darkest hue for last
#         offset = 0
#         if period < shades:
#             offset = 1
# 
#         # Generate a sub-palette with each hue, at each shade
#         sub_palettes = [colors[ix::shades] for ix in range(offset, period + offset)]
# 
#         # Interleave the sub-palettes so the individuals colors are ordered by hue, then shade
#         colors = list(chain.from_iterable(zip(*sub_palettes)))
# 
#     # Repeat the palette to extend it to the length of the domain
#     extended_palette = colors * (n_rows // len(colors)) + colors[: n_rows % len(colors)]
# 
#     return extended_palette
# 
# def prepare_props(title=None, height=None, width=None):
#     """Prepare key plotting kwargs for passing to Altair, which d/n like None values."""
#     props = {}
#     if title:
#         props["title"] = title  # None gets rendered as `None`
#     if height:
#         props["height"] = height  # None violates Vega JSON Schema
#     if width:
#         props["width"] = width  # None violates Vega JSON Schema
#     return props
# 
# def get_base_classification_url():
#     return os.environ.get("ONE_CODEX_API_BASE", "https://app.onecodex.com") + "/classification/"
# 
# Path: onecodex/exceptions.py
# class OneCodexException(Exception):
#     pass
# 
# class PlottingException(OneCodexException):
#     """User-facing plotting error for cases when the user may take action to resolve the issue."""
# 
#     pass
# 
# Path: onecodex/utils.py
# def is_continuous(series):
#     import pandas as pd
# 
#     return not (
#         pd.api.types.is_bool_dtype(series)
#         or pd.api.types.is_categorical_dtype(series)  # noqa
#         or pd.api.types.is_object_dtype(series)  # noqa
#     )
# 
# def has_missing_values(dataframe_or_series):
#     return dataframe_or_series.isnull().values.any()


# Path: onecodex/viz/_pca.py
from onecodex.lib.enums import Rank
from onecodex.viz._primitives import interleave_palette, prepare_props, get_base_classification_url
from onecodex.exceptions import OneCodexException, PlottingException
from onecodex.utils import is_continuous, has_missing_values
        from sklearn.decomposition import PCA
        import altair as alt
        import numpy as np
        import pandas as pd

        Examples
        --------
        Perform PCA on relative abundances at the species-level and color the resulting points by
        'geo_loc_name', a metadata field representing the geographical origin of each sample.

        >>> plot_pca(rank='species', normalize=True, color='geo_loc_name')

        Change the size of each point in the plot based on the abundance of Bacteroides.

        >>> plot_pca(size='Bacteroides')

        Display the abundances of Bacteroides, Prevotella, and Bifidobacterium in each sample when
        hovering over points in the plot.

        >>> plot_pca(tooltip=['Bacteroides', 'Prevotella', 'Bifidobacterium'])
        """
        # Deferred imports

        if rank is None:
            raise OneCodexException("Please specify a rank or 'auto' to choose automatically")

        if len(self._results) < 3:
            raise PlottingException(
                "There are too few samples for PCA after filtering. Please select 3 or more "
                "samples to plot."
            )

        df = self.to_df(rank=rank, normalize=normalize)

        if len(df.columns) < 2:

            raise PlottingException(