"""
The full content is this module is copied from xarray.plot.utils.py. Unused
parts are removed, so this module only contains about a third of the original's
content.

Additionally, _easy_facetgrid has been copied from xarray.plot.facetgrid.

The reason is that these functions are all private methods. Hence, Xarray
provides no guarantees on breaking changes.

We heavily discourage editing this file. Any update should only consist of
copying updated parts of the xarray module.

Some minor edits are necessary. These are marked by an comment with "EDIT:".

Xarray is licensed under Apache License 2.0:
https://github.com/pydata/xarray/blob/main/LICENSE
"""
from __future__ import annotations

import importlib
import textwrap
from collections.abc import Callable, Hashable, Iterable, Mapping
from datetime import datetime
from inspect import getfullargspec
from typing import TYPE_CHECKING, Any, Literal, TypeVar, Union

import numpy as np
from xarray import DataArray, Dataset
from xarray.plot.facetgrid import FacetGrid

# EDIT: added these here
AspectOptions = Union[Literal["auto", "equal"], float, None]
ScaleOptions = Literal["linear", "symlog", "log", "logit", None]
T_DataArrayOrSet = TypeVar("T_DataArrayOrSet", bound=Union["Dataset", "DataArray"])
nc_time_axis_available = importlib.util.find_spec("nc_time_axis") is not None

try:
    import cftime
except ImportError:
    cftime = None

if TYPE_CHECKING:
    from matplotlib.axes import Axes
    from numpy.typing import ArrayLike

    try:
        import matplotlib.pyplot as plt
    except ImportError:
        plt: Any = None  # type: ignore

ROBUST_PERCENTILE = 2.0

__all__ = [
    "_add_colorbar",
    "_ensure_plottable",
    "_process_cmap_cbar_kwargs",
    "_update_axes",
    "get_axis",
    "label_from_attrs",
    "_easy_facetgrid",
]

def _determine_extend(calc_data, vmin, vmax):
    extend_min = calc_data.min() < vmin
    extend_max = calc_data.max() > vmax
    if extend_min and extend_max:
        return "both"
    elif extend_min:
        return "min"
    elif extend_max:
        return "max"
    else:
        return "neither"

def _build_discrete_cmap(cmap, levels, extend, filled):
    """
    Build a discrete colormap and normalization of the data.
    """
    import matplotlib as mpl

    if len(levels) == 1:
        levels = [levels[0], levels[0]]

    if not filled:
        # non-filled contour plots
        extend = "max"

    if extend == "both":
        ext_n = 2
    elif extend in ["min", "max"]:
        ext_n = 1
    else:
        ext_n = 0

    n_colors = len(levels) + ext_n - 1
    pal = _color_palette(cmap, n_colors)

    new_cmap, cnorm = mpl.colors.from_levels_and_colors(levels, pal, extend=extend)
    # copy the old cmap name, for easier testing
    new_cmap.name = getattr(cmap, "name", cmap)

    # copy colors to use for bad, under, and over values in case they have been
    # set to non-default values
    try:
        # matplotlib<3.2 only uses bad color for masked values
        bad = cmap(np.ma.masked_invalid([np.nan]))[0]
    except TypeError:
        # cmap was a str or list rather than a color-map object, so there are
        # no bad, under or over values to check or copy
        pass
    else:
        under = cmap(-np.inf)
        over = cmap(np.inf)

        new_cmap.set_bad(bad)

        # Only update under and over if they were explicitly changed by the user
        # (i.e. are different from the lowest or highest values in cmap). Otherwise
        # leave unchanged so new_cmap uses its default values (its own lowest and
        # highest values).
        if under != cmap(0):
            new_cmap.set_under(under)
        if over != cmap(cmap.N - 1):
            new_cmap.set_over(over)

    return new_cmap, cnorm

def _color_palette(cmap, n_colors):
    import matplotlib.pyplot as plt
    from matplotlib.colors import ListedColormap

    colors_i = np.linspace(0, 1.0, n_colors)
    if isinstance(cmap, (list, tuple)):
        # we have a list of colors
        cmap = ListedColormap(cmap, N=n_colors)
        pal = cmap(colors_i)
    elif isinstance(cmap, str):
        # we have some sort of named palette
        try:
            # is this a matplotlib cmap?
            cmap = plt.get_cmap(cmap)
            pal = cmap(colors_i)
        except ValueError:
            # ValueError happens when mpl doesn't like a colormap, try seaborn
            try:
                from seaborn import color_palette

                pal = color_palette(cmap, n_colors=n_colors)
            except (ValueError, ImportError):
                # or maybe we just got a single color as a string
                cmap = ListedColormap([cmap], N=n_colors)
                pal = cmap(colors_i)
    else:
        # cmap better be a LinearSegmentedColormap (e.g. viridis)
        pal = cmap(colors_i)

    return pal

# _determine_cmap_params is adapted from Seaborn:
# https://github.com/mwaskom/seaborn/blob/v0.6/seaborn/matrix.py#L158
# Used under the terms of Seaborn's license, see licenses/SEABORN_LICENSE.

def _determine_cmap_params(
    plot_data,
    vmin=None,
    vmax=None,
    cmap=None,
    center=None,
    robust=False,
    extend=None,
    levels=None,
    filled=True,
    norm=None,
    _is_facetgrid=False,
):
    """
    Use some heuristics to set good defaults for colorbar and range.

    Parameters
    ----------
    plot_data : Numpy array
        Doesn't handle xarray objects

    Returns
    -------
    cmap_params : dict
        Use depends on the type of the plotting function
    """
    import matplotlib as mpl

    if isinstance(levels, Iterable):
        levels = sorted(levels)

    calc_data = np.ravel(plot_data[np.isfinite(plot_data)])

    # Handle all-NaN input data gracefully
    if calc_data.size == 0:
        # Arbitrary default for when all values are NaN
        calc_data = np.array(0.0)

    # Setting center=False prevents a divergent cmap
    possibly_divergent = center is not False

    # Set center to 0 so math below makes sense but remember its state
    center_is_none = False
    if center is None:
        center = 0
        center_is_none = True

    # Setting both vmin and vmax prevents a divergent cmap
    if (vmin is not None) and (vmax is not None):
        possibly_divergent = False

    # Setting vmin or vmax implies linspaced levels
    user_minmax = (vmin is not None) or (vmax is not None)

    # vlim might be computed below
    vlim = None

    # save state; needed later
    vmin_was_none = vmin is None
    vmax_was_none = vmax is None

    if vmin is None:
        if robust:
            vmin = np.percentile(calc_data, ROBUST_PERCENTILE)
        else:
            vmin = calc_data.min()
    elif possibly_divergent:
        vlim = abs(vmin - center)

    if vmax is None:
        if robust:
            vmax = np.percentile(calc_data, 100 - ROBUST_PERCENTILE)
        else:
            vmax = calc_data.max()
    elif possibly_divergent:
        vlim = abs(vmax - center)

    if possibly_divergent:
        levels_are_divergent = (
            isinstance(levels, Iterable) and levels[0] * levels[-1] < 0
        )
        # kwargs not specific about divergent or not: infer defaults from data
        divergent = (
            ((vmin < 0) and (vmax > 0)) or not center_is_none or levels_are_divergent
        )
    else:
        divergent = False

    # A divergent map should be symmetric around the center value
    if divergent:
        if vlim is None:
            vlim = max(abs(vmin - center), abs(vmax - center))
        vmin, vmax = -vlim, vlim

    # Now add in the centering value and set the limits
    vmin += center
    vmax += center

    # now check norm and harmonize with vmin, vmax
    if norm is not None:
        if norm.vmin is None:
            norm.vmin = vmin
        else:
            if not vmin_was_none and vmin != norm.vmin:
                raise ValueError("Cannot supply vmin and a norm with a different vmin.")
            vmin = norm.vmin

        if norm.vmax is None:
            norm.vmax = vmax
        else:
            if not vmax_was_none and vmax != norm.vmax:
                raise ValueError("Cannot supply vmax and a norm with a different vmax.")
            vmax = norm.vmax

    # if BoundaryNorm, then set levels
    if isinstance(norm, mpl.colors.BoundaryNorm):
        levels = norm.boundaries

    # Choose default colormaps if not provided
    if cmap is None:
        # EDIT: replaced OPTIONS
        if divergent:
            cmap = "RdBu_r"
        else:
            cmap = "viridis"

    # Handle discrete levels
    if levels is not None:
        # EDIT: replaced is_scalar(levels) by np.issubdtype(type(levels), np.integer)
        # xarray uses a relatelively complicated is_scalar function here. For
        # the purposes of plotting, checking for an integer should do.
        if np.issubdtype(type(levels), np.integer):
            if user_minmax:
                levels = np.linspace(vmin, vmax, levels)
            elif levels == 1:
                levels = np.asarray([(vmin + vmax) / 2])
            else:
                # N in MaxNLocator refers to bins, not ticks
                ticker = mpl.ticker.MaxNLocator(levels - 1)
                levels = ticker.tick_values(vmin, vmax)
        vmin, vmax = levels[0], levels[-1]

    # GH3734
    if vmin == vmax:
        vmin, vmax = mpl.ticker.LinearLocator(2).tick_values(vmin, vmax)

    if extend is None:
        extend = _determine_extend(calc_data, vmin, vmax)

    if (levels is not None) and (not isinstance(norm, mpl.colors.BoundaryNorm)):
        cmap, newnorm = _build_discrete_cmap(cmap, levels, extend, filled)
        norm = newnorm if norm is None else norm

    # vmin & vmax needs to be None if norm is passed
    # TODO: always return a norm with vmin and vmax
    if norm is not None:
        vmin = None
        vmax = None

    return dict(
        vmin=vmin, vmax=vmax, cmap=cmap, extend=extend, levels=levels, norm=norm
    )

def get_axis(
    figsize: Iterable[float] | None = None,
    size: float | None = None,
    aspect: AspectOptions = None,
    ax: Axes | None = None,
    **subplot_kws: Any,
) -> Axes:
    try:
        import matplotlib as mpl
        import matplotlib.pyplot as plt
    except ImportError:
        raise ImportError("matplotlib is required for plot.utils.get_axis")

    if figsize is not None:
        if ax is not None:
            raise ValueError("cannot provide both `figsize` and `ax` arguments")
        if size is not None:
            raise ValueError("cannot provide both `figsize` and `size` arguments")
        _, ax = plt.subplots(figsize=figsize, subplot_kw=subplot_kws)
        return ax

    if size is not None:
        if ax is not None:
            raise ValueError("cannot provide both `size` and `ax` arguments")
        if aspect is None or aspect == "auto":
            width, height = mpl.rcParams["figure.figsize"]
            faspect = width / height
        elif aspect == "equal":
            faspect = 1
        else:
            faspect = aspect
        figsize = (size * faspect, size)
        _, ax = plt.subplots(figsize=figsize, subplot_kw=subplot_kws)
        return ax

    if aspect is not None:
        raise ValueError("cannot provide `aspect` argument without `size`")

    if subplot_kws and ax is not None:
        raise ValueError("cannot use subplot_kws with existing ax")

    if ax is None:
        ax = _maybe_gca(**subplot_kws)

    return ax

def _maybe_gca(**subplot_kws: Any) -> Axes:
    import matplotlib.pyplot as plt

    # can call gcf unconditionally: either it exists or would be created by plt.axes
    f = plt.gcf()

    # only call gca if an active axes exists
    if f.axes:
        # can not pass kwargs to active axes
        return plt.gca()

    return plt.axes(**subplot_kws)

def _get_units_from_attrs(da: DataArray) -> str:
    """Extracts and formats the unit/units from a attributes."""
    # EDIT: removed pint support for now.
    # pint_array_type = DuckArrayModule("pint").type
    units = " [{}]"
    # if isinstance(da.data, pint_array_type):
    #    return units.format(str(da.data.units))
    if "units" in da.attrs:
        return units.format(da.attrs["units"])
    if "unit" in da.attrs:
        return units.format(da.attrs["unit"])
    return ""

def label_from_attrs(da: DataArray | None, extra: str = "") -> str:
    """Makes informative labels if variable metadata (attrs) follows
    CF conventions."""
    if da is None:
        return ""

    name: str = "{}"
    if "long_name" in da.attrs:
        name = name.format(da.attrs["long_name"])
    elif "standard_name" in da.attrs:
        name = name.format(da.attrs["standard_name"])
    elif da.name is not None:
        name = name.format(da.name)
    else:
        name = ""

    units = _get_units_from_attrs(da)

    # Treat `name` differently if it's a latex sequence
    if name.startswith("$") and (name.count("$") % 2 == 0):
        return "$\n$".join(
            textwrap.wrap(name + extra + units, 60, break_long_words=False)
        )
    else:
        return "\n".join(textwrap.wrap(name + extra + units, 30))

def _valid_other_type(
    x: ArrayLike, types: type[object] | tuple[type[object], ...]
) -> bool:
    """
    Do all elements of x have a type from types?
    """
    return all(isinstance(el, types) for el in np.ravel(x))

def _valid_numpy_subdtype(x, numpy_types):
    """
    Is any dtype from numpy_types superior to the dtype of x?
    """
    # If any of the types given in numpy_types is understood as numpy.generic,
    # all possible x will be considered valid.  This is probably unwanted.
    for t in numpy_types:
        assert not np.issubdtype(np.generic, t)

    return any(np.issubdtype(x.dtype, t) for t in numpy_types)

def _ensure_plottable(*args) -> None:
    """
    Raise exception if there is anything in args that can't be plotted on an
    axis by matplotlib.
    """
    numpy_types: tuple[type[object], ...] = (
        np.floating,
        np.integer,
        np.timedelta64,
        np.datetime64,
        np.bool_,
        np.str_,
    )
    other_types: tuple[type[object], ...] = (datetime,)
    cftime_datetime_types: tuple[type[object], ...] = (
        () if cftime is None else (cftime.datetime,)
    )
    other_types += cftime_datetime_types

    for x in args:
        if not (
            _valid_numpy_subdtype(np.asarray(x), numpy_types)
            or _valid_other_type(np.asarray(x), other_types)
        ):
            raise TypeError(
                "Plotting requires coordinates to be numeric, boolean, "
                "or dates of type numpy.datetime64, "
                "datetime.datetime, cftime.datetime or "
                f"pandas.Interval. Received data of type {np.asarray(x).dtype} instead."
            )
        if _valid_other_type(np.asarray(x), cftime_datetime_types):
            if nc_time_axis_available:
                # Register cftime datetypes to matplotlib.units.registry,
                # otherwise matplotlib will raise an error:
                import nc_time_axis  # noqa: F401
            else:
                raise ImportError(
                    "Plotting of arrays of cftime.datetime "
                    "objects or arrays indexed by "
                    "cftime.datetime objects requires the "
                    "optional `nc-time-axis` (v1.2.0 or later) "
                    "package."
                )

def _add_colorbar(primitive, ax, cbar_ax, cbar_kwargs, cmap_params):
    cbar_kwargs.setdefault("extend", cmap_params["extend"])
    if cbar_ax is None:
        cbar_kwargs.setdefault("ax", ax)
    else:
        cbar_kwargs.setdefault("cax", cbar_ax)

    # dont pass extend as kwarg if it is in the mappable
    if hasattr(primitive, "extend"):
        cbar_kwargs.pop("extend")

    fig = ax.get_figure()
    cbar = fig.colorbar(primitive, **cbar_kwargs)

    return cbar

def _update_axes(
    ax: Axes,
    xincrease: bool | None,
    yincrease: bool | None,
    xscale: ScaleOptions = None,
    yscale: ScaleOptions = None,
    xticks: ArrayLike | None = None,
    yticks: ArrayLike | None = None,
    xlim: tuple[float, float] | None = None,
    ylim: tuple[float, float] | None = None,
) -> None:
    """
    Update axes with provided parameters
    """
    if xincrease is None:
        pass
    elif xincrease and ax.xaxis_inverted():
        ax.invert_xaxis()
    elif not xincrease and not ax.xaxis_inverted():
        ax.invert_xaxis()

    if yincrease is None:
        pass
    elif yincrease and ax.yaxis_inverted():
        ax.invert_yaxis()
    elif not yincrease and not ax.yaxis_inverted():
        ax.invert_yaxis()

    # The default xscale, yscale needs to be None.
    # If we set a scale it resets the axes formatters,
    # This means that set_xscale('linear') on a datetime axis
    # will remove the date labels. So only set the scale when explicitly
    # asked to. https://github.com/matplotlib/matplotlib/issues/8740
    if xscale is not None:
        ax.set_xscale(xscale)
    if yscale is not None:
        ax.set_yscale(yscale)

    if xticks is not None:
        ax.set_xticks(xticks)
    if yticks is not None:
        ax.set_yticks(yticks)

    if xlim is not None:
        ax.set_xlim(xlim)
    if ylim is not None:
        ax.set_ylim(ylim)

def _process_cmap_cbar_kwargs(
    func,
    data,
    cmap=None,
    colors=None,
    cbar_kwargs: Iterable[tuple[str, Any]] | Mapping[str, Any] | None = None,
    levels=None,
    _is_facetgrid=False,
    **kwargs,
) -> tuple[dict[str, Any], dict[str, Any]]:
    """
    Parameters
    ----------
    func : plotting function
    data : ndarray,
        Data values

    Returns
    -------
    cmap_params : dict
    cbar_kwargs : dict
    """
    if func.__name__ == "surface":
        # Leave user to specify cmap settings for surface plots
        kwargs["cmap"] = cmap
        return {
            k: kwargs.get(k, None)
            for k in ["vmin", "vmax", "cmap", "extend", "levels", "norm"]
        }, {}

    cbar_kwargs = {} if cbar_kwargs is None else dict(cbar_kwargs)

    if "contour" in func.__name__ and levels is None:
        levels = 7  # this is the matplotlib default

    # colors is mutually exclusive with cmap
    if cmap and colors:
        raise ValueError("Can't specify both cmap and colors.")

    # colors is only valid when levels is supplied or the plot is of type
    # contour or contourf
    if colors and (("contour" not in func.__name__) and (levels is None)):
        raise ValueError("Can only specify colors with contour or levels")

    # we should not be getting a list of colors in cmap anymore
    # is there a better way to do this test?
    if isinstance(cmap, (list, tuple)):
        raise ValueError(
            "Specifying a list of colors in cmap is deprecated. "
            "Use colors keyword instead."
        )

    cmap_kwargs = {
        "plot_data": data,
        "levels": levels,
        "cmap": colors if colors else cmap,
        "filled": func.__name__ != "contour",
    }

    cmap_args = getfullargspec(_determine_cmap_params).args
    cmap_kwargs.update((a, kwargs[a]) for a in cmap_args if a in kwargs)
    if not _is_facetgrid:
        cmap_params = _determine_cmap_params(**cmap_kwargs)
    else:
        cmap_params = {
            k: cmap_kwargs[k]
            for k in ["vmin", "vmax", "cmap", "extend", "levels", "norm"]
        }

    return cmap_params, cbar_kwargs

def _easy_facetgrid(
    data: T_DataArrayOrSet,
    plotfunc: Callable,
    kind: Literal["line", "dataarray", "dataset", "plot1d"],
    x: Hashable | None = None,
    y: Hashable | None = None,
    row: Hashable | None = None,
    col: Hashable | None = None,
    col_wrap: int | None = None,
    sharex: bool = True,
    sharey: bool = True,
    aspect: float | None = None,
    size: float | None = None,
    subplot_kws: dict[str, Any] | None = None,
    ax: Axes | None = None,
    figsize: Iterable[float] | None = None,
    **kwargs: Any,
) -> FacetGrid[T_DataArrayOrSet]:
    """
    Convenience method to call xarray.plot.FacetGrid from 2d plotting methods

    kwargs are the arguments to 2d plotting method
    """
    if ax is not None:
        raise ValueError("Can't use axes when making faceted plots.")
    if aspect is None:
        aspect = 1
    if size is None:
        size = 3
    elif figsize is not None:
        raise ValueError("cannot provide both `figsize` and `size` arguments")
    if kwargs.get("z") is not None:
        # 3d plots doesn't support sharex, sharey, reset to mpl defaults:
        sharex = False
        sharey = False

    g = FacetGrid(
        data=data,
        col=col,
        row=row,
        col_wrap=col_wrap,
        sharex=sharex,
        sharey=sharey,
        figsize=figsize,
        aspect=aspect,
        size=size,
        subplot_kws=subplot_kws,
    )

    if kind == "line":
        return g.map_dataarray_line(plotfunc, x, y, **kwargs)

    if kind == "dataarray":
        return g.map_dataarray(plotfunc, x, y, **kwargs)

    if kind == "plot1d":
        return g.map_plot1d(plotfunc, x, y, **kwargs)

    if kind == "dataset":
        return g.map_dataset(plotfunc, x, y, **kwargs)

    raise ValueError(
        f"kind must be one of `line`, `dataarray`, `dataset` or `plot1d`, got {kind}"
    )


import logging
import random
import torch
import os
import time

import numpy as np
import pprint as pprint
from sklearn.metrics import confusion_matrix
import matplotlib.pyplot as plt
import matplotlib
import numpy as np
from sklearn import datasets
from sklearn.manifold import TSNE
import pandas

_utils_pp = pprint.PrettyPrinter()

def pprint(x):
    _utils_pp.pprint(x)

def set_seed(seed):
    if seed == 0:
        print(' random seed')
        torch.backends.cudnn.benchmark = True
    else:
        print('manual seed:', seed)
        random.seed(seed)
        np.random.seed(seed)
        torch.manual_seed(seed)
        torch.cuda.manual_seed_all(seed)
        torch.backends.cudnn.deterministic = True
        torch.backends.cudnn.benchmark = False

def set_gpu(args):
    gpu_list = [int(x) for x in args.gpu.split(',')]
    print('use gpu:', gpu_list)
    os.environ['CUDA_DEVICE_ORDER'] = 'PCI_BUS_ID'
    os.environ['CUDA_VISIBLE_DEVICES'] = args.gpu
    return gpu_list.__len__()

def ensure_path(path):
    if os.path.exists(path):
        pass
    else:
        print('create folder:', path)
        os.makedirs(path)

class Averager():

    def __init__(self):
        self.n = 0
        self.v = 0

    def add(self, x):
        self.v = (self.v * self.n + x) / (self.n + 1)
        self.n += 1

    def item(self):
        return round(self.v, 5)

class AverageMeter(object):
    """Computes and stores the average and current value"""

    def __init__(self):
        self.reset()

    def reset(self):
        self.val = 0
        self.avg = 0.0
        self.sum = 0.0
        self.count = 0

    def update(self, val, n=1):
        self.val = val
        self.sum += float(val * n)
        self.count += n
        self.avg = round(self.sum / self.count, 5)

    def average(self):
        return self.avg

class LAverageMeter(object):
    """Computes and stores the average and current value"""

    def __init__(self):
        self.reset()

    def reset(self):
        self.val = []
        self.avg = []
        self.sum = []
        self.count = 0

    def update(self, val):
        self.val = val
        self.count += 1
        if len(self.sum) == 0:
            assert (self.count == 1)
            self.sum = [v for v in val]
            self.avg = [round(v, 4) for v in val]
        else:
            assert (len(self.sum) == len(val))
            for i, v in enumerate(val):
                self.sum[i] += v
                self.avg[i] = round(self.sum[i] / self.count, 4)

class DAverageMeter(object):
    def __init__(self):
        self.reset()

    def reset(self):
        self.values = {}

    def update(self, values):
        assert (isinstance(values, dict))
        for key, val in values.items():
            if isinstance(val, (float, int)):
                if not (key in self.values):
                    self.values[key] = AverageMeter()
                self.values[key].update(val)
            elif isinstance(val, np.ndarray):
                val = float(val)
                if not (key in self.values):
                    self.values[key] = AverageMeter()
                self.values[key].update(val)
            elif isinstance(val, dict):
                if not (key in self.values):
                    self.values[key] = DAverageMeter()
                self.values[key].update(val)
            elif isinstance(val, list):
                if not (key in self.values):
                    self.values[key] = LAverageMeter()
                self.values[key].update(val)

    def average(self):
        average = {}
        for key, val in self.values.items():
            if isinstance(val, type(self)):
                average[key] = val.average()
            else:
                average[key] = val.avg
        return average

def acc_utils(da, num_base, num_session, way, session):
    acc_dict = {}
    acc_dict['all_acc'] = 0.0
    acc_dict['base_acc'] = 0.0
    acc_dict['novel_acc'] = 0.0
    acc_dict['former_acc'] = 0.0
    acc_dict['cur_acc'] = 0.0
    for i in range(num_session):
        acc_dict['sess{}_acc'.format(i)] = None
    if session == 0:
        avger = Averager()
        for i in range(num_base):
            if i in da:
                avger.add(da[i])
        acc_dict['all_acc'] = avger.item()
        acc_dict['former_acc'] = None
        acc_dict['cur_acc'] = None
        acc_dict['base_acc'] = avger.item()
        acc_dict['novel_acc'] = None
        acc_dict['sess0_acc'] = avger.item()
    else:
        for i in range(session + 1):
            if i == 0:
                sess_cls = range(num_base)
                acc_dict['sess{}_acc'.format(i)] =  get_aver(sess_cls, da)
            else:
                sess_cls = range(num_base + way * (i - 1), num_base + way * i)
                acc_dict['sess{}_acc'.format(i)] =  get_aver(sess_cls, da)

        all_cls = range(num_base + way * session)
        former_cls = range(num_base + way * (session - 1))
        cur_cls = range(num_base + way * (session - 1), num_base + way * session)
        base_cls = range(num_base)
        novel_cls = range(num_base, num_base + way * session)

        acc_dict['all_acc'] = get_aver(all_cls, da)
        acc_dict['former_acc'] = get_aver(former_cls, da)
        acc_dict['cur_acc'] = get_aver(cur_cls, da)
        acc_dict['base_acc'] = get_aver(base_cls, da)
        acc_dict['novel_acc'] = get_aver(novel_cls, da)
    return acc_dict

def cal_auxIndex(final_out_dict, alpha=0.5):
    aux_index = {}
    acc_aver = {}
    acc_aver['acc_base_aver'] = 0.0
    acc_aver['acc_novel_aver'] = 0.0
    acc_aver['acc_both_aver'] = 0.0
    acc_aver['acc_cur_aver'] = 0.0
    ar_over = ((final_out_dict['base_Acc'][0] - final_out_dict['base_Acc'][-1]) / final_out_dict['base_Acc'][0])
    msr_over = 1 - ar_over
    acc_aver['acc_base_aver'] = sum(final_out_dict['base_Acc']) / len(final_out_dict['base_Acc'])
    acc_aver['acc_both_aver'] = sum(final_out_dict['Both_ACC']) / len(final_out_dict['Both_ACC'])
    if len(final_out_dict['novel_Acc']) - 1 > 0:
        acc_aver['acc_novel_aver'] = sum(final_out_dict['novel_Acc'][1:]) / (len(final_out_dict['novel_Acc']) - 1)
        acc_aver['acc_cur_aver'] = sum(final_out_dict['cur_acc'][1:]) / (len(final_out_dict['cur_acc']) - 1)
    else:
        acc_aver['acc_novel_aver'] = None
        acc_aver['acc_cur_aver'] = None
    cpi = alpha * msr_over + (1 - alpha) * acc_aver['acc_novel_aver']
    acc_df = pandas.Series(acc_aver)
    return cpi, msr_over, acc_df, ar_over

def get_aver(cls, da):
    avger = Averager()
    for i in cls:
        if i in da:
            avger.add(da[i])
    return avger.item()

def plot_tsne(fc_proto, test_class, save_path, session):
    ts = TSNE(n_components=2, init='pca', random_state=0)
    reslut = ts.fit_transform(fc_proto.cpu().numpy())
    # 调用函数，绘制图像
    fig = plot_embedding(reslut, np.arange(test_class), 't-SNE proto of session {}'.format(session))
    # 显示图像
    plt.savefig(save_path)

class Timer():

    def __init__(self):
        self.o = time.time()

    def measure(self, p=1):
        x = (time.time() - self.o) / p
        x = int(x)
        if x >= 3600:
            return '{:.1f}h'.format(x / 3600)
        if x >= 60:
            return '{}m'.format(round(x / 60))
        return '{}s'.format(x)

def count_acc(logits, label):
    pred = torch.argmax(logits, dim=1)
    if torch.cuda.is_available():
        return (pred == label).type(torch.cuda.FloatTensor).mean().item()
    else:
        return (pred == label).type(torch.FloatTensor).mean().item()

def count_per_cls_acc(logits, true_label):
    pred = torch.argmax(logits, dim=1)
    acc_dict = {}
    cls_sample_count = {}
    for cls in true_label.unique():
        indices = torch.where(true_label==cls, 1, 0)
        idx = torch.nonzero(indices)
        if torch.cuda.is_available():
            per_acc = (pred == true_label)[idx].type(torch.cuda.FloatTensor).mean().item()
        else:
            per_acc = (pred == true_label)[idx].type(torch.FloatTensor).mean().item()
        acc_dict[cls.cpu().data.item()] = per_acc
        cls_sample_count[f"number:{cls.cpu().data.item()}"] = len(idx)
        # cls_sample_count[f"percent:{cls.cpu().data.item()}"] = len(idx) / len(indices)
    return acc_dict, cls_sample_count

def count_acc_topk(x,y,k=5):
    _,maxk = torch.topk(x,k,dim=-1)
    total = y.size(0)
    test_labels = y.view(-1,1)
    #top1=(test_labels == maxk[:,0:1]).sum().item()
    topk=(test_labels == maxk).sum().item()
    return float(topk/total)

def count_acc_taskIL(logits, label,args):
    basenum=args.base_class
    incrementnum=(args.num_classes-args.base_class)/args.way
    for i in range(len(label)):
        currentlabel=label[i]
        if currentlabel<basenum:
            logits[i,basenum:]=-1e9
        else:
            space=int((currentlabel-basenum)/args.way)
            low=basenum+space*args.way
            high=low+args.way
            logits[i,:low]=-1e9
            logits[i,high:]=-1e9

    pred = torch.argmax(logits, dim=1)
    if torch.cuda.is_available():
        return (pred == label).type(torch.cuda.FloatTensor).mean().item()
    else:
        return (pred == label).type(torch.FloatTensor).mean().item()

def confmatrix(logits,label,filename):

    font={'family':'FreeSerif','size':18}
    matplotlib.rc('font',**font)
    matplotlib.rcParams.update({'font.family':'FreeSerif','font.size':18})
    plt.rcParams["font.family"]="FreeSerif"

    pred = torch.argmax(logits, dim=1)
    cm=confusion_matrix(label, pred,normalize='true')
    #print(cm)
    clss=len(cm)
    fig = plt.figure()
    ax = fig.add_subplot(111)
    cax = ax.imshow(cm,cmap=plt.cm.jet)
    if clss<=100:
        plt.yticks([0,19,39,59,79,99],[0,20,40,60,80,100],fontsize=16)
        plt.xticks([0,19,39,59,79,99],[0,20,40,60,80,100],fontsize=16)
    elif clss<=200:
        plt.yticks([0,39,79,119,159,199],[0,40,80,120,160,200],fontsize=16)
        plt.xticks([0,39,79,119,159,199],[0,40,80,120,160,200],fontsize=16)
    else:
        plt.yticks([0,199,399,599,799,999],[0,200,400,600,800,1000],fontsize=16)
        plt.xticks([0,199,399,599,799,999],[0,200,400,600,800,1000],fontsize=16)

    plt.xlabel('Predicted Label',fontsize=20)
    plt.ylabel('True Label',fontsize=20)
    plt.tight_layout()
    plt.savefig(filename+'.pdf',bbox_inches='tight')
    plt.close()

    fig = plt.figure()
    ax = fig.add_subplot(111)
    cax = ax.imshow(cm,cmap=plt.cm.jet)
    cbar = plt.colorbar(cax) # This line includes the color bar
    cbar.ax.tick_params(labelsize=16)
    if clss<=100:
        plt.yticks([0,19,39,59,79,99],[0,20,40,60,80,100],fontsize=16)
        plt.xticks([0,19,39,59,79,99],[0,20,40,60,80,100],fontsize=16)
    elif clss<=200:
        plt.yticks([0,39,79,119,159,199],[0,40,80,120,160,200],fontsize=16)
        plt.xticks([0,39,79,119,159,199],[0,40,80,120,160,200],fontsize=16)
    else:
        plt.yticks([0,199,399,599,799,999],[0,200,400,600,800,1000],fontsize=16)
        plt.xticks([0,199,399,599,799,999],[0,200,400,600,800,1000],fontsize=16)
    plt.xlabel('Predicted Label',fontsize=20)
    plt.ylabel('True Label',fontsize=20)
    plt.tight_layout()
    plt.savefig(filename+'_cbar.pdf',bbox_inches='tight')
    plt.close()

    return cm

def save_list_to_txt(name, input_list):
    f = open(name, mode='w')
    for item in input_list:
        f.write(str(item) + '\n')
    f.close()

# 对样本进行预处理并画图
def plot_embedding(data, label, title):
    """
    :param data:数据集
    :param label:样本标签
    :param title:图像标题
    :return:图像
    """
    x_min, x_max = np.min(data, 0), np.max(data, 0)
    data = (data - x_min) / (x_max - x_min)     # 对数据进行归一化处理
    fig = plt.figure()      # 创建图形实例
    ax = plt.subplot(111)       # 创建子图
    # 遍历所有样本
    for i in range(data.shape[0]):
        # 在图中为每个数据点画出标签
        plt.text(data[i, 0], data[i, 1], str(label[i]), color=plt.cm.Set2(label[i] / len(label)),
                 fontdict={'weight': 'bold', 'size': 7})
    plt.xticks()        # 指定坐标的刻度
    plt.yticks()
    plt.title(title, fontsize=14)
    # 返回值
    return fig

def get_base_novel_ids(meta_labels, num_base, episode_way, session=0):
    batch_size = meta_labels.size(0)
    all_base_labels = np.arange(num_base+ session * episode_way)
    novel_ids = np.unique(meta_labels.cpu().numpy())
    base_ids = np.delete(all_base_labels, novel_ids)
    base_ids = torch.from_numpy(base_ids)
    novel_ids = torch.from_numpy(novel_ids)
    base_ids = base_ids.type(torch.cuda.LongTensor)
    novel_ids = novel_ids.type(torch.cuda.LongTensor)
    return base_ids, novel_ids

class Logger:
    def __init__(self, savedir):
        self.log = logging.getLogger(savedir)
        self.log.setLevel(logging.DEBUG)
        self.formatter = logging.Formatter("%(asctime)s-%(name)s-%(levelname)s: %(message)s")

        self.fhander = logging.FileHandler(os.path.join(savedir, 'logs.log'), mode='w')
        self.fhander.setLevel(logging.DEBUG)
        self.fhander.setFormatter(self.formatter)
        self.log.addHandler(self.fhander)

        self.shander = logging.StreamHandler()
        self.shander.setLevel(logging.DEBUG)
        self.shander.setFormatter(self.formatter)
        self.log.addHandler(self.shander)

    def write_log(self, *args, **kwargs):
        self.log.info(args)
        # self.log.info(kwargs)

def get_torch_size(model, input_size):
    import torchinfo
    model_profile= torchinfo.summary(model, input_size=input_size)
    return model_profile.total_mult_adds, model_profile.total_params


from django.test import TestCase
from django.contrib.gis.db import models
from django.contrib.gis.geos import Point
from django.apps import apps
from itertools import chain
from streamwebs.models import CameraPoint, Site
import datetime

class CameraPointTestCase(TestCase):

    def setUp(self):
        self.expected_fields = {
            'school': models.ForeignKey,
            'school_id': models.ForeignKey,
            'site': models.ForeignKey,
            'site_id': models.ForeignKey,
            'letter': models.CharField,
            'cp_date': models.DateField,
            'location': models.PointField,
            'map_datum': models.CharField,
            'description': models.TextField,
            'created': models.DateTimeField,
            'id': models.AutoField,

            'camera_point': models.ManyToOneRel
        }

        self.optional_fields = {
            'map_datum': models.CharField,
            'description': models.TextField
        }

        self.site = Site.test_objects.create_site('test site a')

    def test_fields_exist(self):
        model = apps.get_model('streamwebs', 'camerapoint')
        for field, field_type in self.expected_fields.items():
            self.assertEqual(
                field_type, type(model._meta.get_field(field)))

    def test_no_extra_fields(self):
        cp_fields = list(set(chain.from_iterable(
            (field.name, field.attname) if hasattr(field, 'attname') else
            (field.name,) for field in CameraPoint._meta.get_fields()
            if not (field.many_to_one and field.related_model is None)
            )))
        self.assertEqual(sorted(cp_fields),
                         sorted(self.expected_fields.keys()))

    def test_optional_fields(self):
        for field in self.optional_fields:
            self.assertEqual(
                CameraPoint._meta.get_field(field).blank, True)

    def test_CameraPoint_ManyToOneSite(self):
        """
        A camera point should correspond to a single specified site.
        """
        cp_date = datetime.date.today()

        camera_point = CameraPoint.test_objects.create_camera_point(
            self.site, cp_date, 'POINT(-121.393401 44.061437)'
        )

        self.assertEqual(camera_point.site.site_name, 'test site a')

    def test_obj_exists_req_fields(self):
        """
        Tests that the CameraPoint object can be created successfully when the
        required fields are provided.
        """
        camera_point = CameraPoint.test_objects.create_camera_point(
            self.site, '2016-07-07', 'POINT(-121.393401 44.061437)'
        )

        # Required fields
        self.assertEqual(camera_point.site.site_name, 'test site a')
        self.assertEqual(camera_point.cp_date, '2016-07-07')

        # Optional fields
        self.assertEqual(camera_point.location.coords,
                         (-121.393401, 44.061437))
        self.assertEqual(camera_point.map_datum, '')
        self.assertEqual(camera_point.description, '')

    def test_obj_exists_opt_fields(self):
        """
        Tests that the CameraPoint object can be created successfully when the
        required and optional fields are provided.
        """
        camera_point = CameraPoint.test_objects.create_camera_point(
            self.site, '2016-07-08', Point(-120.2684184, 44.3910532), 'WGS84',
            'Notes on this camera point for test site a'
        )

        # Required fields
        self.assertEqual(camera_point.site.site_name, 'test site a')
        self.assertEqual(camera_point.cp_date, '2016-07-08')

        # Optional fields
        self.assertEqual(camera_point.location.coords,
                         (-120.2684184, 44.3910532))
        self.assertEqual(camera_point.map_datum, 'WGS84')
        self.assertEqual(camera_point.description,
                         'Notes on this camera point for test site a')

    def test_letter_assign_for_first_cp(self):
        camera_point = CameraPoint.test_objects.create_camera_point(
            self.site, '2016-07-08', Point(-120.2684184, 44.3910532),
        )
        self.assertEqual(camera_point.letter, 'A')

    def test_letter_assign_for_regular_cp(self):
        camera_point = CameraPoint.test_objects.create_camera_point(
            self.site, '2016-07-08', Point(-120.2684184, 44.3910532),
        )
        self.assertEqual(camera_point.letter, 'A')

        camera_point_2 = CameraPoint.test_objects.create_camera_point(
            self.site, '2016-07-08', Point(-120.2684184, 44.3910532),
        )
        self.assertEqual(camera_point_2.letter, 'B')

    def test_letter_assign_for_end_of_alphabet(self):
        camera_point = CameraPoint.test_objects.create_camera_point(
            self.site, '2016-07-08', Point(-120.2684184, 44.3910532),
        )
        camera_point.letter = 'ZZ'
        camera_point.save()

        self.assertEqual(camera_point.letter, 'ZZ')

        camera_point_2 = CameraPoint.test_objects.create_camera_point(
            self.site, '2016-07-08', Point(-120.2684184, 44.3910532)
        )
        self.assertEqual(camera_point_2.letter, 'AAA')

    def test_restart_lettering_for_new_site(self):
        camera_point = CameraPoint.test_objects.create_camera_point(
            self.site, '2016-07-08', Point(-120.2684184, 44.3910532),
        )
        self.assertEqual(camera_point.letter, 'A')

        site_2 = Site.test_objects.create_site('Second site')
        camera_point_2 = CameraPoint.test_objects.create_camera_point(
            site_2, '2016-07-08', Point(-120.2684184, 44.3910532),
        )
        self.assertEqual(camera_point_2.letter, 'A')


# -*- coding: utf-8 -*-
# Time : 2023/8/28 17:10
# Author : chen
# Software: PyCharm
import matplotlib.pyplot as plt
import numpy as np
from sklearn.svm import SVC
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import PolynomialFeatures
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix
from sklearn.metrics import classification_report
# File : 练习2.py
def main():
    # 1.完成数据集的加载apple.txt
    datas = np.loadtxt('apple.txt',delimiter=',')
    # 2.获取特征和标签
    x = datas[:,:2]
    y = datas[:,-1:]
    # 3.进行特征缩放
    x = StandardScaler().fit_transform(x)
    # 4.对其添加常数项
    x = PolynomialFeatures().fit_transform(x)
    # 5.将数据集洗牌
    m = len(x)
    np.random.seed(0)
    np_perm = np.random.permutation(m)
    x = x[np_perm]
    y = y[np_perm]
    # 6.合理分割成训练集和测试集
    train_x,test_x,train_y,test_y = train_test_split(x,y)
    # 7.正确调用SVM库函数（惩罚系数0.6，使用高斯核函数）
    s = SVC(
        C=0.6,
        kernel='rbf'
    )
    # 8.训练模型
    s.fit(train_x,train_y)
    # 9.进行模型预测
    test_p = s.predict(test_x)
    print(test_p)
    # 10.求出训练集准确率
    print(s.score(train_x,train_y))
    # 11.求出测试集的准确率
    print(s.score(test_x,test_y))
    # 12.输出混淆矩阵
    print(confusion_matrix(test_y,s.predict(test_x)))
    # 13.输出分类报告
    print(classification_report(test_y,s.predict(test_x)))
    # 14.输出支持向量的索引
    print(s.support_)
    # 15.输出支持向量的列表
    print(s.support_vectors_)
    # 16.输出支持向量所属每个类别的个数
    print(s.n_support_)
    # 17.绘制整个样本散点图
    plt.scatter(test_x[:,1],test_x[:,2],c='r',marker='+')
    plt.show()
if __name__ == '__main__':
    main()


from PyQt5 import QtCore,QtWidgets

class Ui_Sure(QtWidgets.QDialog):
    def setupUi(self, Sure):
        Sure.setObjectName("Sure")
        Sure.resize(200, 100)
        self.Sure = QtWidgets.QPushButton(Sure)
        self.Sure.setGeometry(QtCore.QRect(62.5, 37.5, 75, 25))
        self.Sure.setObjectName("Sure")
        self.Sure.raise_()

        self.retranslateUi(Sure)
        QtCore.QMetaObject.connectSlotsByName(Sure)

    def retranslateUi(self, Sure):
        _translate = QtCore.QCoreApplication.translate
        Sure.setWindowTitle(_translate("Sure", "Diagol"))
        self.Sure.setText(_translate("Sure", "确定"))

# if __name__=="__main__":
#     import sys
#     app=QtWidgets.QApplication(sys.argv)
#     dialog=QtWidgets.QDialog()
#     ui=Ui_Sure()
#     ui.setupUi(dialog)
#     dialog.show()
#     sys.exit(app.exec_())


# Definition for singly-linked list.
from typing import Optional

# 合并两个有序数组

class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

# 双指针， 代码较繁琐
class Solution:
    def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
        a = list1
        b = list2
        t = ListNode()
        if a is None and b is None:
            return
        elif a is not None and b is None:
            t = a
            c = t
        elif a is None and b is not None:
            t = b
            c = t
        else:
            while a is not None and b is not None:
                if a.val <= b.val and t.next is None:
                    t = a
                    a = a.next
                    c = t
                elif a.val > b.val and t.next is None:
                    t = b
                    b = b.next
                    c = t
                elif a.val <= b.val:
                    t.next = a
                    a = a.next
                    t = t.next
                else:
                    t.next = b
                    b = b.next
                    t = t.next
            if a is not None:
                t.next = a
            if b is not None:
                t.next = b
        return c

    def mergeTwoLists_LC(self, l1: ListNode, l2: ListNode) -> ListNode:
        prehead = ListNode(-1)  # 头指针

        prev = prehead
        while l1 and l2:
            if l1.val <= l2.val:
                prev.next = l1
                l1 = l1.next
            else:
                prev.next = l2
                l2 = l2.next
            prev = prev.next

        prev.next = l1 if l1 is not None else l2

        return prehead.next

l1 = ListNode(1)
# l2 = ListNode(2)
# l3 = ListNode(3)

# l1.next = l2
# l2.next = l3

m1 = ListNode(0)
# m2 = ListNode(2)
# m3 = ListNode(3)

# m1.next = m2
# m2.next = m3

s = Solution()
s.mergeTwoLists(l1, None)


from contextlib import contextmanager
from xml.etree import ElementTree as etree
from xml.sax.saxutils import quoteattr

import six

CNAME_TAGS = ('system-out', 'skipped', 'error', 'failure')
CNAME_PATTERN = '<![CDATA[{}]]>'
TAG_PATTERN = '<{tag}{attrs}>{text}</{tag}>'

@contextmanager
def patch_etree_cname(etree):
    """
    Patch ElementTree's _serialize_xml function so that it will
    write text as CDATA tag for tags tags defined in CNAME_TAGS.

    >>> import re
    >>> from xml.etree import ElementTree
    >>> xml_string = '''
    ... <testsuite name="nosetests" tests="1" errors="0" failures="0" skip="0">
    ...     <testcase classname="some.class.Foo" name="test_system_out" time="0.001">
    ...         <system-out>Some output here</system-out>
    ...     </testcase>
    ...     <testcase classname="some.class.Foo" name="test_skipped" time="0.001">
    ...         <skipped type="unittest.case.SkipTest" message="Skipped">Skipped</skipped>
    ...     </testcase>
    ...     <testcase classname="some.class.Foo" name="test_error" time="0.001">
    ...         <error type="KeyError" message="Error here">Error here</error>
    ...     </testcase>
    ...     <testcase classname="some.class.Foo" name="test_failure" time="0.001">
    ...         <failure type="AssertionError" message="Failure here">Failure here</failure>
    ...     </testcase>
    ... </testsuite>
    ... '''
    >>> tree = ElementTree.fromstring(xml_string)
    >>> with patch_etree_cname(ElementTree):
    ...    saved = str(ElementTree.tostring(tree))
    >>> systemout = re.findall(r'(<system-out>.*?</system-out>)', saved)[0]
    >>> print(systemout)
    <system-out><![CDATA[Some output here]]></system-out>
    >>> skipped = re.findall(r'(<skipped.*?</skipped>)', saved)[0]
    >>> print(skipped)
    <skipped message="Skipped" type="unittest.case.SkipTest"><![CDATA[Skipped]]></skipped>
    >>> error = re.findall(r'(<error.*?</error>)', saved)[0]
    >>> print(error)
    <error message="Error here" type="KeyError"><![CDATA[Error here]]></error>
    >>> failure = re.findall(r'(<failure.*?</failure>)', saved)[0]
    >>> print(failure)
    <failure message="Failure here" type="AssertionError"><![CDATA[Failure here]]></failure>
    """
    original_serialize = etree._serialize_xml

    def _serialize_xml(write, elem, *args, **kwargs):
        if elem.tag in CNAME_TAGS:
            attrs = ' '.join(
                ['{}={}'.format(k, quoteattr(v))
                 for k, v in sorted(elem.attrib.items())]
            )
            attrs = ' ' + attrs if attrs else ''
            text = CNAME_PATTERN.format(elem.text)
            write(TAG_PATTERN.format(
                tag=elem.tag,
                attrs=attrs,
                text=text
            ))
        else:
            original_serialize(write, elem, *args, **kwargs)

    etree._serialize_xml = etree._serialize['xml'] = _serialize_xml

    yield

    etree._serialize_xml = etree._serialize['xml'] = original_serialize

def merge_trees(*trees):
    """
    Merge all given XUnit ElementTrees into a single ElementTree.
    This combines all of the children test-cases and also merges
    all of the metadata of how many tests were executed, etc.
    """
    first_tree = trees[0]
    first_root = first_tree.getroot()

    if len(trees) == 0:
        return first_tree

    for tree in trees[1:]:
        root = tree.getroot()

        # append children elements (testcases)
        first_root.extend(root.getchildren())

        # combine root attributes which stores the number
        # of executed tests, skipped tests, etc
        for key, value in first_root.attrib.items():
            if not value.isdigit():
                continue
            combined = six.text_type(int(value) + int(root.attrib.get(key, '0')))
            first_root.set(key, combined)

    return first_tree

def merge_xunit(files, output, callback=None):
    """
    Merge the given xunit xml files into a single output xml file.

    If callback is not None, it will be called with the merged ElementTree
    before the output file is written (useful for applying other fixes to
    the merged file). This can either modify the element tree in place (and
    return None) or return a completely new ElementTree to be written.
    """
    trees = []

    for f in files:
        trees.append(etree.parse(f))

    merged = merge_trees(*trees)

    if callback is not None:
        result = callback(merged)
        if result is not None:
            merged = result

    with patch_etree_cname(etree):
        merged.write(output, encoding='utf-8', xml_declaration=True)


from kubernetes import client
import yaml

def handle_env(file):
    with open(file,'r') as f:
        env_data = yaml.safe_load(f)
    f.close()
    return [client.V1EnvVar(name=key,value=value) for key,value in env_data.items()]

def template(context):
    """
    handle yml env
    """
    name = context.get("name")
    labels = {"name": name}
    image_tag=context["name"].split('-')[1]
    image = context["image_namespace"]+image_tag+":"+context["image_branch"]
    args = [arg for arg in context["args"]] if context.get("args") else None
    limits,requests = context["resources"]["limits"],context["resources"]["requests"]
    replicas = context["replicas"][name]

    """
    handle cmdb env
    """
    filename = "env_" + name.split("-")[1] + ".yml"
    env = handle_env("/tmp/{}".format(filename))
    workingDir = context["workingDir"]

    """
    k8s yaml 组件模块
    """

    containers = [
                client.V1Container(
                    name = name,
                    image = image,
                    env = env,
                    args = args,
                    image_pull_policy = "Always",
                    # readiness_probe=client.V1Probe(_exec=client.V1ExecAction(command=['cat','/tmp/container_ready']),initial_delay_seconds=10, period_seconds=5),
                    resources = client.V1ResourceRequirements(limits = limits,requests = requests),
                    security_context = client.V1SecurityContext(privileged=True),
                    working_dir = working_dir,
                )
    ]

    template = client.V1PodTemplateSpec(
                    metadata = client.V1ObjectMeta(labels=labels),
                    spec = client.V1PodSpec(
                                containers = containers,
                                dns_policy = "ClusterFirst",
                                image_pull_secrets = [client.V1LocalObjectReference(name="image-pull-secret")],
                                restart_policy = "Always"
                            )

               )

    spec = client.V1StatefulSetSpec(
                service_name = name,
                replicas = replicas,
                selector = client.V1LabelSelector(match_labels=labels),
                template = template
           )

    return client.V1StatefulSet(
        api_version = "apps/v1",
        kind = "StatefulSet",
        metadata = client.V1ObjectMeta(name = name,labels = labels),
        spec = spec
    )


"""Tests for basic interactions"""
import time
from typing import Any
from selenium.webdriver.common.by import By
from selenium.webdriver.remote.webdriver import WebDriver

from .helpers import (
    wait_for_tagged_element,
    get_tab,
    screenshot_exception,
)

def test_tabs_available(
    webdriver: WebDriver,
    tallymarks_dataset: Any,
    frontend_base_url: str,
    skip_tour: None,
) -> None:
    """
    test to click tabs
    """

    from ._autogenerated_ui_elements import DataTestTags

    with screenshot_exception(webdriver):
        webdriver.get(frontend_base_url)
        driver = webdriver

        wait_for_tagged_element(webdriver, DataTestTags.HELP_BUTTON)

        time.sleep(1.0)

        wait_for_tagged_element(webdriver, DataTestTags.DATAGRID_ALL_TAB_BUTTON)
        num = int(
            wait_for_tagged_element(webdriver, DataTestTags.DATAGRID_ALL_COUNT).text
        )
        assert num > 10
        tab = wait_for_tagged_element(webdriver, DataTestTags.DATAGRID_ALL_TAB_BUTTON)
        tab.click()

        wait_for_tagged_element(webdriver, DataTestTags.DATAGRID_FILTERED_TAB_BUTTON)
        num = int(
            wait_for_tagged_element(
                webdriver, DataTestTags.DATAGRID_FILTERED_COUNT
            ).text
        )
        assert num > 10
        tab = wait_for_tagged_element(
            webdriver, DataTestTags.DATAGRID_FILTERED_TAB_BUTTON
        )
        tab.click()

        wait_for_tagged_element(webdriver, DataTestTags.DATAGRID_SELECTED_TAB_BUTTON)
        num = int(
            wait_for_tagged_element(
                webdriver, DataTestTags.DATAGRID_SELECTED_COUNT
            ).text
        )
        assert num == 0
        tab = wait_for_tagged_element(
            webdriver, DataTestTags.DATAGRID_SELECTED_TAB_BUTTON
        )

        tab.click()

        tab = get_tab(driver, "Scatter Plot")
        tab.click()

        tab = get_tab(driver, "Histogram")
        tab.click()

        tab = get_tab(driver, "Similarity Map")
        tab.click()

        tab = get_tab(driver, "Inspector")
        tab.click()

def test_tagged_elements_available(
    webdriver: WebDriver,
    tallymarks_dataset: Any,
    frontend_base_url: str,
    skip_tour: None,
) -> None:
    """
    test that elements with data-test-tag are available
    """
    from ._autogenerated_ui_elements import DataTestTags

    with screenshot_exception(webdriver):
        webdriver.get(frontend_base_url)

        driver = webdriver

        wait_for_tagged_element(webdriver, DataTestTags.HELP_BUTTON)

        for tag in [
            tag for name, tag in vars(DataTestTags).items() if not name.startswith("_")
        ]:
            if tag not in [
                DataTestTags.GLOBAL_LOADING_INDICATOR,
                DataTestTags.MESHVIEW_SETTINGS_DROPDOWN,
                DataTestTags.SEQUENCEVIEW_SETTINGS_DROPDOWN,
            ]:
                element = wait_for_tagged_element(webdriver, tag, 1)
                if "dropdown" in tag or "button" in tag:
                    element.click()
                driver.find_element(by=By.XPATH, value="//body").click()


import collections

import numpy as np
import pandas as pd
import pandas.util.testing as pdt

import modules.pd_utils as pd_utils

def extend_cam_id_ts(df):
    """Extend df with cam ids and timestamps.

    This function extracts information about the camera id and the timestamps of
    the first and last frame from the videonames (column curr_img_name
    and succ_img_name).
    >>> data = [('Cam_0_2016-07-19T12:41:22.353295Z--2016-07-19T12:47:02.199607Z.mkv',
    ...          'Cam_0_2016-07-19T12:41:22.353295Z--2016-07-19T12:47:02.199607Z.mkv')]
    >>> df = pd.DataFrame(data = data, columns=['curr_img_name', 'succ_img_name'])
    >>> df = extend_cam_id_ts(df)
    >>> df['curr_start_ts'].loc[0]
    Timestamp('2016-07-19 12:41:22.353295+0000', tz='<iso8601.Utc>')
    """
    curr_meta = df.apply(lambda row: pd_utils.extract_metadata_videoname(row['curr_img_name']), axis=1)
    curr_meta.columns = ['curr_cam_id', 'curr_start_ts', 'curr_end_ts']
    df = df.merge(curr_meta, left_index=True, right_index=True)
    succ_meta = df.apply(lambda row: pd_utils.extract_metadata_videoname(row['succ_img_name']), axis=1)
    succ_meta.columns = ['succ_cam_id', 'succ_start_ts', 'succ_end_ts']
    df = df.merge(succ_meta, left_index=True, right_index=True)
    return df

def extend_distance(df):
    """Extend df with distance.

    >>> data = [('A', '[[1,0,3],[1,0,4]]')]
    >>> df = pd.DataFrame(data=data, columns=['foo', 'warp_matrix'])
    >>> extend_distance(df)
    >>> df['distance'].loc[0]
    5.0
    """
    def get_distance(row):
        if pd.isnull(row['warp_matrix']):
            return np.NaN
        else:
            return np.linalg.norm(pd_utils.str_to_numpy(row['warp_matrix'])[:, 2])
    df['distance'] = df.apply(lambda row: get_distance(row), axis=1)

# %%
def load_ecc_csv_to_pd(path):
    """Load the data from the csv file to a pandas df."""
    names = ['id', 'curr_img_name', 'succ_img_name', 'cc', 'warp_matrix']
    df = pd.read_csv(path, sep=';', names=names, index_col=0)
    return df
# %%

def load_and_prepare(path):
    """Load data from ecc csv file and prepare it for further analysis."""
    df = load_ecc_csv_to_pd(path)
    df = extend_cam_id_ts(df)
    extend_distance(df)
    return df

def get_intervalls(path, accuracy):
    df = load_and_prepare(path)

    pdt.assert_series_equal(df['succ_cam_id'], df['curr_cam_id'], check_names=False)

    df_prep = df.drop(['warp_matrix', 'cc', 'succ_cam_id'], axis=1)

    # `df_prep['distance']` beschreibt die Bewegung welche von `curr_start` zu `succ_start` stattgefunden hat.

    shifted = df[['curr_img_name', 'curr_start_ts', 'curr_end_ts']].shift(1)
    shifted.columns = ['pred_img_name', 'pred_start_ts', 'pred_end_ts']

    df_ext = df_prep.merge(shifted, left_index=True, right_index=True)

    df_selection = df_ext[(df_ext['distance'] > accuracy)]

    # calculate all intervals
    intervals = []
    start = None

    interval = collections.namedtuple('interval', ['start', 'end', 'info'])

    for i, (index, row) in enumerate(df_selection.iterrows()):

        # Das erste Intervall beginnt mit dem ersten Video im Jahr
        if i == 0:

            # Start mit dem ersten Frame im Jahr.
            start = df_ext.loc[0]['curr_img_name']
            end = df_ext.loc[index]['pred_img_name']
            intervals.append(interval(start, end, 'ecc stable'))

            # Unsicheres Intervall
            # Da immer nur der erste Frame eines jeden Videos mit dem ersten
            # Frame des darauffolgenden Videos verglichen wurden, kann
            # eine mögliche Bewegung in dem Video, bevor die Veränderung
            # messbar war, stattgefunden haben.
            start = df_ext.loc[index]['curr_img_name']
            end = df_ext.loc[index]['curr_img_name']
            intervals.append(interval(start, end, 'ecc possible movement'))

            start = df_ext.loc[index]['succ_img_name']

        else:
            # Überpüft ob bereits im vorherigen Video eine Bewegung stattgefunden
            # hat.
            if (index - 1) not in df_selection.index.values:
                # Sicheres Intervall
                end = df_ext.loc[index]['pred_img_name']
                intervals.append(interval(start, end, 'ecc stable'))

                # Unsicheres Intervall
                start = df_ext.loc[index]['curr_img_name']
                end = df_ext.loc[index]['curr_img_name']
                intervals.append(interval(start, end, 'ecc possible movement'))
            else:
                # einzelnes Video welches direkt auf ein Video folgt,
                # bei welchem bereits auch schon eine Bewegung stattgefunden hat.
                start = df_ext.loc[index]['curr_img_name']
                end = df_ext.loc[index]['curr_img_name']
                intervals.append(interval(start, end, 'ecc double movement'))

            start = df_ext.loc[index]['succ_img_name']

            if i == len(df_selection) - 1:
                end = df_ext.loc[max(df_ext.index.values)]['succ_img_name']
                intervals.append(interval(start, end, 'last interval'))
    return intervals


import math
from typing import Callable, Any
from dataclasses import dataclass
from datetime import datetime, timedelta

@dataclass
class Event:
    time_until_happen: timedelta
    callback: Callable
    data: Any

    def __repr__(self):
        return self.callback.__qualname__

    __str__ = __repr__

class EventCalendar:
    def __init__(self):
        self.calendar: list[Event] = []

    def push(self, time: float, callback: Callable, **data: Any):
        """
        Add event to calendar ordered by time
        :param time: fire time
        :param callback: callback_function
        :param data: custom calback data.
        """
        event = Event(time_until_happen=time, callback=callback, data=data)
        edge_indexes = [0, len(self.calendar)]
        while edge_indexes[0] != edge_indexes[1]:
            pivot = math.floor((edge_indexes[0]+edge_indexes[1])/2)
            if time >= self.calendar[pivot].time_until_happen:
                edge_indexes[0] = pivot + 1
            else:
                edge_indexes[1] = pivot

        self.calendar.insert(edge_indexes[0], event)

    def pop(self):
        """
        remove nearest event
        :return (float): fire time
        :return (callable): callback function
        """
        return self.calendar.pop(0)

    @property
    def is_empty(self):
        """
        Check wheter calendar is empty
        :return:
        """
        return len(self.calendar) == 0

    def update_events(self, time_step: timedelta):
        for event in self.calendar:
            event.time_until_happen -= time_step

if __name__ == '__main__':
    print("="*50)
    event_calendar = EventCalendar()
    event_calendar.push(0, lambda: print('Primeira função'))
    event_calendar.push(15, lambda: print('Terceira função'))
    event_calendar.push(2, lambda: print('Segunda função'))
    for event in event_calendar.calendar:
        event.callback()
    print("="*50)
    event_calendar.pop()
    for event in event_calendar.calendar:
        event.callback()
    print("="*50)
    print(event_calendar.is_empty)
    print("=" * 50)
    event_calendar.pop()
    event_calendar.pop()

    print(event_calendar.is_empty)


"""# Import libraries and methods"""

import nltk
nltk.download('punkt')
from scipy import spatial
import statistics
#from word_vectors import WordVectors
import numpy as np
import pickle
import pandas as pd
import torch
import torch.utils.data

from typing import List, \
    Union
import os
import sys

import matplotlib.pyplot as plt
import seaborn as sns
import random
from collections import defaultdict
from collections import Counter
from current_files_gensim.word_vectors import WordVectors
from pytorch.model_torch import Word2VecModel
from pytorch.dataset_torch import create_skipgram, read_corpus

def read_corpus(path, min_len = 3):
    text = []
    #cut_min = lambda x: x if len(x) > min_len
    try:
        with open(path, 'r') as f:
            #text = [nltk.tokenize.word_tokenize(x.strip()) for x in f.readlines()]
            for x in f.readlines():
                res = nltk.tokenize.word_tokenize(x.strip())
                if len(res) > min_len:
                    text.append(res)
    except Exception as e:
        print(e)
    return text

torch.set_default_tensor_type(torch.cuda.FloatTensor if torch.cuda.is_available()
                                                    else torch.FloatTensor)

import datetime;

def split_given_size(a, size):
    return np.split(a, np.arange(size, len(a), size))

def get_emb_og(wv, word):
    """
    Function allowing to get the embedding of a given word.
    word: word of interest
    return: word embedding
    """

    # same as wv[word]
    return wv._syn0_final[wv._rev_vocab[word]]

def cos_similarity(tar, att):
    '''
    Calculates the cosine similarity of the target variable vs the attribute
    '''
    score = np.dot(tar, att) / (np.linalg.norm(tar) * np.linalg.norm(att))
    return score

def mean_cos_similarity(tar, att):
    '''
    Calculates the mean of the cosine similarity between the target and the range of attributes
    '''
    mean_cos = np.mean([cos_similarity(tar, attribute) for attribute in att])
    return mean_cos

def association(tar, att1, att2):
    '''
    Calculates the mean association between a single target and all of the attributes
    '''
    association = mean_cos_similarity(
        tar, att1) - mean_cos_similarity(tar, att2)

    return association

def effect_sizev2(t1, t2, att1, att2):
    '''
    Calculates the effect size (d) between the two target variables and the attributes
    Parameters:
        t1 (np.array): first target variable matrix
        t2 (np.array): second target variable matrix
        att1 (np.array): first attribute variable matrix
        att2 (np.array): second attribute variable matrix
    Returns:
        effect_size (float): The effect size, d.
    Example:
        t1 (np.array): Matrix of word embeddings for professions "Programmer, Scientist, Engineer"
        t2 (np.array): Matrix of word embeddings for professions "Nurse, Librarian, Teacher"
        att1 (np.array): matrix of word embeddings for males (man, husband, male, etc)
        att2 (np.array): matrix of word embeddings for females (woman, wife, female, etc)
    '''
    combined = np.concatenate([t1, t2])
    num1 = np.mean([association(target, att1, att2) for target in t1])
    num2 = np.mean([association(target, att1, att2) for target in t2])
    combined_association = np.array(
        [association(target, att1, att2) for target in combined])

    dof = combined_association.shape[0]
    denom = np.sqrt(
        ((dof-1)*np.std(combined_association, ddof=1) ** 2) / (dof-1))
    effect_size = (num1 - num2) / denom

    return effect_size

"""# Load data"""

BATCH_SIZE = 256
NEGATIVES = 5
EPOCHS = 3
SAMPLING_RATE = 1E-3
MIN_FREQ = 60
WINDOW_SIZE = 5
LEARNING_RATE = 1E-3
HIDDEN_SIZE = 300
# liste_termini_weat
S = ["science", "technology", "physics", "chemistry", "einstein", "nasa",
    "experiment", "astronomy"]
T = ["poetry", "art", "shakespeare", "dance", "literature", "novel", "symphony", "drama"]
A = ["male", "man", "boy", "brother", "he", "him", "his", "son"]
B = ["female", "woman", "girl", "sister", "she", "her", "hers", "daughter"]
WEATLIST = S+T+A+B

text = read_corpus('./corpus/nyt_dal_90_ad_oggi.txt')

with open("./content/data_correct_post_train/data_v2.pkl", "rb") as f:
  data = pickle.load(f)

with open("unigram_counts.pkl", "rb") as f:
  unigram_counts = pickle.load(f)

with open("vocab.pkl", "rb") as f:
  vocab = pickle.load(f)

with open("inv_vocab.pkl", "rb") as f:
  inv_vocab = pickle.load(f)

S_A = S.copy()+A.copy()
random.seed(0)
random.shuffle(S_A)
print(S_A)

def get_tuples(sentence, vocab):
  _data = []

  window = 5
  for i, t in enumerate(sentence):

      contexts = list(range(i-window, i + window+1))
      contexts = [c for c in contexts if c >=
                  0 and c != i and c < len(sentence)]
      for c in contexts:
          # TARGET, CONTEXT, nsent
          _data.append((vocab[t], vocab[sentence[c]], 1))

  return _data

sent_tuples = get_tuples(S_A, vocab)

list_index_weat = []
for word in S+T+A+B:
  list_index_weat.append(vocab[word])

list_approx_words = list(set(list_index_weat.copy()))

flat_data = [x for y in data for x in y] # 6 secondi
for tu in sent_tuples:
    flat_data.append(np.array([tu[0], tu[1], -1]))
tuple_set = {(x[0], x[1]) for x in iter(flat_data)} # 32 secondi
tuple_set_1 = [x for x in tuple_set if x[0] in list_approx_words] #1m 7s secondi

tuple_set_ord = tuple_set_1.copy()
tuple_set_ord.sort(key=lambda i:i[1],reverse=True)

list_sim_sent_retrain = []
sent_id =  -1
sent_text = text[sent_id]

log_per_steps= 1000#10000  # Every `log_per_steps` steps to log the value of loss to be minimized.

#flat_data = [x for xs in data for x in xs]
#flat_data_rt = [x for x in flat_data if x[2]!=sent_id]
data_rt = split_given_size(flat_data, BATCH_SIZE)
data_rt = [x for x in data_rt if len(x) == BATCH_SIZE]
unigram_counts_rt = unigram_counts.copy()
vocab_rt = vocab.copy()
for key in vocab:
    if key in sent_text:
        unigram_counts_rt[vocab[key]] = unigram_counts[vocab[key]]+1
inv_vocab_rt = {v: k for k, v in vocab_rt.items()}

        #data_rt, unigram_counts_rt, vocab_rt, inv_vocab_rt = create_skipgram(text_rt, WINDOW_SIZE, WEATLIST, MIN_FREQ, SAMPLING_RATE, EPOCHS, BATCH_SIZE)

word2vec = Word2VecModel(hidden_size=300,
                         batch_size=BATCH_SIZE,
                         negatives=NEGATIVES,
                         power=0.75,
                         alpha=LEARNING_RATE)

word2vec._data = data_rt
word2vec._vocab = vocab_rt
word2vec._unigram_counts = unigram_counts_rt
word2vec._vocab_size = len(unigram_counts_rt)
word2vec._inv_vocab = inv_vocab_rt
word2vec._text = text

word2vec.build_weights()
word2vec.train(EPOCHS, save=False)

print("Re-training for sentence "+str(sent_id)+" completed")

w0 = word2vec.syn0.cpu().detach().numpy()
w1 = word2vec.syn1.cpu().detach().numpy()

vocab_words = [word for word in vocab_rt]

wv = WordVectors(w0, vocab_words)

# compute original effect size and similarities:
t1 = np.array([get_emb_og(wv, word) for word in S])
t2 = np.array([get_emb_og(wv, word) for word in T])
att1 = np.array([get_emb_og(wv, word) for word in A])
att2 = np.array([get_emb_og(wv, word) for word in B])

simSA = np.array([mean_cos_similarity(tar, att1) for tar in t1]).mean()
simTA = np.array([mean_cos_similarity(tar, att1) for tar in t2]).mean()
simSB = np.array([mean_cos_similarity(tar, att2) for tar in t1]).mean()
simTB = np.array([mean_cos_similarity(tar, att2) for tar in t2]).mean()

print("effect size retraining: ", effect_sizev2(t1, t2, att1, att2))
print("similarity S-A origin: ", simSA)
print("similarity T-A origin: ", simTA)
print("similarity S-B origin: ", simSB)
print("similarity T-B origin: ", simTB)


import cv2 as cv

if __name__=="__main__":

    cam = cv.VideoCapture(-1)

    while(True):

        flag, frame = cam.read()

        if(not flag):
            print("Frame grab error")
            continue

        cv.imshow("Frame", frame)

        if(cv.waitKey(1) == ord('q')):
            break

    cv.destroyAllWindows()


from torchvision.transforms import Compose, Resize, CenterCrop, RandomHorizontalFlip, RandomRotation, ColorJitter, Normalize,ToTensor

class Pixt_ImageTransform:
    def __init__(self):
        self.transform = Compose(
            [
                Resize((256, 256)),
                CenterCrop((224, 224)),
                RandomHorizontalFlip(0.5),
                RandomRotation(degrees=(-15,15)),
                ColorJitter(brightness=0.2,contrast=0.2,saturation=0.2,hue=0.1),
                ToTensor(),

            ]
        )

    def __call__(self, x):
        return self.transform(x)

class Pixt_ValidationTest_Transform:
    def __init__(self):
        self.transform=Compose(
            [
                Resize((256,256)),
                CenterCrop((224,224)),
                ToTensor(),

            ]
        )

    def __call__(self,x):
        return self.transform(x)


import tkinter as tk
from decimal import *
import RSAMfinder
from tkinter import ttk
import threading
import tkinter.scrolledtext as tkscrolled
from PIL import ImageTk, Image
import os,sys,random,time

class parameters_frame(object):
    def __init__(self,top,labels,specification):
        self.top = top
        self.v = None

        if specification == 'general':
            self.entries, self.error_labels, self.error, self.only_draw = makeform(self, self.top, labels)
        elif specification == 'patterns':
            self.entries = make_patterns_tab(self.top, ['p1','p2'])
        elif specification == 'figure_params':
            self.entries = make_figure_parameters(self,self.top)

    def work_task (self):
        return self.entries

    def callback_color(self,bool_var,entries):
        ent = list(filter(
            lambda x: x[0] == 'number_of_dup', entries))[0]

        if not bool_var.get():
            ent[1].delete(0, tk.END)
            ent[1].config(state='disabled')
        else:
            ent[1].config(state='normal')
            ent[1].delete(0, tk.END)
            ent[1].insert("end", '3')

    def callback_random_sol(self,bool_var,entry):
        if bool_var.get():
            entry.delete(0,tk.END)
            entry.config(state='disabled')
        else:
            entry.config(state='normal')

    def callback_only_draw(self,bool_var,entries,fields):
        temp_ents = list(filter(lambda x: x[0] not in ['track_solution','create_sigma','draw','random_sol',"Data Folder's name"
            ,'Color specification','only_draw'], entries))
        draw_check_butt = list(filter(lambda x: x[0] == 'draw', entries))[0]

        if bool_var.get():
            for entry in temp_ents:
                entry[1].delete(0,tk.END)
                entry[1].config(state='disabled')
            draw_check_butt[1].set('1')
        else:
            for entry in temp_ents:
                entry[1].config(state='normal')
                entry[1].delete(0,tk.END)
                entry[1].insert("end",fields[temp_ents.index(entry)+2][2])
            draw_check_butt[1].set('0')

def make_patterns_tab(root, patterns):
    entries = []
    t1 = tk.Frame(root)

    for p in patterns:
        row = tk.Frame(root)
        names = ['Event1','Event2','Event3','Colors','Distance']
        for name in names:
            lab = tk.Label(row, text=name,width=10)
            lab.grid(row=0, column=names.index(name)+1)
        lab = tk.Label(row, width=20, text=p)
        lab.grid(row=1,column=0)

        number_of_events = 3
        for i in range(0,number_of_events):
            string_var = tk.StringVar(t1)
            if i == 0 and patterns.index(p) == 0:
                string_var.set('S')
            else:
                string_var.set('None')
            EV = ['S','D','HT','None']
            EV = tk.OptionMenu(row, string_var, *EV)
            EV.grid(row=1, column=i+1)
            entries.append((p+'_event'+str(i),string_var))
        colors = ['red','black','None']
        string_var = tk.StringVar(t1)
        string_var.set('None')
        colors_op = tk.OptionMenu(row, string_var, *colors)
        colors_op.config(width=10)
        colors_op.grid(row=1, column=number_of_events+1)
        entries.append((p + '_colors', string_var))

        string_var = tk.BooleanVar(t1)
        c = tk.Checkbutton(row,variable=string_var)
        entries.append((p + '_dis', string_var))
        c.grid(row=1, column=number_of_events+2)
        row.pack(side=tk.TOP, fill=tk.X, padx=5, pady=5)
    return entries

def floatValidation(S):
    flag = True
    for s in S:
        if s not in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.']:
            flag = False
    if flag:
        return True
    t3.bell()  # .bell() plays that ding sound telling you there was invalid input
    return False

def make_figure_parameters(self,root):
    def intValidation(S):
        flag = True
        for s in S:
            if s not in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']:
                flag = False
        if flag:
            return True
        t1.bell()  # .bell() plays that ding sound telling you there was invalid input
        return False

    bool_var = []
    c = []
    entries = []
    t1 = tk.Frame(root)
    names = [('color','Whether or not the figuer will be colored.\n'
                      'If a duplication event is part of p1 or'
                      'p2, duplications will also be colored.'),
             ('labels', 'Whether or not labels will appear in the figure.'),
             ('draw marked','Whether or not mark the interesting vertices in the figure.')]
    for name in names:
        lab = tk.Label(t1, text=name[0],width=10)
        ind = names.index(name)
        lab.grid(row=0, column=ind)
        bool_var.append(tk.BooleanVar(t1))
        c.append(tk.Checkbutton(t1, variable=bool_var[ind],command=lambda param=bool_var[ind]: self.callback_color(param,entries)))
        entries.append((name[0], bool_var[ind]))
        c[ind].grid(row=1, column=ind)
        c[ind].select()
        t1.pack(side=tk.TOP, padx=5, pady=5)
        CreateToolTip(lab, text=name[1])

    lab = tk.Label(t1, width=15, text='Minimal number\nof duplications\nto color.')
    intVal = (t1.register(intValidation), '%S')
    ent = tk.Entry(t1, validate='key', vcmd=intVal, width=5)
    ent.insert("end", '3')
    lab.grid(row=2, column=0)
    ent.grid(row=3, column=0)
    CreateToolTip(lab, text='This is the minumal number of duplication\n'
                            ' that will be colored if duplication event is\n'
                            'a part of p1' )
    entries.append(('number_of_dup', ent))
    t1.pack(side=tk.TOP, padx=0, pady=5)

    row = tk.Frame(root)
    CreateToolTip(row, text='Figure proportions')
    floatVal = (row.register(floatValidation), '%S')

    lab = tk.Label(row, width=2, text='x:')
    ent = tk.Entry(row, validate='key', vcmd=floatVal,width=5)
    ent.insert("end",'100')
    lab.grid(row=0, column=0)
    ent.grid(row=0, column=1)
    entries.append(('x', ent))
    row.pack(side=tk.TOP, padx=0, pady=5)

    lab = tk.Label(row, width=5, text='X')
    lab.grid(row=0, column=2)

    lab = tk.Label(row, width=2, text='y:')
    ent = tk.Entry(row, validate='key', vcmd=floatVal,width=5)
    ent.insert("end",'40')
    lab.grid(row=0, column=3)
    ent.grid(row=0, column=4)
    entries.append(('y', ent))
    row.pack(side=tk.TOP, padx=0, pady=5)

    row = tk.Frame(root)
    lab = tk.Label(row, text='Draw Species and Gene trees', width=25)
    lab.grid(row=0, column=0)
    draw_S_and_G = tk.BooleanVar(root)
    tk.Checkbutton(row, variable=draw_S_and_G).grid(row=1,column=0)
    entries.append(('draw_S_and_G', draw_S_and_G))
    row.pack(side=tk.TOP, padx=0, pady=5)
    return entries

def makeform(param_frame, root, fields):
    def intValidation(S):
        flag = True
        for s in S:
            if s not in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']:
                flag = False
        if flag:
            return True
        t3.bell()  # .bell() plays that ding sound telling you there was invalid input
        return False

    error_labels = {}
    entries = []
    t3 = tk.Frame(root)
    intVal = (t3.register(intValidation), '%S')
    floatVal = (t3.register(floatValidation), '%S')

    row = tk.Frame(root)

    bool_var1 = tk.BooleanVar(row)
    butt = tk.Checkbutton(row, variable=bool_var1,
                          command=lambda: param_frame.callback_only_draw(bool_var1, entries, fields))
    butt.grid(row=0, column=1)
    lab = tk.Label(row, text='only draw', width=10)
    lab.grid(row=0, column=0)
    entries.append(('only_draw', bool_var1))
    row.pack(side=tk.TOP, padx=0, pady=5)

    for field in fields:
        if len(field) >= 3:
            row = tk.Frame(root)
            lab = tk.Label(row, width=20, text=field[0])
            if field[1] == 'float':
                ent = tk.Entry(row, validate='key',vcmd=floatVal,width=10)
            elif field[1] == 'int':
                ent = tk.Entry(row, validate='key', vcmd=intVal,width=10)
            else:
                ent = tk.Entry(row, validate='key',width=10)
            if field[2]:
                ent.insert("end",field[2])
            lab.grid(row=fields.index(field),column=0)
            ent.grid(row=fields.index(field),column=1)
            if field[0].find('cost') == -1:
                CreateToolTip(lab, text=field[3])
            error_labels.update({field[0]+' error':tk.StringVar()})
            lab = tk.Label(row, font=('Helvetica', 18, 'bold'), fg='red', width=5, textvariable=error_labels[field[0] + ' error'],justify=tk.LEFT)
            lab.grid(row=fields.index(field), column=3)
            entries.append((field[0], ent))
            row.pack(side=tk.TOP, padx=0, pady=5)

    row = tk.Frame(root,background='grey')
    lab = tk.Label(row, text='create sigma from FASTA file', width=30,background='grey')
    lab.grid(row=0, column=0)
    CreateToolTip(lab, text='If this option is selected, the user\n'
                            'should provide a FASTA file, called\n'
                            ' FASTA_(extention).txt, Otherwise,\n'
                            ' the user should proves Gene tree where\n'
                            ' the leaves are labeled with their\n'
                            ' corresponding Species, in the following\n'
                            ' format: (species name)g -> (species name).\n'
                            'For example, Ag->A.')
    create_sigma = tk.BooleanVar(t3)
    c = tk.Checkbutton(row, variable=create_sigma,background='black')
    c.grid(row=0, column=1)
    entries.append(('create_sigma', create_sigma))
    c.select()

    lab = tk.Label(row, text='Draw the gene tree', width=20,background='grey')
    lab.grid(row=0, column=2)
    draw = tk.BooleanVar(t3)
    c = tk.Checkbutton(row, variable=draw,background='black')
    c.grid(row=0, column=3)
    entries.append(('draw', draw))
    row.pack(side=tk.TOP, fill=tk.X, padx=0, pady=5)

    row = tk.Frame(root)
    lab = tk.Label(row, text='track solution number:', width=20)
    lab.grid(row=0, column=0)
    CreateToolTip(lab, text='If this option is selected, the program will\n'
                            'output the desired solution. One can select a\n'
                            'random solution, and the output will be one \n'
                            'random solution out od the k.')

    intVal = (t3.register(intValidation), '%S')
    track_sol_ent = tk.Entry(row, validate='key', vcmd=intVal, width=5)
    entries.append(('track_solution', track_sol_ent))
    track_sol_ent.grid(row=0, column=1)

    bool_var = tk.BooleanVar(row)
    butt = tk.Checkbutton(row, variable=bool_var, command=lambda: param_frame.callback_random_sol(bool_var,track_sol_ent))
    butt.grid(row=0, column= 3)
    lab = tk.Label(row, text='random solution', width=15)
    lab.grid(row=0, column=2)
    entries.append(('random_sol', bool_var))

    error = tk.StringVar()
    lab = tk.Label(row, font=('Helvetica', 11, 'bold'), fg='red', width=20,
                   textvariable=error, justify=tk.LEFT)
    lab.grid(row=0, column=4)

    row.pack()
    return entries, error_labels, error, bool_var1

class Main_Frame(object):
    def __init__(self, top=None):
        self.top = top
        img = ImageTk.PhotoImage(Image.open("logo.jpg"))
        panel = tk.Label(root, image=img)
        panel.pack(side="top", fill="both", expand="yes")

        parameter_lables = [["Data Folder's name", 'string', '',
                             "This is the folder's name under /data/"],
                            ['Color specification', 'string', '',
                             'This is the extension of the file colors_(extension).txt'],
                            ['k', 'int', '10','Value of k for the k-best hypergraph'],
                            ['Threshold Edges\nin Subtree', 'float', '0.1','The minimal number of edges in subtrees that\n'
                                                                           'will considered when looking for top scoring vertices\n'
                                                                           'within the gene tree.'],
                            ['HT event cost', 'float', '1'], ['Duplication event cost', 'float', '1'],['Speciation event cost', 'float', '0'], ['Loss event cost', 'float', '1'],
                            ['Gamma', 'float', '1','A parameter related to the probablity calculation.\n'
                                                   'As gamma grows lower, hypernodes with higher (worse)\n'
                                                   'scores are assigned probabilities much lower than'
                                                   ' hypernodes with lower scores.'],
                            ['p', 'float', '0.05',"Defins how much is 'mostly red' and 'mostly black'"],
                            ['Number of Vertices to find', 'int', 5,'How many Gene tree vertices will be reported.']]

        nb = Notebook(self.top,'RSAM-Finder')
        t1 = nb.add_tab('General Parameters', parameters_frame, parameter_lables,'general')
        t2 = nb.add_tab('Pattern Definitions', parameters_frame,[],'patterns')
        t3 = nb.add_tab('Figure Parameters', parameters_frame, [], 'figure_params')

        self.b1 = tk.Button(top, text='Run',
                            command=lambda: self.bar_init(t1,t2,t3))
        self.b1.pack(side=tk.TOP, padx=5, pady=5)
        b2 = tk.Button(top, text='Quit', command=top.quit)
        b2.pack(side=tk.TOP, padx=5, pady=5)

        self.result = {'text': '', 'error': '', 'solution': ''}
        self.msg_error = None
        # run mainloop
        self.top.mainloop()

    def bar_init(self,t1,t2,t3):
        ent1 = t1.work_task()
        ent2 = t2.work_task()
        ent3 = t3.work_task()

        only_draw = t1.only_draw.get()
        for ent in ent1:
            if ent[0] not in ['track_solution','create_sigma','draw','random_sol','only_draw']:
                if not only_draw or (ent[0] == "Data Folder's name") or (ent[0] == 'Color specification'):
                    if ent1[ent1.index(ent)][1].get() == '':
                        t1.error_labels[ent[0]+' error'].set('*')
                        return
                else:
                    t1.error_labels[ent[0] + ' error'].set('')
        self.window = tk.Toplevel(root)
        msg = tk.Message(self.window, text='RSAM-finder in progress...')
        msg.grid(row=0, column=0)
        self.load_bar = ttk.Progressbar(self.window)
        self.load_bar.grid(row=1, column=0)
        # first layer of isolation, note var being passed along to the self.start_bar function
        # target is the function being started on a new thread, so the "bar handler" thread
        self.start_bar_thread = threading.Thread(target=self.start_bar, args=(ent1+ent2+ent3, t1))
        # start the bar handling thread
        self.start_bar_thread.start()

    def start_bar(self, ent, t1):
        # the load_bar needs to be configured for indeterminate amount of bouncing
        self.load_bar.config(mode='determinate', maximum=100, value=0)
        # 8 here is for speed of bounce
        self.load_bar.start(8)
        # start the work-intensive thread, again a var can be passed in here too if desired
        self.work_thread = threading.Thread(target=self.work_task, args=(ent, ['p1','p2'], t1))
        self.work_thread.start()
        # close the work thread
        self.work_thread.join()
        # stop the indeterminate bouncing
        self.load_bar.stop()
        # reconfigure the bar so it appears reset
        self.load_bar.config(value=0, maximum=0)
        self.window.destroy()
        if self.result['error'] != '':
            if self.msg_error:
                self.msg_error.destroy()
            self.msg_error = tkscrolled.ScrolledText(self.top, width=100, height=10)
            self.msg_error.insert(1.0, self.result['error'],'error')
            self.msg_error.tag_config('error',foreground='red')
            self.msg_error.pack()
            self.result['error'] = ''
            self.result['text'] = ''
            self.result['solution'] = ''
        elif self.result['text'] != '':
            msg = tkscrolled.ScrolledText(self.top, width=100, height=10)
            msg.insert(1.0, self.result['text'])
            if self.msg_error:
                self.msg_error.destroy()
            msg.pack()
            self.b1.destroy()
            b3 = tk.Button(self.top, text='Restart',command=lambda: os.execl(sys.executable, sys.executable, * sys.argv))
            b3.pack()

        if self.result['solution'] != '':
            solution_frame = tk.Toplevel()
            TKScrollTXT = tkscrolled.ScrolledText(solution_frame, width=80, height=50)
            TKScrollTXT.insert(1.0, self.result['solution'])
            TKScrollTXT.pack(side=tk.LEFT)
        os.system("say 'התוכנית הסתיימה'")

    def work_task(self, entries, patterns, t1):
        p1_EV = []
        p2_EV = []
        for e in entries:
            if e[1]:
                for p in patterns:
                    if e[0].find(p) != -1:
                        if e[0][3:].find('event') != -1:
                            eval(p + '_EV').append(e[1].get())
                        if e[0][3:].find('colors') != -1:
                            exec("%s = '%s'" % (p+'_color',e[1].get()),locals(),globals())
                        if e[0][3:].find('dis') != -1:
                            exec("%s = '%s'" % (p + '_dis', e[1].get()), locals(), globals())
        p1 = (p1_EV, p1_color, p1_dis)
        if p2_EV != ['None','None','None']:
            p2 = (p2_EV, p2_color, p2_dis)
        else:
            p2 = [None,None,None]
        vars = []
        for entry in entries:
            if entry[0].find('p1') == -1 and entry[0].find('p2') == -1:
                text = entry[1].get()
                vars.append(text)
        only_draw ,speciesTreespecification, color_ext, k, TH_edges, HT_cost, D_cost, S_cost, loss_cost,\
        gamma, p, number_of_planted_vertices, create_sigma, draw, track_solution, random_sol, color,\
        labels,draw_marked,number_of_dup, x, y, draw_S_and_G = vars

        if number_of_dup == '':
            number_of_dup = 0
        if track_solution == "":
            track_solution = False
        elif int(track_solution) > int(k):
            t1.error.set('must be lower than k')
            return
        if random_sol:
            track_solution = random.choice(range(0,int(k)))

        if t1.only_draw.get():
            k = TH_edges = HT_cost = D_cost = S_cost = loss_cost = gamma = p = number_of_planted_vertices = 0
            track_solution = 0
        RSAMfinder.main(speciesTreespecification, color_ext, int(k), Decimal(TH_edges), int(HT_cost), int(D_cost), int(S_cost),
                        int(loss_cost), Decimal(gamma), Decimal(p), int(number_of_planted_vertices), p1, p2, create_sigma,
                        track_solution, draw, color,labels,draw_marked,x,y, self.result, only_draw, draw_S_and_G, int(number_of_dup))

class Notebook:
    def __init__(self,top,title):
        self.root = top
        self.root.title(title)
        self.notebook = ttk.Notebook(self.root)

    def add_tab(self, title, func,labels,specification):
        frame = ttk.Frame(self.notebook)
        self.notebook.add(frame, text=title)
        tab = func(frame,labels,specification)
        self.notebook.pack()
        return tab

    def run(self):
        self.root.mainloop()

class ToolTip(object):
    def __init__(self, widget):
        self.widget = widget
        self.tipwindow = None
        self.id = None
        self.x = self.y = 0

    def showtip(self, text):
        time.sleep(2)
        self.text = text
        if self.tipwindow or not self.text:
            return
        x, y, cx, cy = self.widget.bbox("insert")
        x = x + self.widget.winfo_rootx() + 57
        y = y + cy + self.widget.winfo_rooty() +27
        self.tipwindow = tw = tk.Toplevel(self.widget)
        tw.wm_overrideredirect(1)
        tw.wm_geometry("+%d+%d" % (x, y))
        label = tk.Label(tw, text=self.text, justify=tk.LEFT,
                      background="#ffffe0", relief=tk.SOLID, borderwidth=1,
                      font=("tahoma", "10", "normal"))
        label.pack(ipadx=1)

    def hidetip(self):
        tw = self.tipwindow
        self.tipwindow = None
        if tw:
            tw.destroy()

def CreateToolTip(widget, text):
    toolTip = ToolTip(widget)
    def enter(event):
        toolTip.showtip(text)
    def leave(event):
        toolTip.hidetip()
    widget.bind('<Enter>', enter)
    widget.bind('<Leave>', leave)

root = tk.Tk()
Main_Frame(root)


import PySimpleGUI as sg
import os.path
import textwrap
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import UV_Vis_reader

def draw_figure(canvas, figure):
    figure_canvas_agg = FigureCanvasTkAgg(figure, canvas)
    figure_canvas_agg.draw()
    figure_canvas_agg.get_tk_widget().pack(side='top', fill='both')
    return figure_canvas_agg

fig_canvas_agg = []
folder = []
t_unit = 's'
t_adj = 1
x_range = None
start = 0
inc = None
region_limits = []

sg.theme('LightBrown2')

file_list_column = [
    [sg.Text("UV-Vis Spectra Processor", font='Any 18')],
    #[sg.Text("This program shows multiple UV-Vis spectra on a single figure, integrate a peak in multiple UV-Vis spectra and graph these results")],
    [
        sg.Text("UV-Vis files folder"),
        sg.Input(size=(25, 1), enable_events=True, key="-FOLDER-"),
        sg.FolderBrowse()
    ],
    [sg.Listbox(values=[], enable_events=True, size=(40, 10), key="-FILE LIST-")],
    [
        sg.Text("Time unit"),
        sg.Combo(["s", "min", "h"], default_value="s", enable_events=True, key="-t_unit-")
    ],
    [sg.Text("Show absorption spectra", font=("Arial", 12, ' underline'))],
    [
        sg.Text("First spectrum"),
        sg.InputText(size=(5, 1), key="-FS-"),
        sg.Text("Spectra increment"),
        sg.InputText(size=(5, 1), key="-SI-"),
    ],
    [
        sg.Text("Lower x bound"),
        sg.InputText(size=(5, 1), key="-LB1-"),
        sg.Text("Upper x bound"),
        sg.InputText(size=(5, 1), key="-UB1-"),
    ],
    [sg.Button('Submit/Update', key="-SUBMIT1-")],
    [sg.Text("Calculate integrals and export", font=("Arial", 12, ' underline'))],
    [
        sg.Text("Lower range limit"),
        sg.InputText(size=(5, 1), key="-LB2-"),
        sg.Text("Upper range limit"),
        sg.InputText(size=(5, 1), key="-UB2-"),
    ],
    [
        sg.Text("Export path"),
        sg.Input(size=(25, 1), enable_events=True, key="-FILE-"),
        sg.FileBrowse()
    ],
    [sg.Button('Submit/Update', key="-SUBMIT2-")],
]

image_viewer_column = [
    [sg.Text('Plot', font=("Arial", 12, ' underline'))],
    [sg.Frame("Frame", [[sg.Canvas(key='-CANVAS-', expand_x=True, expand_y=True)]], size=(450, 450))]
]

layout = [
    [
        sg.Column(file_list_column),
        sg.VSeperator(),
        sg.Column(image_viewer_column),
    ]
]

window = sg.Window("UV-Vis Spectra Processor", layout, resizable=True, finalize=True)

while True:
    event, values = window.read()
    if event == "Exit" or event == sg.WIN_CLOSED:
        break
    # Folder name was filled in, make a list of files in the folder
    if event == "-FOLDER-":
        folder = values["-FOLDER-"]
        try:
            # Get list of files in folder
            file_list = os.listdir(folder)
        except:
            file_list = []

        fnames = [
            f
            for f in file_list
            if os.path.isfile(os.path.join(folder, f))
            and f.lower().endswith((".txt"))
        ]
        window["-FILE LIST-"].update(fnames)
    elif event == "-FILE-":
        exportpath = values["-FILE-"]

    elif event == "-t_unit-":
        t_unit = values["-t_unit-"]
        t_adj = UV_Vis_reader.get_t_adj(t_unit)

    elif event == "-SUBMIT1-":
        try:
            if values["-FS-"] != '': start = int(values["-FS-"])
            if values["-SI-"] != '': inc = int(values["-SI-"])
            if values["-LB1-"] != '' or values["-LB1-"] != '': x_range = tuple([float(values["-LB1-"]), float(values["-UB1-"])])
            if fig_canvas_agg: fig_canvas_agg.get_tk_widget().forget()
            fig = UV_Vis_reader.plot_spec(folder, x_range=x_range, start=start, inc=inc, t_adj=t_adj)
            fig_canvas_agg = draw_figure(window['-CANVAS-'].TKCanvas, fig)
        except:
            if not folder:
                sg.Popup('Select data folder')
            else:
                sg.Popup('Error detected. Please refer to operating manual')

    elif event == "-SUBMIT2-":
        try:
            region_limits = [tuple([float(values["-LB2-"]), float(values["-UB2-"])])]
            arr_res = UV_Vis_reader.integral_calc(folder, region_limits, t_adj=t_adj)
            UV_Vis_reader.spec_export(arr_res, region_limits, exportpath)
            if fig_canvas_agg: fig_canvas_agg.get_tk_widget().forget()
            fig = UV_Vis_reader.plot_integral(arr_res, t_unit=t_unit)
            fig_canvas_agg = draw_figure(window['-CANVAS-'].TKCanvas, fig)
        except:
            try:
                region_limits = [tuple([float(values["-LB2-"]), float(values["-UB2-"])])]
                try:
                    arr_res = UV_Vis_reader.integral_calc(folder, region_limits, t_adj=t_adj)
                    if fig_canvas_agg: fig_canvas_agg.get_tk_widget().forget()
                    fig = UV_Vis_reader.plot_integral(arr_res, t_unit=t_unit)
                    fig_canvas_agg = draw_figure(window['-CANVAS-'].TKCanvas, fig)
                except:
                    if not folder:
                        sg.Popup('Select data folder')
                    else:
                        sg.Popup('Error detected - please refer to operating manual')
            except:
                if not folder:
                    sg.Popup('Select data folder')
                elif not region_limits:
                    sg.Popup('Input lower and upper range limit')
                else:
                    sg.Popup('Error detected - please refer to operating manual')

window.close()


from concurrent.futures import ProcessPoolExecutor
from requests import Session
from requests_futures.sessions import FuturesSession

def callback(future):
    print(type(future))
    response = future.result()
    print(response.json()["args"])

session = FuturesSession(executor=ProcessPoolExecutor(max_workers=10),
                         session=Session())
for i in range(10):
    future_response = session.get('http://httpbin.org/get?foo=' + str(i))
    future_response.add_done_callback(callback)

print("done")