# -*- coding: utf-8 -*-
### Module import
import sys
import os
import random
import matplotlib
import pickle
import numpy as np
import signal
import scipy.stats as st
import matplotlib.pyplot as plt
from scipy import io
from scipy.interpolate import interp1d
from scipy.integrate import odeint
from scipy import interpolate
import scipy.integrate as spi
from multiprocessing import Pool
from scipy.interpolate import interp2d
from scipy.interpolate import RectBivariateSpline
from scipy.interpolate import Rbf
from scipy.interpolate import griddata
from scipy.interpolate import BSpline
import matplotlib.animation as animation
import copy
import seaborn as sn

#nice plotting style
matplotlib.rcParams['pdf.fonttype'] = 42
sn.set_style("whitegrid", {'xtick.direction': 'out', 'xtick.major.size': 6.0,
            'xtick.minor.size': 3.0, 'ytick.color': '.15',
            'ytick.direction': 'out', 'ytick.major.size': 6.0,
            'ytick.minor.size': 3.0})

#sys.path.insert(0, os.path.realpath('./Classes'))

class DetSim:
    """
    This class is used to simulate traces using a deterministic version of the
    system.
    """
    def __init__(self, l_parameters, cell, temperature, upfolder = True):
        """
        Constructor of DetSim.

        Parameters
        ----------
        l_parameters : list
            A list of all parameters needed for simulation:
            dt : time increment (float)
            sigma_em_circadian : circadian observation noise (float)
            W : waveform (list)
            pi : initial state distribution (ndarray)
            N_theta : number of circadian states (integer)
            std_theta : circadian phase diffusion parameter (float)
            period_theta : circadian period (integer)
            l_boundaries_theta : Limits of the circadian domain (list)
            w_theta : circadian speed (float)
            N_phi : number of cell-cyle states (integer)
            std_phi : cell-cyle phase diffusion parameter (float)
            period_phi : cell-cyle period (integer)
            l_boundaries_phi : Limits of the cell-cycle domain (list)
            w_phi : cell-cycle speed (float)
            N_amplitude_theta : number of amplitude states (integer)
            mu_amplitude_theta : mean amplitude (float)
            std_amplitude_theta : amplitude standard deviation (float)
            gamma_amplitude_theta : amplitude regression constant (float)
            l_boundaries_amplitude_theta : limits of the amplitude domain (list)
            N_background_theta : number of background states (integer)
            mu_background_theta : mean background (float)
            std_background_theta : background standard deviation (float)
            gamma_background_theta : background regression constant (float)
            l_boundaries_background_theta : limits of the background domain
                                            (list)
            F : coupling function (ndarray)
        cell : string
            The type of cell used in the experiment.
            Either 'NIH3T3' or 'U2OS'
        temperature : integer
            The temperature condition used in the experiment.
            Either 34, 37 or 40
        """
        [dt, sigma_em_circadian, W, pi,
        N_theta, std_theta, period_theta, l_boundaries_theta, w_theta,
        N_phi, std_phi, period_phi, l_boundaries_phi, w_phi,
        N_amplitude_theta, mu_amplitude_theta, std_amplitude_theta,
        gamma_amplitude_theta, l_boundaries_amplitude_theta,
        N_background_theta, mu_background_theta, std_background_theta,
        gamma_background_theta, l_boundaries_background_theta,
        F] = l_parameters

        self.gamma_A = gamma_amplitude_theta
        self.gamma_B = gamma_background_theta
        self.T_theta = 2*np.pi/w_theta
        self.T_phi = 2*np.pi/w_phi
        self.F = F
        self.pi = pi
        self.sigma_theta = std_theta
        self.mu_A = mu_amplitude_theta
        self.mu_B = mu_background_theta
        self.waveform = W

        #compute F for a large domain not to have to deal with periodicity
        F_temp = np.hstack((self.F,self.F,self.F))
        F_temp = np.vstack((F_temp, F_temp, F_temp))
        dom_theta = np.linspace(-2*np.pi,4*np.pi, 3*self.F.shape[0],
                                endpoint = False)
        dom_phi = np.linspace(-2*np.pi,4*np.pi, 3*self.F.shape[1],
                                endpoint = False)
        self.F_func = interpolate.interp2d(dom_theta, dom_phi, F_temp.T,
                                           kind='cubic', bounds_error= True)
        #interpolate waveform
        waveform_temp = self.waveform + self.waveform[0]
        dom_w = np.linspace(0,2*np.pi, len(waveform_temp), endpoint = True)
        self.waveform_func = interpolate.interp1d(dom_w, waveform_temp)

        self.cell = cell
        self.temperature = temperature
        #smooth the function with Fourier approximation (DOESNT WORK FOR NOW)
        self.fourier= False

        if upfolder:
            self.upfolder ='../'
        else:
            self.upfolder =''

    def simulate(self, tf=80, full_simulation = True, rand = True):
        """
        Simulate a deterministic trace, for a given time.

        Parameters
        ----------
        tf : int
            Simulation length.
        full_simulation : bool
            Simulate only the phase (False) or the full system (True).
        rand : bool
            Random initial condition (True) or not (False).

        Returns
        -------
        An array for the time domain and a ndarray for the simulated variables.
        """

        #define system of ODE
        def system(Y, t):
            theta, phi = Y
            d_theta_dt = 2*np.pi/self.T_theta \
                         + self.F_func(theta%(2*np.pi), phi%(2*np.pi))
            d_phi_dt = 2*np.pi/self.T_phi
            return [d_theta_dt, d_phi_dt]

        def system_full(Y, t):
            theta, phi, A, B = Y
            d_theta_dt = 2*np.pi/self.T_theta \
                        + self.F_func(theta%(2*np.pi), phi%(2*np.pi))
            d_phi_dt = 2*np.pi/self.T_phi
            d_A_dt = -self.gamma_A*(A -self.mu_A )
            d_B_dt = -self.gamma_B*(B -self.mu_B )
            return [d_theta_dt, d_phi_dt, d_A_dt, d_B_dt]

        #define intial condition
        if rand:
            theta_0 = random.random()*2*np.pi
            phi_0 = random.random()*2*np.pi
        else:
            theta_0 = 6.
            phi_0 = 0.
        Y0 = [theta_0, phi_0]
        Y0_full = [theta_0, phi_0, random.random()*2*self.mu_A,
                   random.random()*2*self.mu_B]
        tspan = np.linspace(0, tf, abs(2*tf))

        if full_simulation:
            vect_Y = odeint(system_full, Y0_full, tspan)
        else:
            vect_Y = odeint(system, Y0, tspan)

            ''' COMMENTED SINCE ODEINT WORKS JUST AS WELL
            def system_vode(t, Y):
                Eqs = np.zeros((2))
                Eqs[0] = 2*np.pi/self.T_theta
                        + self.F_func(Y[0]%(2*np.pi), Y[1]%(2*np.pi))
                Eqs[1] = 2*np.pi/self.T_phi
                return Eqs

            ode =  spi.ode(system_vode)

            # BDF method suited to stiff systems of ODEs
            t_step = 0.5
            ode.set_integrator('dopri5',nsteps=500,method='bdf')
            ode.set_initial_value(Y0,0)

            ts = [ode.t]
            ys = [ode.y]

            while ode.successful() and ode.t < tf:
                ode.integrate(ode.t + t_step)
                ts.append(ode.t)
                ys.append(ode.y)

            tspan = np.vstack(ts)
            vect_theta, vect_phi = np.vstack(ys).T
            vect_Y = np.vstack((vect_theta, vect_phi)).T
            '''
        return tspan, vect_Y

    def plot_signal(self, tf = 200, full_simulation = True, save = False):
        """
        Plot a temporal trace.

        Parameters
        ----------
        tf : int
            Simulation length.
        full_simulation : bool
            Simulate only the phase (False) or the full system (True).
        save : bool
            Save plot (True) or not (False).
        """
        tspan, vect_Y = self.simulate(tf, full_simulation)

        l_div =[]
        for t1, t2, phi1, phi2 in zip(tspan[:-1], tspan[1:],
                                      vect_Y[:-1,1],vect_Y[1:,1]):

            if (phi1%(2*np.pi)-phi2%(2*np.pi))>0:
                l_div.append((t1+t2)/2)

        if full_simulation:
            l_signal =  np.exp(vect_Y[:,2]) \
                        *self.waveform_func(vect_Y[:,0]%(2*np.pi))+vect_Y[:,3]
        else:
            l_signal = self.waveform_func(vect_Y[:,0]%(2*np.pi))
        plt.plot(tspan, l_signal)
        for t_div in l_div:
            plt.axvline(t_div)
        plt.xlabel("Time")
        plt.ylabel("Circadian signal")
        if save:
            plt.savefig(self.upfolder+'Results/DetSilico/trace_'+self.cell+'_'
                        +str(self.temperature)+'.pdf')
        plt.show()
        plt.close()

    def plot_trajectory(self ,ti = 0, tf = 80, rand = True, save = False, K = 1,
                        T_phi  = None, full_simulation = False):
        """
        Plot a trace in the phase space.

        Parameters
        ----------
        ti : int
            First recorded point of the simulation.
        tf : int
            Simulation length.
        rand : bool
            Random initial condition (True) or not (False).
        save : bool
            Save plot (True) or not (False).
        K : float
            Couplint strength.
        T_phi : float
            Cell-cycle period.
        full_simulation : bool
            Simulate only the phase (False) or the full system (True).
        Returns
        -------
        A list of list for both the circadian and cell-cycle phases.
        Lists are truncated everytime a boundary of the phase domain is crossed.
        """
        real_coupling_function = copy.copy(self.F)
        real_T_phi = self.T_phi
        self.F = K * real_coupling_function

        F_temp = np.hstack((self.F,self.F,self.F))
        F_temp = np.vstack((F_temp, F_temp, F_temp))
        dom_theta = np.linspace(-2*np.pi,4*np.pi, 3*self.F.shape[0],
                                endpoint = False)
        dom_phi = np.linspace(-2*np.pi,4*np.pi, 3*self.F.shape[1],
                                endpoint = False)
        self.F_func = interpolate.interp2d(dom_theta, dom_phi, F_temp.T,
                                           kind='cubic', bounds_error= True)

        if T_phi is not None:
            self.T_phi = T_phi

        tspan, vect_Y = self.simulate(tf, full_simulation = full_simulation,
                                      rand = rand)
        tspan = tspan[ti:]
        vect_Y = vect_Y[ti:]
        l_phase_theta_flat =  vect_Y[:,0]%(2*np.pi)
        l_phase_phi_flat =  vect_Y[:,1]%(2*np.pi)

        #cut trace so that each time a boundary is crossed it creates a new plot
        ll_phase_theta=[]
        ll_phase_phi=[]
        l_phase_theta=[]
        l_phase_phi=[]
        for theta2, phi2, theta1, phi1 in zip(l_phase_theta_flat[1:],
                                              l_phase_phi_flat[1:],
                                              l_phase_theta_flat[:-1],
                                              l_phase_phi_flat[:-1]):
            l_phase_theta.append(theta1)
            l_phase_phi.append(phi1)
            if abs(theta2-theta1)>np.pi or abs(phi2-phi1)>np.pi:
                ll_phase_theta.append(np.array(l_phase_theta))
                ll_phase_phi.append(np.array(l_phase_phi))
                l_phase_theta=[]
                l_phase_phi=[]
        ll_phase_theta.append(np.array(l_phase_theta))
        ll_phase_phi.append(np.array(l_phase_phi))

        #plot
        plt.figure(figsize=(5,5))
        for l_phase_theta, l_phase_phi in zip(ll_phase_theta,ll_phase_phi):
            plt.plot(l_phase_theta[:-1], l_phase_phi[:-1], lw = 2,
                     color = 'lightblue')
        plt.xlim(10**-2,2*np.pi-10**-2)
        plt.ylim(10**-2,2*np.pi-10**-2)
        if T_phi is None:
            plt.xlabel("Circadian phase")
            plt.ylabel("Cell-cycle phase")
        else:
            if T_phi>=30:
                plt.xlabel("Circadian phase")

            if (T_phi-14)%4==0:
                plt.ylabel("Cell-cycle phase")
        if save:
            plt.savefig(self.upfolder+'Results/DetSilico/trajectory_'
                        +self.cell+'_'+str(self.temperature)+'_' + str(K)
                        +'_' + str(T_phi)+ '.pdf')
        #plt.show()
        plt.close()

        self.F = real_coupling_function
        F_temp = np.hstack((self.F,self.F,self.F))
        F_temp = np.vstack((F_temp, F_temp, F_temp))
        self.F_func = interpolate.interp2d(dom_theta, dom_phi, F_temp.T,
                                           kind='cubic', bounds_error= True)
        self.T_phi = real_T_phi

        return ll_phase_theta, ll_phase_phi

    def plot_vectorfield(self, save = True):
        """
        Plot vectofield in the phase space.

        Parameters
        ----------
        save : bool
            Save plot (True) or not (False).
        """

        X = np.linspace(0,2*np.pi,self.F.shape[0], endpoint = False)
        Y = np.linspace(0,2*np.pi,self.F.shape[1], endpoint = False)

        U = 2*np.pi/self.T_theta + self.F.T
        V = np.empty((self.F.shape[0], self.F.shape[1]))
        V.fill(2*np.pi/self.T_phi)

        fig0, ax0 = plt.subplots()
        strm = ax0.streamplot(X, Y, U, V, color=U, linewidth=1.5,
                              cmap='coolwarm')
        cbar = fig0.colorbar(strm.lines)
        ax0.axis([0, 2*np.pi, 0, 2*np.pi])
        plt.xlabel("Circadian phase")
        plt.ylabel("Cell-cycle phase")
        #plt.title("Speed vectorfield")
        cbar.set_label('Circadian speed')

        #fig1, (ax1, ax2) = plt.subplots(ncols=2)
        #ax1.streamplot(X, Y, U, V, density=[0.5, 1])
        #speed = np.sqrt(U*U + V*V)
        #lw = 5*speed / speed.max()
        #ax2.streamplot(X, Y, U, V, density=0.6, color='k', linewidth=lw)

        if save:
            plt.savefig(self.upfolder+'Results/DetSilico/vectorfield_'
                        +self.cell+'_'+str(self.temperature)+'.pdf')
        plt.show()

    def plot_vectorfield_bis(self, T_phi, save = True):
        """
        Plot vectofield in the phase space (version 2).

        Parameters
        ----------
        T_phi : float
            Cell-cycle period.
        save : bool
            Save plot (True) or not (False).
        """
        F_temp = np.hstack((self.F,self.F,self.F))
        F_temp = np.vstack((F_temp, F_temp, F_temp))
        F_temp = F_temp[48:48+48+1,48:48+48+1]

        X = np.linspace(0,2*np.pi,F_temp.shape[0], endpoint = True)
        Y = np.linspace(0,2*np.pi,F_temp.shape[1], endpoint = True)

        U = 2*np.pi/self.T_theta + F_temp.T
        V = np.empty((F_temp.shape[0], F_temp.shape[1]))
        V.fill(2*np.pi/T_phi)

        #sample to reduce the number of arrows
        l_idx_x = [x for x in range(0,F_temp.shape[0],5)]
        l_idx_y = [x for x in range(0,F_temp.shape[1],5)]
        X = X[l_idx_x]
        Y = Y[l_idx_y]
        U = [u[l_idx_y] for u in U[l_idx_x]]
        V = [v[l_idx_y] for v in V[l_idx_x]]
        C = [c[l_idx_y] for c in F_temp.T[l_idx_x]]

        #get attractor
        ll_phase_theta, ll_phase_phi = self.plot_trajectory(ti = 5000,
                                                        tf = 5100,
                                                        rand = True,
                                                        save = False,
                                                        K = 1,
                                                        T_phi  = T_phi)
        #get repeller
        ll_phase_theta_rep, ll_phase_phi_rep = self.plot_trajectory(ti = 5000,
                                                        tf = -5100,
                                                        rand = True,
                                                        save = False,
                                                        K = 1,
                                                        T_phi  = T_phi,
                                                        full_simulation = True)

        #hide the grid
        sn.set_style("whitegrid",
                    {'grid.color': 'white',  'xtick.direction': 'out',
                    'xtick.major.size': 6.0, 'xtick.minor.size': 3.0,
                    'ytick.color': '.15', 'ytick.direction': 'out',
                    'ytick.major.size': 6.0, 'ytick.minor.size': 3.0})

        #plot
        grb, ax1 = plt.subplots(figsize=(5,5))

        #ax1.grid(b=False)
        #ax1.set_axis_bgcolor('white')

        #plot vectorfield
        #ax1.quiver(np.array(X)/(2*np.pi), np.array(Y)/(2*np.pi), U, V,
                    #C, alpha=.5, cmap = 'coolwarm')
        ax1.quiver(np.array(X)/(2*np.pi), np.array(Y)/(2*np.pi), U, V,
                    color = 'blue', alpha = 0.7)
                    #edgecolor='k', facecolor='None', linewidth=.1)

        #plot attractor
        for l_phase_theta, l_phase_phi in zip(ll_phase_theta,ll_phase_phi):
            ax1.plot(np.array(l_phase_theta)/(2*np.pi),
                    np.array(l_phase_phi)/(2*np.pi),
                    lw = 2, color = 'green', alpha = 0.1)

        #plot repeller
        for l_phase_theta_rep, l_phase_phi_rep in zip(ll_phase_theta_rep,
                                                      ll_phase_phi_rep):
            ax1.plot(np.array(l_phase_theta_rep)/(2*np.pi),
                    np.array(l_phase_phi_rep)/(2*np.pi),
                    lw = 2, color = 'red', alpha = 0.1)

        plt.xlabel(r'Circadian phase $\theta$')
        plt.ylabel(r'Cell-cycle phase $\phi$')
        '''
        plt.plot([0,1],[0.22,0.22], '--', color = 'grey')
        plt.text(x = 0.45, y = 0.14, s='G1', color = 'grey', fontsize=12)
        plt.text(x = 0.46, y = 0.27, s='S', color = 'grey', fontsize=12)
        plt.plot([0,1],[0.84,0.84], '--', color = 'grey')
        plt.text(x = 0.05, y = 0.84-0.08, s='S/G2', color = 'grey', fontsize=12)
        plt.text(x = 0.06, y = 0.84+0.05, s='M', color = 'grey', fontsize=12)
        '''
        plt.title(r"$T_{\phi} = $" + str(T_phi ))

        ax1.set_xlim([0.0,1.])
        ax1.set_ylim([0.0,1.])

        if save:
            plt.savefig(self.upfolder+'Results/DetSilico/vectorfield_'
                        +self.cell+'_'+str(self.temperature)+'_'+str(T_phi)
                        +'.pdf')
        plt.show()
        plt.close()

    def anim_vectorfield(self):
        """
        Animate and save the vectofield.
        """
        #hide the grid
        sn.set_style("whitegrid",
                    {'grid.color': 'white',  'xtick.direction': 'out',
                    'xtick.major.size': 6.0, 'xtick.minor.size': 3.0,
                    'ytick.color': '.15', 'ytick.direction': 'out',
                    'ytick.major.size': 6.0, 'ytick.minor.size': 3.0})

        F_temp = np.hstack((self.F,self.F,self.F))
        F_temp = np.vstack((F_temp, F_temp, F_temp))
        F_temp = F_temp[48:48+48+1,48:48+48+1]
        X = np.linspace(0,2*np.pi,F_temp.shape[0], endpoint = True)
        Y = np.linspace(0,2*np.pi,F_temp.shape[1], endpoint = True)

        #sample to reduce the number of arrows
        l_idx_x = [x for x in range(0,F_temp.shape[0],5)]
        l_idx_y = [x for x in range(0,F_temp.shape[1],5)]
        X = X[l_idx_x]
        Y = Y[l_idx_y]

        l_period = np.arange(8,48,0.05)

        def init_quiver():
            global Q
            global lines
            T_phi = l_period[0]
            U = 2*np.pi/self.T_theta + F_temp.T
            V = np.empty((F_temp.shape[0], F_temp.shape[1]))
            V.fill(2*np.pi/T_phi)
            U = np.array([u[l_idx_y] for u in U[l_idx_x]])
            V = np.array([v[l_idx_y] for v in V[l_idx_x]])
            C = [c[l_idx_y] for c in F_temp.T[l_idx_x]]

            Q = ax.quiver(np.array(X)/(2*np.pi), np.array(Y)/(2*np.pi),
                          U/np.sqrt(U**2+V**2), V/np.sqrt(U**2+V**2),
                          color = 'blue', alpha = 0.7)

            #get attractor
            ll_phase_theta, ll_phase_phi = self.plot_trajectory( ti = 5000,
                                                tf = 5100, rand = True,
                                                save = False, K = 1,
                                                T_phi  = T_phi)
            #get repeller
            ll_phase_theta_rep, ll_phase_phi_rep = self.plot_trajectory( \
                                                ti = 5000, tf = -5100,
                                                rand = True, save = False,
                                                K = 1, T_phi  = T_phi,
                                                full_simulation = True)

            lines = []
            #plot attractor
            for l_phase_theta, l_phase_phi in zip(ll_phase_theta,ll_phase_phi):
                lines.append(ax.plot(np.array(l_phase_theta)/(2*np.pi),
                            np.array(l_phase_phi)/(2*np.pi),
                            lw = 2, color = 'green', alpha = 0.1)[0])

            #plot repeller
            for l_phase_theta_rep, l_phase_phi_rep in zip(ll_phase_theta_rep,
                                                          ll_phase_phi_rep):
                lines.append(ax.plot(np.array(l_phase_theta_rep)/(2*np.pi),
                                     np.array(l_phase_phi_rep)/(2*np.pi),
                                     lw = 2, color = 'red', alpha = 0.1)[0])

            ax.set_title(r"$T_{\phi} = $" + str(T_phi )[:4])
            ax.set_xlabel(r'Circadian phase $\theta$')
            ax.set_ylabel(r'Cell-cycle phase $\phi$')
            ax.set_xlim([0.0,1.])
            ax.set_ylim([0.0,1.])

            return  Q, lines

        def update_quiver(i, ax, fig):
            for line in lines:
                line.set_data([],[])
            #global lines
            lines = []
            T_phi = l_period[i]
            V = np.empty((F_temp.shape[0], F_temp.shape[1]))
            V.fill(2*np.pi/T_phi)
            V = np.array([v[l_idx_y] for v in V[l_idx_x]])
            U = 2*np.pi/self.T_theta + F_temp.T
            U = np.array([u[l_idx_y] for u in U[l_idx_x]])
            Q.set_UVC( U/np.sqrt(U**2+V**2), V/np.sqrt(U**2+V**2))

            #get attractor
            ll_phase_theta, ll_phase_phi = self.plot_trajectory( ti = 1000,
                                                        tf = 1100, rand = True,
                                                        save = False, K = 1,
                                                        T_phi  = T_phi)
            #get repeller
            ll_phase_theta_rep, ll_phase_phi_rep = self.plot_trajectory( \
                                                        ti = 1000, tf = -1100,
                                                        rand = True,
                                                        save = False, K = 1,
                                                        T_phi  = T_phi,
                                                        full_simulation = True)

            #plot attractor
            for l_phase_theta, l_phase_phi in zip(ll_phase_theta,ll_phase_phi):
                lines.append(ax.plot(np.array(l_phase_theta)/(2*np.pi),
                                     np.array(l_phase_phi)/(2*np.pi),
                                     lw = 2, color = 'green', alpha = 0.1)[0])

            #plot repeller
            for l_phase_theta_rep, l_phase_phi_rep in zip(ll_phase_theta_rep,
                                                          ll_phase_phi_rep):
                lines.append(ax.plot(np.array(l_phase_theta_rep)/(2*np.pi),
                                     np.array(l_phase_phi_rep)/(2*np.pi),
                                     lw = 2, color = 'red', alpha = 0.1)[0])

            ax.set_title(r"$T_{\phi} = $" + str(T_phi )[:4])
            return Q, lines

        fig =plt.figure(figsize=(5,5))
        ax = fig.gca()
        #ax.set_title('$t$ = '+ str(t[0]))
        #ax.set_xlabel('$x$')
        #ax.set_ylabel('$y$')

        ani = animation.FuncAnimation(fig, update_quiver,
                                      frames = range(len(l_period)),
                                      init_func=init_quiver,
                                      interval=1,fargs=(ax, fig))

        ani.save(self.upfolder+'Results/DetSilico/vectorfield_'+self.cell+'_'
                 +str(self.temperature)+'.mp4',
                 fps=30, extra_args=['-vcodec', 'libx264'], dpi=600)
        #plt.show()

    def return_period(self, tspan, vect_Y, period_to_remove = 0):
        """
        Return the list of period of a given simulated trace.

        Parameters
        ----------
        tspan : list or array
            Time domain.
        vect_Y : array
            Vector returned by a simulation.
        period_to_remove : int
            Number of periods to remove (to ignore non-steady state)

        Returns
        -------
        A list of periods for a given simulated trace
        """

        l_T = []
        theta0 = vect_Y[0,0]%(2*np.pi)
        for t1, t2, theta1, theta2 in zip(tspan[:-1], tspan[1:],
                                          vect_Y[:-1,0], vect_Y[1:,0]):
            cond1 = (theta1%(2*np.pi)-theta0<0 and theta2%(2*np.pi)-theta0>=0)
            if cond1 and t1>0 and theta2-theta1>0:
                if (t1+t2)/2 - np.sum(l_T)>4 and (t1+t2)/2 - np.sum(l_T)<70:
                    l_T.append( (t1+t2)/2 - np.sum(l_T) )
        #print("periods", l_T)
        for i in range(period_to_remove):
            try:
                del l_T[0]
            except:
                print("Not enough simulation time to remove that many periods")
        return l_T

    def plot_sync_tongues(self, NK, NT, N, tf = 100):
        """
        Plot approximate version of the Arnold tongues

        Parameters
        ----------
        NK : list or array
            Strength domain.
        NT : list or array
            Time domain.
        N : int
            Number of simulated traces.
        tf : int
            Simulation length.
        """
        ll_arnold = np.zeros((NT, NK))
        #explore all possible coupling strength
        real_coupling_function = copy.copy(self.F)
        period_space = np.linspace(5,50,NT)
        coupling_space = np.linspace(0,2, NK)
        for iK, K in enumerate(coupling_space):
            self.F = K * real_coupling_function
            F_temp = np.hstack((self.F,self.F,self.F))
            F_temp = np.vstack((F_temp, F_temp, F_temp))
            dom_theta = np.linspace(-2*np.pi,4*np.pi, 3*self.F.shape[0],
                                    endpoint = False)
            dom_phi = np.linspace(-2*np.pi,4*np.pi, 3*self.F.shape[1],
                                    endpoint = False)
            self.F_func = interpolate.interp2d(dom_theta, dom_phi, F_temp.T,
                                               kind='cubic', bounds_error= True)

            #explore all possible cell-cycle periods
            for iT, T_phi in enumerate(period_space):
                self.T_phi = T_phi
                #generate uniform traces on the plan
                l_T = []
                #print("K, T_phi", K, T_phi)
                for i in range(N):
                    tspan, vect_Y = self.simulate(tf, False)
                    l_T.extend(self.return_period(tspan, vect_Y, 2))
                diff = T_phi - np.mean(l_T)
                ll_arnold[iT,iK] = abs(diff)

        #plt.pcolormesh(F.T, cmap='bwr', vmin=-0.6, vmax=0.6)
        plt.pcolormesh(period_space, coupling_space, ll_arnold.T,
                       cmap = 'binary', vmin = 0, vmax = 3)
        plt.colorbar()
        plt.xlabel("T cell cycle")
        plt.ylabel("K")
        plt.savefig(self.upfolder+'Results/DetSilico/sync_tongue_'+self.cell+'_'
                    +str(self.temperature)+'.pdf')
        plt.show()
        plt.close()

        self.F = real_coupling_function
        F_temp = np.hstack((self.F,self.F,self.F))
        F_temp = np.vstack((F_temp, F_temp, F_temp))
        self.F_func = interpolate.interp2d(dom_theta, dom_phi, F_temp.T,
                                           kind='cubic', bounds_error= True)

    def plot_devil_staircase(self, l_arg):
        """
        Plot Devil staircase and return average circadian speed for a given
        cell-cycle period list.

        Parameters
        ----------
        l_arg : list
            Arguments used by the function (used for multiprocessing):
            speed_space : Speed/frequency domain (array)
            coupling_strength : Coupling strength used for simulation (float)
            tf : Simulation length (int)
            random_init : Random initial condition (bool)
        """
        #print('new staircase')
        (speed_space, coupling_strength, tf, random_init) = l_arg
        print("K = " + str(coupling_strength))
        if self.fourier:
            dom1 = np.linspace(0,2*np.pi, self.F.shape[0], endpoint = False)
            dom2 = np.linspace(0,2*np.pi, self.F.shape[1], endpoint = False)
            Fp = interpolate.interp2d(dom1, dom2 , self.F)
            dom_theta = np.linspace(0,2*np.pi, N_theta, endpoint = False)
            Fp = Fp(dom_theta, dom_theta)
            F_t = np.fft.rfft2(Fp)
            F_mag = np.abs(np.fft.fftshift(F_t))
            F_phase = np.angle(np.fft.fftshift(F_t))
            F_t = np.fft.fftshift(F_t)

            tenth = np.percentile( F_mag.flatten(), 50)
            ll_idx_coef = [(i,j) for i in range(F_mag.shape[0]) \
                            for j in range(F_mag.shape[1]) if F_mag[i,j]<tenth]
            print("remaining coef:" ,
                  F_mag.shape[0]*F_mag.shape[1]-len(ll_idx_coef))

            for (i,j) in ll_idx_coef:
                F_t[i,j] = 0
                F_mag[i,j] = 0
                F_phase[i,j] = 0
            F_t = np.fft.ifftshift(F_t)
            def func(grid_phase):
                return np.fft.irfft2( grid_phase )
            self.F_func = func

        else:
            real_coupling_function = copy.copy(self.F)
            real_T_phi = self.T_phi
            self.F = self.F * coupling_strength
            print(self.F[0,10])
            F_temp = np.hstack((self.F,self.F,self.F))
            F_temp = np.vstack((F_temp, F_temp, F_temp))
            dom_theta = np.linspace(-2*np.pi,4*np.pi, 3*self.F.shape[0],
                                    endpoint = False)
            dom_phi = np.linspace(-2*np.pi,4*np.pi, 3*self.F.shape[1],
                                    endpoint = False)
            self.F_func = interpolate.interp2d(dom_theta, dom_phi, F_temp.T,
                                               kind='cubic', bounds_error= True)

        l_wm = []
        #explore all possible cell-cycle periods
        new_method = True
        for iw, w_phi in enumerate(speed_space):
            self.T_phi = 2*np.pi/w_phi
            tspan, vect_Y = self.simulate(tf, False, rand = random_init)
            if not new_method:
                try:
                    l_wm.append( w_phi-(vect_Y[-1,0]\
                                            -vect_Y[-int(tf/4),0])/(tf/4/2) )

                except:
                    print("point ", w_phi, "with strength ",
                          coupling_strength, " was ignored")
                    l_wm.append(np.nan)
            else:
                #first interpolate time
                real_tf = (len(vect_Y[:,0])-1)*0.5
                dom_interp = np.linspace(0,(len(vect_Y[:,0])-1)*0.5,
                                            len(vect_Y[:,0]), endpoint = True)
                func = interpolate.interp1d(vect_Y[:,0],
                                            dom_interp , kind='linear')
                real_ti = func(vect_Y[-1,0]-8*np.pi)
                wm = (8*np.pi)/(real_tf-real_ti)
                #check if wm is very close to a quotient of integers:
                done = False
                best_k = -1
                val_min = 100
                l_ratio = [1,2,1/2,2/3,3/2,1/3,3,1/4,3/4,5/4, 4/3, 4/5, 7/4,
                           9/4, 4/7, 4/9]
                for k in l_ratio:
                    #if (abs(k*w_phi-wm))<10**-4:
                    #    w_final = 0
                    #    done = True
                    #    break
                    #else:
                    if abs(k*w_phi-wm)<val_min:
                        val_min = abs(k*w_phi-wm)
                        best_k = k
                if not done:
                    w_final = wm
                    #w_final = val_min
                l_wm.append(w_final)
            ''' OLD VERSION
            l_phase_theta_flat =  vect_Y[:,0]%(2*np.pi)
            l_phase_phi_flat =  vect_Y[:,1]%(2*np.pi)

            #cut traces so that when a boundary is crossed it creates a new plot
            ll_phase_theta=[]
            ll_phase_phi=[]
            l_phase_theta=[]
            l_phase_phi=[]
            for theta2, phi2, theta1, phi1 in zip(l_phase_theta_flat[1:],
                                                  l_phase_phi_flat[1:],
                                                  l_phase_theta_flat[:-1],
                                                  l_phase_phi_flat[:-1]):
                l_phase_theta.append(theta1)
                l_phase_phi.append(phi1)
                if abs(theta2-theta1)>np.pi or abs(phi2-phi1)>np.pi:
                    ll_phase_theta.append(np.array(l_phase_theta))
                    ll_phase_phi.append(np.array(l_phase_phi))
                    l_phase_theta=[]
                    l_phase_phi=[]
            ll_phase_theta.append(np.array(l_phase_theta))
            ll_phase_phi.append(np.array(l_phase_phi))

            #plot
            plt.figure(figsize=(5,5))
            for l_phase_theta, l_phase_phi in zip(ll_phase_theta,ll_phase_phi):
                plt.plot(l_phase_theta[:-1], l_phase_phi[:-1], lw = 2,
                         color = 'lightblue')
                #plt.quiver(l_phase_theta[:-1], l_phase_phi[:-1],
                            -(l_phase_theta[1:]-l_phase_theta[:-1]),
                            -(l_phase_phi[1:]-l_phase_phi[:-1]),
                            scale = 5)#, scale_units='xy', angles='xy', scale=1)

            plt.xlim(10**-2,2*np.pi-10**-2)
            plt.ylim(10**-2,2*np.pi-10**-2)
            plt.show()
            plt.close()
            '''

        if not self.fourier:
            self.F = real_coupling_function
            F_temp = np.hstack((self.F,self.F,self.F))
            F_temp = np.vstack((F_temp, F_temp, F_temp))
            dom_theta = np.linspace(-2*np.pi,4*np.pi, 3*self.F.shape[0],
                                    endpoint = False)
            dom_phi = np.linspace(-2*np.pi,4*np.pi, 3*self.F.shape[1],
                                    endpoint = False)
            self.F_func = interpolate.interp2d(dom_theta, dom_phi, F_temp.T,
                                               kind='cubic', bounds_error= True)
        self.T_phi = real_T_phi
        """
        for j in range(1,len(l_wm)-1):
            if (abs(l_wm[j]-l_wm[j-1]) + abs(l_wm[j]-l_wm[j+1])) > 0.2 :
                l_wm[j] = (l_wm[j+1]+l_wm[j-1])/2
        """

        #hide the grid
        sn.set_style("whitegrid",
                    {'grid.color': 'white',  'xtick.direction': 'out',
                    'xtick.major.size': 6.0, 'xtick.minor.size': 3.0,
                    'ytick.color': '.15', 'ytick.direction': 'out',
                    'ytick.major.size': 6.0, 'ytick.minor.size': 3.0})
        #matplotlib.style.use('ggplot')
        #plt.rcParams['axes.facecolor']='white'
        plt.figure(figsize=(5,5))
        plt.plot(speed_space, l_wm, '.', color = 'blue', markersize = 5)
        plt.plot([0,100],[0,100], '--', color = 'grey', alpha = 0.5)
        plt.plot([0,100],[0,200], '--', color = 'grey', alpha = 0.5)
        #plt.plot([0,100],[0,300], '--', color = 'grey', alpha = 0.5)
        plt.plot([0,200],[0,100], '--', color = 'grey', alpha = 0.5)
        plt.plot([0,300],[0,100], '--', color = 'grey', alpha = 0.5)
        #plt.plot([0,200],[0,300], '--', color = 'grey', alpha = 0.5)
        #plt.plot([0,300],[0,200], '--', color = 'grey', alpha = 0.5)
        plt.plot([0,300],[0,400], '--', color = 'grey', alpha = 0.5)

        plt.text(0.345,0.335,'1:1', color = 'grey')
        plt.text(0.175,0.335,'1:2', color = 'grey')
        plt.text(0.68,0.335,'2:1', color = 'grey')
        plt.text(0.735,0.24, '3:1', color = 'grey')
        plt.text(0.26,0.335, '3:4', color = 'grey')
        #plt.text(0.22,0.32,'2:3', color = 'grey')
        #plt.text(0.48,0.32,'3:2', color = 'grey')

        plt.xlabel(r'$\omega_{\phi}$')
        plt.ylabel(r'<$\omega_{\theta}$>')
        plt.xlim([0.1,0.8])
        plt.ylim([0.22,0.34])
        plt.tight_layout()
        #plt.show()
        plt.savefig(self.upfolder+'Results/DetSilico/devil_'+self.cell+'_'
                    +str(self.temperature)+'.pdf')
        plt.close()
        return l_wm

    def plot_arnold_tongues(self, NK, NW, tf = 400, random_init = False):
        """
        Plot and save the Arnold tongues.

        Parameters
        ----------
        NK : list or array
            Strength domain.
        NT : list or array
            Time domain.
        tf : int
            Simulation length.
        random init : bool
            Random initial condition.
        """
        ll_arnold = np.zeros((NW-1, NK))
        ll_arnold_test = np.zeros((NW-1, NK))
        ll_arnold_bis = np.zeros((NW, NK))

        #explore all possible coupling strength
        speed_space = np.linspace(2*np.pi/(2.5*24), 2*np.pi/(24/3), NW)
        #speed_space = np.linspace(2*np.pi/(1*24), 2*np.pi/(24/2.5), NW)
        period_space = list(reversed(2*np.pi/speed_space))
        coupling_space = np.linspace(0.,2., NK)
        #coupling_space = np.linspace(1.,2., NK)
        if random_init:
            n_rand = 5
        else:
            n_rand = 1

        l_arg = [(speed_space, K,  tf, True) for idx_rand in range(n_rand)\
                 for iK, K in enumerate(coupling_space)]
        n_cpu = 2
        original_sigint_handler = signal.signal(signal.SIGINT, signal.SIG_IGN)
        signal.signal(signal.SIGINT, original_sigint_handler)
        pool = Pool(n_cpu)
        try:
            #results = pool.map(self.plot_devil_staircase, l_arg)
            results = list(map(self.plot_devil_staircase, l_arg))
        except:
            print("BUG")
            pool.terminate()
        else:
            print("Normal termination")

        pool.close()
        pool.join()
        idx_mp = 0

        for idx_rand in range(n_rand):
            for iK, K in enumerate(coupling_space):
                l_wm = np.array(results[idx_mp])
                idx_mp+=1

                dspeed = np.absolute(l_wm[1:]-l_wm[:-1])
                dt2 = (speed_space[1]-speed_space[0])
                ll_arnold[:,iK] +=  list(reversed(dspeed/dt2))
                ll_arnold_bis[:,iK] += list(reversed(l_wm))

        test = np.reshape(results, (n_rand,
                          len(coupling_space),len(speed_space)))
        var_test = np.var(test,axis=0)

        ll_arnold[:,iK] = ll_arnold[:,iK]/n_rand
        ll_arnold_bis[:,iK] = ll_arnold_bis[:,iK]/n_rand

        plt.pcolormesh(period_space[:-1], coupling_space, ll_arnold.T,
                       cmap = 'binary', vmin = 0, vmax = 10**-2)
        plt.colorbar()
        plt.xlim([period_space[0], period_space[-2]])
        plt.xlabel(r"$T_{\phi}$")
        plt.ylabel("K")
        plt.savefig(self.upfolder+'Results/DetSilico/arnold_'+self.cell+'_'
                    +str(self.temperature)+'.pdf')
        plt.show()
        plt.close()

        plt.pcolormesh(period_space, coupling_space, ll_arnold_bis.T,
                       cmap = 'plasma')#, vmin = 0, vmax = 0.2)
        plt.colorbar()
        plt.xlabel(r"$T_{\phi}$")
        plt.ylabel("K")
        plt.savefig(self.upfolder+'Results/DetSilico/arnold_bis_'+self.cell+'_'
                    +str(self.temperature)+'.pdf')
        plt.show()
        plt.close()

        plt.pcolormesh(period_space, coupling_space, var_test, cmap = 'binary')
        plt.colorbar()
        plt.xlabel(r"$T_{\phi}$")
        plt.ylabel("K")
        plt.savefig(self.upfolder+'Results/DetSilico/arnold_bis2_'+self.cell+'_'
                    +str(self.temperature)+'.pdf')
        plt.show()
        plt.close()

        pickle.dump(ll_arnold.T, open(self.upfolder+"Results/DetSilico/arnold_"
                                      +self.cell+'_'+str(self.temperature)+".p",
                                       "wb"))
        pickle.dump(ll_arnold_bis.T, open( self.upfolder
                                      +"Results/DetSilico/arnold_bis_"
                                      +self.cell+'_'+str(self.temperature)+".p",
                                       "wb"))
        pickle.dump(var_test, open( self.upfolder
                                    +"Results/DetSilico/arnold_bis2_"+self.cell
                                    +'_'+str(self.temperature)+".p", "wb"))
        return period_space, speed_space, coupling_space

    def refine_arnold_tongues(self, period_space, speed_space, coupling_space):
        """
        Load, refine and plot Arnold tongues from existing plot.
        """
        ll_arnold =  pickle.load(open(self.upfolder+"Results/DetSilico/arnold_"
                                      +self.cell+'_'+str(self.temperature)+".p",
                                      "rb" ) )
        var_test = pickle.load(open (self.upfolder
                                      +"Results/DetSilico/arnold_bis2_"
                                      +self.cell+'_'+str(self.temperature)+".p",
                                       "rb" ) )

        #ll_arnold = ll_arnold[-50:,-50:]

        #data1= griddata( (period_space[-50:], coupling_space[-50:]),
                            #ll_arnold, (xnew, ynew))
        #f = interp2d(period_space[:-1], coupling_space, ll_arnold,
            #kind='linear')
        #f = RectBivariateSpline(period_space[-50:], coupling_space[-50:],
                            #ll_arnold, s= 10)

        #Xn, Yn = np.meshgrid(period_space[-50:], coupling_space[-50:])
        #f = Rbf(Xn, Yn, ll_arnold)
        #xnew = np.linspace(period_space[0], period_space[-2], 1000)
        #ynew = np.linspace(coupling_space[0], coupling_space[-1], 1000)
        #Xn, Yn = np.meshgrid(xnew, ynew)
        #data1 = f(xnew,ynew)

        #plt.pcolormesh(xnew, ynew, data1, cmap = 'binary', vmin = 0, vmax = 5,
                        #shading='gouraud')

        plt.pcolormesh(period_space[:-1], coupling_space, ll_arnold,
                        cmap = 'binary', vmin = 0, vmax = 2, shading='gouraud')
        #plt.imshow(ll_arnold, cmap = 'binary', vmin = 0, vmax =5 ,
                    #origin='lower', extent=[period_space[0],period_space[-2],
                    #coupling_space[0],coupling_space[-1]], aspect='auto')
        plt.colorbar()
        plt.xlim([period_space[0], period_space[-2]])
        plt.xlabel(r"$T_{\phi}:T_{\theta}$")
        plt.ylabel("K")
        locs, labels = plt.xticks()
        plt.xticks([12,2/3*24, 24, 24*4/3, 48],
                   ['2:1', '3:2','1:1', '3:4', '1:2'])
        plt.savefig(self.upfolder+'Results/DetSilico/arnold_'+self.cell+'_'
                    +str(self.temperature)+'.pdf')
        plt.show()
        plt.close()

        plt.figure(figsize=(5,5))
        plt.pcolormesh(period_space, coupling_space, var_test[:,::-1],
                       cmap = 'binary', vmin = 0, vmax = 10**-8,
                       shading='gouraud')
        #plt.imshow(ll_arnold_bis.T, cmap = 'plasma', origin='lower',
                    #extent=[speed_space[0],speed_space[-2],coupling_space[0],
                    #coupling_space[-1]], aspect='auto')
        plt.xlim([period_space[0], period_space[-1]])
        #plt.colorbar()
        plt.xlabel(r"$T_{\phi}:T_{\theta}$")
        plt.ylabel("K")
        locs, labels = plt.xticks()
        plt.xticks([12,2/3*24, 24, 24*4/3, 48],
                   ['2:1', '3:2','1:1', '3:4', '1:2'])
        plt.tight_layout()
        plt.savefig(self.upfolder+'Results/DetSilico/arnold_bis2_'+self.cell+'_'
                    +str(self.temperature)+'.pdf')
        plt.show()
        plt.close()

    def plot_moving_attractor(self, save = False):
        """
        Plot attractor for evolving cell-cycle period.

        Parameters
        ----------
        save : bool
            Save plot (True) or not (False).
        """
        ll_theta= []
        ll_phi = []
        space_period = list(range(19,28,1))
        for T_phi in space_period:
            l_theta, l_phi = self.plot_trajectory(ti = 2500, tf = 3000,
                                                  rand = True, save = False,
                                                  K = 1, T_phi  = T_phi,
                                                  full_simulation = False)
            ll_theta.append(l_theta)
            ll_phi.append(l_phi)

        #hide the grid
        sn.set_style("whitegrid",
                    {'grid.color': 'white',  'xtick.direction': 'out',
                    'xtick.major.size': 6.0, 'xtick.minor.size': 3.0,
                    'ytick.color': '.15', 'ytick.direction': 'out',
                    'ytick.major.size': 6.0, 'ytick.minor.size': 3.0})

        current_palette = sn.color_palette("Greens", len(space_period)+2)
        fig = plt.figure(figsize=(5,5))
        plt.plot([0,1],[0.00,0.00], '--', color = 'blue', alpha = 0.5)
        plt.text(x = 0.1, y = 0.01, s=r'$\phi = 0$')

        plt.plot([0,1],[0.33,0.33], '--', color = 'red', alpha = 0.5)
        plt.text(x = 0.4, y = 0.34, s=r'$\phi = 2\pi/3$')

        plt.plot([0,1],[0.66,0.66], '--', color = 'green', alpha = 0.5)
        plt.text(x = 0.8, y = 0.67, s=r'$\phi = 4\pi/3$')
        for idx, (l_theta, l_phi) in enumerate(zip(ll_theta, ll_phi)):
            flag = False
            for l_phase_theta, l_phase_phi in zip(l_theta,l_phi):
                if not flag:
                    plt.plot(np.array(l_phase_theta)/(2*np.pi),
                            np.array(l_phase_phi)/(2*np.pi),
                            color = current_palette[idx+2] ,
                            label = r'$T_{\phi}=$' +str(space_period[idx])+'h')
                    flag = True
                else:
                    plt.plot(np.array(l_phase_theta)/(2*np.pi),
                    np.array(l_phase_phi)/(2*np.pi),
                    color = current_palette[idx+2] )

        plt.xlim(0,1)
        plt.ylim(-0.01,1)

        #plt.axhspan(0, 0.34, alpha=0.1, color='red')
        #plt.axhspan(0.34, 0.65, alpha=0.1, color='green')
        #plt.axhspan(0.65, 1, alpha=0.1, color='blue')

        #plt.text(1.2,0.7,r'$\phi = 0$')
        #plt.text(1.2,0.4,r'$\phi = 4\pi/3$')
        #plt.text(1.2,0.1,r'$\phi = 2\pi/3$')

        plt.xlabel(r'Circadian phase $\theta$')
        plt.ylabel(r'Cell-cycle phase $\phi$')

        plt.legend(bbox_to_anchor=(1.04,0.5), loc="center left")
        #plt.tight_layout()

        if not save:
            plt.show()
        else:
            plt.savefig(self.upfolder+'Results/DetSilico/shift_attractor_'
                        +self.cell+'_'
                        +str(self.temperature)+'.pdf', bbox_inches='tight')
        plt.close()

if __name__ == '__main__':
    #load parameters
    with open('../Parameters/Real/opt_parameters_div_None_NIH3T3.p', 'rb') as f:
        l_parameters = [dt, sigma_em_circadian, W, pi,
        N_theta, std_theta, period_theta, l_boundaries_theta, w_theta,
        N_phi, std_phi, period_phi, l_boundaries_phi, w_phi,
        N_amplitude_theta, mu_amplitude_theta, std_amplitude_theta,
        gamma_amplitude_theta, l_boundaries_amplitude_theta,
        N_background_theta, mu_background_theta, std_background_theta,
        gamma_background_theta, l_boundaries_background_theta,
        F] = pickle.load(f)
    detSim = DetSim(l_parameters, 'NIH3T3', None)

    #detSim.plot_signal(tf = 200, full_simulation = True, save = False)
    #detSim.plot_trajectory(ti = 0, tf = 80, rand = True, save = True,
    #                       K = 1, T_phi  = None, full_simulation = False)
    #detSim.plot_vectorfield(save = True)
    #detSim.plot_vectorfield_bis(T_phi = 22, save = True)
    #detSim.anim_vectorfield()
    #detSim.plot_sync_tongues(NK = 4, NT = 10, N = 4, tf = 100)
    #speed_space = np.linspace(2*np.pi/(3*24), 2*np.pi/(24/3), 50)
    #l_arg = (speed_space, 3, 400, True)
    #detSim.plot_devil_staircase(l_arg)
    #t = detSim.plot_arnold_tongues(NK = 4, NW = 50, tf = 200)
    #(period_space, speed_space, coupling_space) = t
    #detSim.refine_arnold_tongues(period_space, speed_space, coupling_space)
    #detSim.plot_moving_attractor(save = True)


from django.shortcuts import render, redirect

from .models import ToDo
from .forms import ToDoForm

# Create your views here.

def all_todo(request):
    form = ToDoForm()
    todos = ToDo.objects.order_by('-date_added')
    return render(request, 'todo/all_todo.html', {'todos': todos, 'form': form})

def add(request):
    if request.method == 'POST':
        td = ToDoForm(request.POST)
        if td.is_valid():
            tdnew = td.save()
    return redirect('todo:all_todo')

def delete_todo(request, todo_id):
    td = ToDo.objects.get(id=todo_id)
    td.delete()
    return redirect('todo:all_todo')

def change_status(request, todo_id):
    td = ToDo.objects.get(id=todo_id)
    td.done = not td.done
    td.save()
    return redirect('todo:all_todo')


# Problem Link: https://www.hackerrank.com/challenges/weighted-uniform-string/problem
from collections import Counter

def weightedUniformStrings(string, queries):
    strArr = list(set(string))
    alphabets = 'abcdefghijklmnopqrstuvwxyz'
    charWeights = []
    for char in strArr:
        count = string.count(char)
        index = alphabets.index(char) + 1
        charWeights += [index * x for x in range(1, count + 1)]

    returnArr = []
    for query in queries:
        if query in charWeights:
            returnArr.append('Yes')
        else:
            returnArr.append('No')
    return returnArr

# Better Solution
def weightedUniformStrings2(string, queries):
    alphabet = 'abcdefghijklmnopqrstuvwxyz'
    weights = dict(zip(alphabet, range(1, 27)))
    found = Counter()

    current_letter = string[0]
    count = 1
    found[weights[current_letter] * count] = True
    for c in string[1:]:
        if c == current_letter:
            count += 1
        else:
            count = 1
            current_letter = c
        found[weights[current_letter] * count] = True

    for q in queries:
        yield "Yes" if found[q] else "No"

string1 = 'abccddde'
query1 = [1, 3, 12, 5, 9, 10]
string2 = 'aaabbbbcccddd'
query2 = [9, 7, 8, 12, 5]
print(weightedUniformStrings(string2, query1))
print(weightedUniformStrings2(string2, query1))
# getArrayWeight(string1)


from django.shortcuts import render

from .models import Name
# Create your views here.

def name(request):

    names = Name.objects.all()

    context = {
            'fullname': names[0].getfullname(),
        }
    return render(request, 'name.html', context=context)


__author__ = "6541262: Ansgar Asseburg"
__copyright__ = "Copyright 2020 – Ansgar Asseburg; " \
                "You may use and copy this document (including changing it) " \
                "for non-commercial and educational purposes" \
                "as long as you leave the author and this copyright " \
                "information in"
__email__ = "s2092795@stud.uni-frankfurt.de"

import json

from formats_and_translations import format_seconds

def conditions_met(metric_dict):
    # check scores for condition
    condition_scores = ['accuracy', 'recall', 'f1-score']
    for condition_score in condition_scores:
        if metric_dict[condition_score] != 1.0:
            return False
    return True

def store_scores_one(dataset_name, metric_name, window_size, metric_dict,
                     target_dict):
    window_size_key = f'Warping Window Size = {window_size}'
    target_dict.setdefault(dataset_name, {})
    target_dict[dataset_name].setdefault(window_size_key, {})
    # remove unwanted entries
    metric_dict = {k: v for (k, v) in metric_dict.items() if
                   k not in ['arguments', 'runtime']}
    target_dict[dataset_name][window_size_key].setdefault(metric_name,
                                                          metric_dict)

def benchmark_runtime(archive):
    with open(archive) as scores_file:
        data = json.load(scores_file)
    datasets = [dataset for dataset in data.keys()]
    metrics = [metric for metric in data[datasets[0]] if metric != 'properties']
    runtime = 0
    for dataset in datasets:
        for metric in metrics:
            runtime += data[dataset][metric]['runtime']
    return runtime

if __name__ == '__main__':

    datasets_with_scores_one = {}

    json_store = './Benchmarks/json/'
    json_score_one_file = 'score_one.json'

    json_files_dict = {
        '1.0': ['UEA_archive_wws--1.json', 'UCR_archive_wws--1.json'],
        '0.3': ['UEA_archive_wws-0-3.json', 'UCR_archive_wws-0-3.json'],
        '0.1': ['UEA_archive_wws-0-1.json', 'UCR_archive_wws-0-1.json']
    }
    wws_list = ['1.0', '0.3', '0.1']

    total_runtime = 0
    for wws in wws_list:
        for json_file in json_files_dict[wws]:
            total_runtime += benchmark_runtime(json_store + json_file)
    print(format_seconds(total_runtime))
    #         with open(json_store + json_file) as scores_file:
    #             dataset_scores = json.load(scores_file)
    #
    #         for dataset in dataset_scores:
    #             metrics = sorted([metric for metric in dataset_scores[dataset]
    #                               if metric != 'properties'])
    #             for metric in metrics:
    #                 metric_dict = dataset_scores[dataset][metric]
    #                 if conditions_met(metric_dict):
    #                     store_scores_one(dataset, metric, wws, metric_dict,
    #                                      datasets_with_scores_one)
    #
    # with open(json_store + json_score_one_file, 'w') as score_one_file:
    #     json.dump(datasets_with_scores_one, score_one_file, indent=6)
    #     score_one_file.flush()


from Redacoes import Redacoes
import requests
from bs4 import BeautifulSoup

class Uol(Redacoes):
  def __init__(self, titulo='', html='', notas=''):
    super().__init__(titulo, html, notas)

  def getLinkDosTemas(self):
    soup = BeautifulSoup(self.getPaginaExistente('https://educacao.uol.com.br/bancoderedacoes/'), 'lxml')
    temas = soup.select('.thumbnails-wrapper > a')
    links_dos_temas = []
    for tema in temas:
      links_dos_temas.append(tema.get('href'))
    return links_dos_temas

  def getPropostas(self, url):
    soup = BeautifulSoup(self.getPaginaExistente(url), 'lxml')
    propostas = soup.select('.rt-line-option > a')
    links_das_propostas = []
    for proposta in propostas:
        links_das_propostas.append(proposta.get('href'))
    return links_das_propostas

  def getRedacao(self, url):
    soup = BeautifulSoup(self.getPaginaExistente(url), 'lxml')
    tema = soup.select('.custom-title')[0].text
    titulo = soup.select('.container-composition > h2')[0].text
    paragrafos_da_redacao = soup.select('.text-composition > P')
    redacao_completa = ''
    for redacao in paragrafos_da_redacao:
        redacao_completa += '{}'.format(redacao)
    notas = soup.select('.points')[:6]
    lista_de_notas = []
    for nota in notas:
        lista_de_notas.append(float(nota.text))
    return [tema.replace("'", "`"), titulo.replace("'", "`"), redacao_completa.replace("'", "`"), lista_de_notas]

  def getTodasAsRedacoes():
    temas = self.getLinkDosTemas()
    lista_de_redacoes = []
    index = 0
    for tema in temas:
        propostas = self.getPropostas(tema)
        for proposta in propostas:
            index += 1
            print(index)
            lista_de_redacoes.append(self.getRedacao(proposta))
    return lista_de_redacoes


import click
import cv2
import os
import torch
import tqdm

from utils import get_test_dataset_function

from detectron2 import model_zoo
from detectron2.data import DatasetCatalog, MetadataCatalog
from detectron2.utils.visualizer import Visualizer
from detectron2.engine import DefaultPredictor
from detectron2.config import get_cfg

def save_labelme_json(image_path, output_path, predictions):
    # Get the image dimensions
    image = cv2.imread(image_path)
    height, width, _ = image.shape

    # Create the JSON dictionary
    json_dict = {
        "version": "4.5.6",
        "flags": {},
        "shapes": [],
        "imagePath": os.path.basename(image_path),
        "imageData": None,
        "imageHeight": height,
        "imageWidth": width
    }

    # Add the shapes
    for prediction in predictions:
        class_name = prediction["class_name"]
        bbox = prediction["bbox"]
        xmin, ymin, xmax, ymax, angle = bbox

        shape_dict = {
            "label": class_name,
            "points": [
                [xmin, ymin],
                [xmax, ymax]
            ],
            "group_id": None,
            "shape_type": "rectangle",
            "flags": {}
        }
        json_dict["shapes"].append(shape_dict)

    # Save the JSON file
    json_path = os.path.join(output_path, os.path.basename(image_path).replace(".jpg", ".json"))
    with open(json_path, "wt") as f:
        json.dump(json_dict, f, indent=2)

    print(f"Saved {json_path}")

def convert_jpgs_to_video(jpg_folder, output_video_path, fps):
    # Get the list of JPG files in the folder
    jpg_files = [f for f in os.listdir(jpg_folder) if (f.endswith('.jpg') or f.endswith('.png'))]

    # Sort the files in ascending order
    jpg_files.sort()

    # Get the first image dimensions
    first_image = cv2.imread(os.path.join(jpg_folder, jpg_files[0]))
    height, width, _ = first_image.shape

    # Initialize the video writer
    fourcc = cv2.VideoWriter_fourcc(*'mp4v')  # Use appropriate codec (e.g., 'XVID', 'MJPG')
    video_writer = cv2.VideoWriter(output_video_path, fourcc, fps, (width, height))

    # Write each image to the video writer
    for jpg_file in jpg_files:
        image_path = os.path.join(jpg_folder, jpg_file)
        image = cv2.imread(image_path)
        video_writer.write(image)

    # Release the video writer
    video_writer.release()

    print("Video created successfully.")

@click.command()
@click.argument('directory', nargs=1)
@click.option('--weights', default="model_final.pth", help='Path to the model to use')
def main(directory, weights):
    class_labels = ['Balls', 'Bottlebrush', 'Branching 3D', 'Colonial', 'Crustaceans', 'Cups', 'Fan 2D', 'Feather stars', 'Hydrocorals', 'Mushroom', 'Other', 'Other anemones', 'Pale', 'Prawns / Shrimps / Mysids', 'Sea cucumbers', 'Sea stars', 'Spider crabs', 'Squat lobsters', 'Stalked', 'Three-dimensional branching', 'True crabs', 'Tube-like forms', 'Two-dimensional lamellate', 'Unbranched', 'Yellow', 'biogenic + sediment', 'biogenic rubble', 'coral rubble', 'lost+found', 'rubble', 'volcanic', 'volcanic + sediment', 'volcanic, sediment + biogenic rubble']

    color_palette = {
        'Balls': (15, 78, 117),
        'Bottlebrush': (48, 170, 121),
        'Branching 3D': (180, 82, 205),
        'Colonial': (211, 54, 130),
        'Crustaceans': (223, 123, 48),
        'Cups': (255, 190, 11),
        'Fan 2D': (38, 186, 133),
        'Feather stars': (97, 60, 123),
        'Hydrocorals': (236, 84, 50),
        'Mushroom': (115, 50, 82),
        'Other': (179, 162, 199),
        'Other anemones': (82, 122, 173),
        'Pale': (242, 184, 149),
        'Prawns / Shrimps / Mysids': (205, 48, 135),
        'Sea cucumbers': (113, 197, 199),
        'Sea stars': (242, 130, 43),
        'Spider crabs': (24, 99, 143),
        'Squat lobsters': (147, 188, 71),
        'Stalked': (245, 209, 66),
        'Three-dimensional branching': (92, 146, 87),
        'True crabs': (211, 65, 36),
        'Tube-like forms': (38, 101, 153),
        'Two-dimensional lamellate': (162, 209, 73),
        'Unbranched': (242, 166, 50),
        'Yellow': (255, 235, 59),
        'biogenic + sediment': (63, 81, 125),
        'biogenic rubble': (194, 205, 230),
        'coral rubble': (147, 178, 204),
        'lost+found': (122, 96, 161),
        'rubble': (206, 152, 232),
        'volcanic': (226, 128, 64),
        'volcanic + sediment': (83, 98, 103),
        'volcanic, sediment + biogenic rubble': (226, 158, 74)
    }

    dataset_name = "dive8file4"

    dataset_function = get_test_dataset_function(directory)
    MetadataCatalog.get(dataset_name).thing_classes = class_labels
    MetadataCatalog.get(dataset_name).thing_colors = {
        i: color_palette[k] for i, k in enumerate(class_labels)
    }

    DatasetCatalog.register(dataset_name, dataset_function)
    metadata = MetadataCatalog.get(dataset_name)

    cfg = get_cfg()
    cfg.merge_from_file(model_zoo.get_config_file(
        "COCO-Detection/faster_rcnn_X_101_32x8d_FPN_3x.yaml"))  # Base model
    # cfg.merge_from_file(model_zoo.get_config_file(
    #     "COCO-Detection/faster_rcnn_R_50_FPN_3x.yaml"))  # Base model

    # Rotated bbox specific config in the same directory as this file
    cfg.merge_from_file(os.path.join(os.path.dirname(
        os.path.abspath(__file__)), "rotated_bbox_config.yaml"))
    cfg.DATASETS.TRAIN = (dataset_name,)
    cfg.DATASETS.TEST = (dataset_name,)
    cfg.MODEL.ROI_HEADS.NUM_CLASSES = len(class_labels)

    cfg.MODEL.WEIGHTS = weights
    cfg.MODEL.ROI_HEADS.SCORE_THRESH_TEST = 0.1  # Preiction confidence threshold,
    cfg.MODEL.ROI_HEADS.NMS_THRESH_TEST = 0.05

    predictor = DefaultPredictor(cfg)
    iteration = torch.load(weights)["iteration"]
    output_dir = os.path.join(directory, "predictions", f"{iteration:06d}")
    os.makedirs(output_dir, exist_ok=True)
    for i, d in enumerate(tqdm.tqdm(dataset_function())):
        img = cv2.imread(d["file_name"])
        outputs = predictor(img)

        # Save predictions in labelme format

        v = Visualizer(img[:, :, ::-1], metadata, scale=1.0)
        out = v.draw_instance_predictions(outputs["instances"].to("cpu"))
        # cv2.imshow("Predictions", out.get_image()[:, :, ::-1])

        cv2.imwrite(f"{output_dir}/{d['id']}.jpg", out.get_image()[:, :, ::-1])
        # cv2.waitKey(1000)

    root_directory_name = os.path.basename(os.path.normpath(directory))
    convert_jpgs_to_video(output_dir, os.path.join(output_dir, f"{root_directory_name}.mp4"), 5)

if __name__ == "__main__":
    main()


import os
import pytz
import time
import rrdtool
import logging
import datetime

from scalrpy.util import helper

LOG = logging.getLogger('ScalrPy')

SOURCE = {
    'cpu': [
        'DS:user:COUNTER:600:U:U',
        'DS:system:COUNTER:600:U:U',
        'DS:nice:COUNTER:600:U:U',
        'DS:idle:COUNTER:600:U:U',
        ],
    'la': [
        'DS:la1:GAUGE:600:U:U',
        'DS:la5:GAUGE:600:U:U',
        'DS:la15:GAUGE:600:U:U',
        ],
    'mem': [
        'DS:swap:GAUGE:600:U:U',
        'DS:swapavail:GAUGE:600:U:U',
        'DS:total:GAUGE:600:U:U',
        'DS:avail:GAUGE:600:U:U',
        'DS:free:GAUGE:600:U:U',
        'DS:shared:GAUGE:600:U:U',
        'DS:buffer:GAUGE:600:U:U',
        'DS:cached:GAUGE:600:U:U',
        ],
    'net': [
        'DS:in:COUNTER:600:U:21474836480',
        'DS:out:COUNTER:600:U:21474836480',
        ],
    'snum': [
        'DS:s_running:GAUGE:600:U:U'],
    'io': [
        'DS:read:COUNTER:600:U:U',
        'DS:write:COUNTER:600:U:U',
        'DS:rbyte:COUNTER:600:U:U',
        'DS:wbyte:COUNTER:600:U:U'],
    }

ARCHIVE = {
    'cpu': [
        'RRA:AVERAGE:0.5:1:800',
        'RRA:AVERAGE:0.5:6:800',
        'RRA:AVERAGE:0.5:24:800',
        'RRA:AVERAGE:0.5:288:800',
        'RRA:MAX:0.5:1:800',
        'RRA:MAX:0.5:6:800',
        'RRA:MAX:0.5:24:800',
        'RRA:MAX:0.5:288:800',
        'RRA:LAST:0.5:1:800',
        'RRA:LAST:0.5:6:800',
        'RRA:LAST:0.5:24:800',
        'RRA:LAST:0.5:288:800',
        ],
    'la': [
        'RRA:AVERAGE:0.5:1:800',
        'RRA:AVERAGE:0.5:6:800',
        'RRA:AVERAGE:0.5:24:800',
        'RRA:AVERAGE:0.5:288:800',
        'RRA:MAX:0.5:1:800',
        'RRA:MAX:0.5:6:800',
        'RRA:MAX:0.5:24:800',
        'RRA:MAX:0.5:288:800',
        'RRA:LAST:0.5:1:800',
        'RRA:LAST:0.5:6:800',
        'RRA:LAST:0.5:24:800',
        'RRA:LAST:0.5:288:800',
        ],
    'mem': [
        'RRA:AVERAGE:0.5:1:800',
        'RRA:AVERAGE:0.5:6:800',
        'RRA:AVERAGE:0.5:24:800',
        'RRA:AVERAGE:0.5:288:800',
        'RRA:MAX:0.5:1:800',
        'RRA:MAX:0.5:6:800',
        'RRA:MAX:0.5:24:800',
        'RRA:MAX:0.5:288:800',
        'RRA:LAST:0.5:1:800',
        'RRA:LAST:0.5:6:800',
        'RRA:LAST:0.5:24:800',
        'RRA:LAST:0.5:288:800',
        ],
    'net': [
        'RRA:AVERAGE:0.5:1:800',
        'RRA:AVERAGE:0.5:6:800',
        'RRA:AVERAGE:0.5:24:800',
        'RRA:AVERAGE:0.5:288:800',
        'RRA:MAX:0.5:1:800',
        'RRA:MAX:0.5:6:800',
        'RRA:MAX:0.5:24:800',
        'RRA:MAX:0.5:288:800',
        'RRA:LAST:0.5:1:800',
        'RRA:LAST:0.5:6:800',
        'RRA:LAST:0.5:24:800',
        'RRA:LAST:0.5:288:800',
        ],
    'snum': [
        'RRA:AVERAGE:0.5:1:800',
        'RRA:AVERAGE:0.5:6:800',
        'RRA:AVERAGE:0.5:24:800',
        'RRA:AVERAGE:0.5:288:800',
        'RRA:MAX:0.5:1:800',
        'RRA:MAX:0.5:6:800',
        'RRA:MAX:0.5:24:800',
        'RRA:MAX:0.5:288:800',
        'RRA:LAST:0.5:1:800',
        'RRA:LAST:0.5:6:800',
        'RRA:LAST:0.5:24:800',
        'RRA:LAST:0.5:288:800',
        ],
    'io': [
        'RRA:AVERAGE:0.5:1:800',
        'RRA:AVERAGE:0.5:6:800',
        'RRA:AVERAGE:0.5:24:800',
        'RRA:AVERAGE:0.5:288:800',
        'RRA:MAX:0.5:1:800',
        'RRA:MAX:0.5:6:800',
        'RRA:MAX:0.5:24:800',
        'RRA:MAX:0.5:288:800',
        'RRA:LAST:0.5:1:800',
        'RRA:LAST:0.5:6:800',
        'RRA:LAST:0.5:24:800',
        'RRA:LAST:0.5:288:800',
        ],
    }

GRAPH_OPT = {
    'daily':{
        'start':'-1d5min',
        'end':'-5min',
        'step':'180',
        'update_every':'600',
        'x_grid':'HOUR:1:HOUR:2:HOUR:2:0:%H',
        },
    'weekly':{
        'start':'-1wk5min',
        'end':'-5min',
        'step':'1800',
        'update_every':'7200',
        'x_grid':'HOUR:12:HOUR:24:HOUR:24:0:%a',
        },
    'monthly':{
        'start':'-1mon5min',
        'end':'-5min',
        'step':'7200',
        'update_every':'43200',
        'x_grid':'DAY:2:WEEK:1:WEEK:1:0:week %V',
        },
    'yearly':{
        'start':'-1y',
        'end':'-5min',
        'step':'86400',
        'update_every':'86400',
        'x_grid':'MONTH:1:MONTH:1:MONTH:1:0:%b',
        },
    }

def create_db(file_path, metric):
    if not os.path.exists(os.path.dirname(file_path)):
        os.makedirs(os.path.dirname(file_path))
    rrdtool.create(file_path, SOURCE[metric], ARCHIVE[metric])

def get_data_to_write(metric_name, metric_data):
    data_to_write = 'N'
    for source in SOURCE[metric_name]:
        data_type = {'COUNTER': int, 'GAUGE': float}[source.split(':')[2]]
        try:
            data_to_write += ':%s' % (data_type)(metric_data[source.split(':')[1]])
        except:
            data_to_write += ':U'
    return data_to_write

def update(file_path, data):
    LOG.debug('%s, %s, %s' % (time.time(), file_path, data))
    try:
        rrdtool.update(file_path, '--daemon', 'unix:/var/run/rrdcached.sock', data)
    except rrdtool.error:
        LOG.error('%s rrdtool update error: %s' % (file_path, helper.exc_info()))

def write(base_dir, data):
    try:
        for metric_name, metric_data in data.iteritems():
            if metric_name == 'snum':
                file_path = os.path.join(base_dir, 'SERVERS', 'db.rrd')
                if not os.path.isfile(file_path):
                    create_db(file_path, metric_name)
                data_to_write = get_data_to_write(metric_name, metric_data)
                update(file_path, data_to_write)
            elif metric_name == 'io':
                for device_name, device_data in metric_data.iteritems():
                    file_path = os.path.join(base_dir, 'IO', '%s.rrd' % device_name)
                    if not os.path.isfile(file_path):
                        create_db(file_path, metric_name)
                    data_to_write = get_data_to_write(metric_name, device_data)
                    update(file_path, data_to_write)
            else:
                name_upper = metric_name.upper()
                file_path = os.path.join(base_dir, '%sSNMP' % name_upper, 'db.rrd')
                if not os.path.isfile(file_path):
                    create_db(file_path, metric_name)
                data_to_write = get_data_to_write(metric_name, metric_data)
                update(file_path, data_to_write)
    except:
        LOG.error(helper.exc_info())

def plot_cpu(img_path, rrd_path, opt, tz=None):
    color_cpu_user_line = '#00DF00FF'
    color_cpu_user_area = '#00DF0044'
    color_cpu_syst_line = '#DF0000FF'
    color_cpu_syst_area = '#DF000044'
    color_cpu_nice_line = '#DFDF00FF'
    color_cpu_nice_area = '#DFDF0044'
    color_cpu_idle_line = '#0051AAFF'
    color_cpu_idle_area = '#0051AA22'
    if tz:
        utc = datetime.datetime.utcnow()
        time_string = pytz.timezone(tz).fromutc(utc).strftime('%b %d, %Y %H:%M:%S %z')
    else:
        time_string = time.strftime('%b %d, %Y %H:%M:%S %z')
    rrdtool.graph(
            img_path,
            '--imgformat', 'PNG',
            '--step', opt['step'],
            '--pango-markup',
            '--vertical-label', 'Percent CPU Utilization',
            '--title', 'CPU Utilization (%s)' % time_string,
            '--upper-limit', '100',
            '--alt-autoscale-max',
            '--alt-autoscale-min',
            '--rigid',
            '--no-gridfit',
            '--slope-mode',
            '--x-grid', opt['x_grid'],
            '--end', opt['end'],
            '--start', opt['start'],
            '--width', '440',
            '--height', '160',
            '--font-render-mode', 'normal',
            '--border', '0',
            '--color', 'BACK#FFFFFF',
            'DEF:a=%s:user:AVERAGE' % rrd_path,
            'DEF:b=%s:system:AVERAGE' % rrd_path,
            'DEF:c=%s:nice:AVERAGE' % rrd_path,
            'DEF:d=%s:idle:AVERAGE' % rrd_path,
            'CDEF:total=a,b,c,d,+,+,+',
            'CDEF:a_perc=a,total,/,100,*',
            'VDEF:a_perc_last=a_perc,LAST',
            'VDEF:a_perc_avg=a_perc,AVERAGE',
            'VDEF:a_perc_max=a_perc,MAXIMUM',
            'CDEF:b_perc=b,total,/,100,*',
            'VDEF:b_perc_last=b_perc,LAST',
            'VDEF:b_perc_avg=b_perc,AVERAGE',
            'VDEF:b_perc_max=b_perc,MAXIMUM',
            'CDEF:c_perc=c,total,/,100,*',
            'VDEF:c_perc_last=c_perc,LAST',
            'VDEF:c_perc_avg=c_perc,AVERAGE',
            'VDEF:c_perc_max=c_perc,MAXIMUM',
            'CDEF:d_perc=d,total,/,100,*',
            'VDEF:d_perc_last=d_perc,LAST',
            'VDEF:d_perc_avg=d_perc,AVERAGE',
            'VDEF:d_perc_max=d_perc,MAXIMUM',

            'COMMENT:<tt>                Current   Average   Maximum</tt>\l',

            'LINE1:a_perc%s:<tt>user  </tt>\\t' % color_cpu_user_line,
            'AREA:a_perc%s:' % color_cpu_user_area,
            'GPRINT:a_perc_last:<tt>%3.0lf%% </tt>\\t',
            'GPRINT:a_perc_avg:<tt>%3.0lf%% </tt>\\t',
            'GPRINT:a_perc_max:<tt>%3.0lf%% </tt>\l',

            'LINE1:b_perc%s:<tt>system</tt>\\t' % color_cpu_syst_line,
            'AREA:b_perc%s:' % color_cpu_syst_area,
            'GPRINT:b_perc_last:<tt>%3.0lf%% </tt>\\t',
            'GPRINT:b_perc_avg:<tt>%3.0lf%% </tt>\\t',
            'GPRINT:b_perc_max:<tt>%3.0lf%% </tt>\l',

            'LINE1:c_perc%s:<tt>nice  </tt>\\t' % color_cpu_nice_line,
            'AREA:c_perc%s:' % color_cpu_nice_area,
            'GPRINT:c_perc_last:<tt>%3.0lf%% </tt>\\t',
            'GPRINT:c_perc_avg:<tt>%3.0lf%% </tt>\\t',
            'GPRINT:c_perc_max:<tt>%3.0lf%% </tt>\l',

            'LINE1:d_perc%s:<tt>idle  </tt>\\t' % color_cpu_idle_line,
            'AREA:d_perc%s:' % color_cpu_idle_area,
            'GPRINT:d_perc_last:<tt>%3.0lf%% </tt>\\t',
            'GPRINT:d_perc_avg:<tt>%3.0lf%% </tt>\\t',
            'GPRINT:d_perc_max:<tt>%3.0lf%% </tt>\l'
            )

def plot_la(img_path, rrd_path, opt, tz=None):
    color_la1_line  = '#CF0000FF'
    color_la1_area  = '#CF000030'
    color_la5_line  = '#0000CFFF'
    color_la5_area  = '#0000CF30'
    color_la15_line = '#00CF00FF'
    color_la15_area = '#00CF0030'
    if tz:
        utc = datetime.datetime.utcnow()
        time_string = pytz.timezone(tz).fromutc(utc).strftime('%b %d, %Y %H:%M:%S %z')
    else:
        time_string = time.strftime('%b %d, %Y %H:%M:%S %z')
    rrdtool.graph(
            img_path,
            '--imgformat', 'PNG',
            '--step', opt['step'],
            '--pango-markup',
            '--vertical-label', 'Load averages',
            '--title', 'Load averages (%s)' % time_string,
            '--lower-limit', '0',
            '--alt-autoscale-max',
            '--alt-autoscale-min',
            '--rigid',
            '--no-gridfit',
            '--slope-mode',
            '--alt-y-grid',
            '--units-exponent', '0',
            '--x-grid', opt['x_grid'],
            '--end', opt['end'],
            '--start', opt['start'],
            '--width', '440',
            '--height', '140',
            '--font-render-mode', 'normal',
            '--border', '0',
            '--color', 'BACK#FFFFFF',

            'DEF:la1=%s:la1:AVERAGE' % rrd_path,
            'DEF:la5=%s:la5:AVERAGE' % rrd_path,
            'DEF:la15=%s:la15:AVERAGE' % rrd_path,
            'VDEF:la1_min=la1,MINIMUM',
            'VDEF:la1_last=la1,LAST',
            'VDEF:la1_avg=la1,AVERAGE',
            'VDEF:la1_max=la1,MAXIMUM',
            'VDEF:la5_min=la5,MINIMUM',
            'VDEF:la5_last=la5,LAST',
            'VDEF:la5_avg=la5,AVERAGE',
            'VDEF:la5_max=la5,MAXIMUM',
            'VDEF:la15_min=la15,MINIMUM',
            'VDEF:la15_last=la15,LAST',
            'VDEF:la15_avg=la15,AVERAGE',
            'VDEF:la15_max=la15,MAXIMUM',

            'COMMENT:<tt>                            Minimum   Current    Average   Maximum</tt>\l',

            'LINE1:la15%s:<tt>15 Minutes system load   </tt>' % color_la15_line,
            'AREA:la15%s:' % color_la15_area,
            'GPRINT:la15_min:<tt>%3.2lf</tt>\\t',
            'GPRINT:la15_last:<tt>%3.2lf</tt>\\t',
            'GPRINT:la15_avg:<tt>%3.2lf</tt>\\t',
            'GPRINT:la15_max:<tt>%3.2lf</tt>\l',

            'LINE1:la5%s:<tt> 5 Minutes system load   </tt>' % color_la5_line,
            'AREA:la5%s:' % color_la5_area,
            'GPRINT:la5_min:<tt>%3.2lf</tt>\\t',
            'GPRINT:la5_last:<tt>%3.2lf</tt>\\t',
            'GPRINT:la5_avg:<tt>%3.2lf</tt>\\t',
            'GPRINT:la5_max:<tt>%3.2lf</tt>\l',

            'LINE1:la1%s:<tt> 1 Minute  system load   </tt>' % color_la1_line,
            'AREA:la1%s:' % color_la1_area,
            'GPRINT:la1_min:<tt>%3.2lf</tt>\\t',
            'GPRINT:la1_last:<tt>%3.2lf</tt>\\t',
            'GPRINT:la1_avg:<tt>%3.2lf</tt>\\t',
            'GPRINT:la1_max:<tt>%3.2lf</tt>\l'
            )

def plot_mem(img_path, rrd_path, opt, tz=None):
    color_mem_shrd = '#00FFFF'
    color_mem_buff_line = '#FF0000FF'
    color_mem_buff_area = '#FF000055'
    color_mem_cach_line = '#0000FFFF'
    color_mem_cach_area = '#0000FF30'
    color_mem_free_line = '#00CF00FF'
    color_mem_free_area = '#00CF0030'
    color_mem_swap_line = '#EFEF00FF'
    color_mem_swap_area = '#EFEF0030'
    if tz:
        utc = datetime.datetime.utcnow()
        time_string = pytz.timezone(tz).fromutc(utc).strftime('%b %d, %Y %H:%M:%S %z')
    else:
        time_string = time.strftime('%b %d, %Y %H:%M:%S %z')
    rrdtool.graph(
            img_path,
            '--imgformat', 'PNG',
            '--step', opt['step'],
            '--pango-markup',
            '--vertical-label', 'Memory Usage',
            '--title', 'Memory Usage (%s)' % time_string,
            '--lower-limit', '0',
            '--base', '1024',
            '--alt-autoscale-max',
            '--alt-autoscale-min',
            '--rigid',
            '--no-gridfit',
            '--slope-mode',
            '--x-grid', opt['x_grid'],
            '--end', opt['end'],
            '--start', opt['start'],
            '--width', '440',
            '--height', '180',
            '--font-render-mode', 'normal',
            '--border', '0',
            '--color', 'BACK#FFFFFF',

            'DEF:mem1=%s:swap:AVERAGE' % rrd_path,
            'DEF:mem2=%s:swapavail:AVERAGE' % rrd_path,
            'DEF:mem3=%s:total:AVERAGE' % rrd_path,
            'DEF:mem4=%s:avail:AVERAGE' % rrd_path,
            'DEF:mem5=%s:free:AVERAGE' % rrd_path,
            'DEF:mem6=%s:shared:AVERAGE' % rrd_path,
            'DEF:mem7=%s:buffer:AVERAGE' % rrd_path,
            'DEF:mem8=%s:cached:AVERAGE' % rrd_path,
            'CDEF:swap_total=mem1,1024,*',
            'VDEF:swap_total_min=swap_total,MINIMUM',
            'VDEF:swap_total_last=swap_total,LAST',
            'VDEF:swap_total_avg=swap_total,AVERAGE',
            'VDEF:swap_total_max=swap_total,MAXIMUM',
            'CDEF:swap_avail=mem2,1024,*',
            'VDEF:swap_avail_min=swap_avail,MINIMUM',
            'VDEF:swap_avail_last=swap_avail,LAST',
            'VDEF:swap_avail_avg=swap_avail,AVERAGE',
            'VDEF:swap_avail_max=swap_avail,MAXIMUM',
            'CDEF:swap_used=swap_total,swap_avail,-',
            'VDEF:swap_used_min=swap_used,MINIMUM',
            'VDEF:swap_used_last=swap_used,LAST',
            'VDEF:swap_used_avg=swap_used,AVERAGE',
            'VDEF:swap_used_max=swap_used,MAXIMUM',
            'CDEF:mem_total=mem3,1024,*',
            'VDEF:mem_total_min=mem_total,MINIMUM',
            'VDEF:mem_total_last=mem_total,LAST',
            'VDEF:mem_total_avg=mem_total,AVERAGE',
            'VDEF:mem_total_max=mem_total,MAXIMUM',
            'CDEF:mem_avail=mem4,1024,*',
            'VDEF:mem_avail_min=mem_avail,MINIMUM',
            'VDEF:mem_avail_last=mem_avail,LAST',
            'VDEF:mem_avail_avg=mem_avail,AVERAGE',
            'VDEF:mem_avail_max=mem_avail,MAXIMUM',
            'CDEF:mem_free=mem5,1024,*',
            'VDEF:mem_free_min=mem_free,MINIMUM',
            'VDEF:mem_free_last=mem_free,LAST',
            'VDEF:mem_free_avg=mem_free,AVERAGE',
            'VDEF:mem_free_max=mem_free,MAXIMUM',
            'CDEF:mem_shared=mem6,1024,*',
            'VDEF:mem_shared_min=mem_shared,MINIMUM',
            'VDEF:mem_shared_last=mem_shared,LAST',
            'VDEF:mem_shared_avg=mem_shared,AVERAGE',
            'VDEF:mem_shared_max=mem_shared,MAXIMUM',
            'CDEF:mem_buffer=mem7,1024,*',
            'VDEF:mem_buffer_min=mem_buffer,MINIMUM',
            'VDEF:mem_buffer_last=mem_buffer,LAST',
            'VDEF:mem_buffer_avg=mem_buffer,AVERAGE',
            'VDEF:mem_buffer_max=mem_buffer,MAXIMUM',
            'CDEF:mem_cached=mem8,1024,*',
            'VDEF:mem_cached_min=mem_cached,MINIMUM',
            'VDEF:mem_cached_last=mem_cached,LAST',
            'VDEF:mem_cached_avg=mem_cached,AVERAGE',
            'VDEF:mem_cached_max=mem_cached,MAXIMUM',

            'COMMENT:<tt>                  Minimum   Current    Average   Maximum</tt>\l',

            'LINE1:mem_shared%s:<tt>Shared        </tt>' % color_mem_shrd,
            'GPRINT:swap_total_min:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:swap_total_last:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:swap_total_avg:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:swap_total_max:<tt>%4.1lf%s</tt>\l',

            'LINE1:mem_buffer%s:<tt>Buffer        </tt>' % color_mem_buff_line,
            'AREA:mem_buffer%s:' % color_mem_buff_area,
            'GPRINT:mem_buffer_min:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:mem_buffer_last:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:mem_buffer_avg:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:mem_buffer_max:<tt>%4.1lf%s</tt>\l',

            'LINE1:mem_cached%s:<tt>Cached        </tt>' % color_mem_cach_line,
            'AREA:mem_cached%s:' % color_mem_cach_area,
            'GPRINT:mem_cached_min:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:mem_cached_last:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:mem_cached_avg:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:mem_cached_max:<tt>%4.1lf%s</tt>\l',

            'LINE1:mem_free%s:<tt>Free          </tt>' % color_mem_free_line,
            'AREA:mem_free%s:' % color_mem_free_area,
            'GPRINT:mem_free_min:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:mem_free_last:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:mem_free_avg:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:mem_free_max:<tt>%4.1lf%s</tt>\l',

            'LINE1:swap_used%s:<tt>Swap In Use   </tt>' % color_mem_swap_line,
            'AREA:swap_used%s:' % color_mem_swap_area,
            'GPRINT:swap_used_min:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:swap_used_last:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:swap_used_avg:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:swap_used_max:<tt>%4.1lf%s</tt>\l'
            )

def plot_net(img_path, rrd_path, opt, tz=None):
    color_ibound_line = '#CF0000FF'
    color_ibound_area = '#CF000030'
    color_obound_line = '#0000CFFF'
    color_obound_area = '#0000CF30'
    if tz:
        utc = datetime.datetime.utcnow()
        time_string = pytz.timezone(tz).fromutc(utc).strftime('%b %d, %Y %H:%M:%S %z')
    else:
        time_string = time.strftime('%b %d, %Y %H:%M:%S %z')
    rrdtool.graph(
            img_path,
            '--imgformat', 'PNG',
            '--step', opt['step'],
            '--pango-markup',
            '--vertical-label', 'Bits per second',
            '--title', 'Network usage (%s)' % time_string,
            '--lower-limit', '0',
            '--alt-autoscale-max',
            '--alt-autoscale-min',
            '--rigid',
            '--no-gridfit',
            '--slope-mode',
            '--x-grid', opt['x_grid'],
            '--end', opt['end'],
            '--start', opt['start'],
            '--width', '440',
            '--height', '100',
            '--font-render-mode', 'normal',
            '--border', '0',
            '--color', 'BACK#FFFFFF',

            'DEF:in=%s:in:AVERAGE' % rrd_path,
            'DEF:out=%s:out:AVERAGE' % rrd_path,
            'CDEF:in_bits=in,8,*',
            'CDEF:out_bits=out,8,*',
            'VDEF:in_last=in_bits,LAST',
            'VDEF:in_avg=in_bits,AVERAGE',
            'VDEF:in_max=in_bits,MAXIMUM',
            'VDEF:out_last=out_bits,LAST',
            'VDEF:out_avg=out_bits,AVERAGE',
            'VDEF:out_max=out_bits,MAXIMUM',

            'COMMENT:<tt>          Current   Average   Maximum</tt>\\l',

            'LINE1:in_bits%s:<tt>In    </tt>' % color_ibound_line,
            'AREA:in_bits%s:' % color_ibound_area,
            'GPRINT:in_last:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:in_avg:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:in_max:<tt>%4.1lf%s</tt>\l',

            'LINE1:out_bits%s:<tt>Out   </tt>' % color_obound_line,
            'AREA:out_bits%s:' % color_obound_area,
            'GPRINT:out_last:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:out_avg:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:out_max:<tt>%4.1lf%s</tt>\l'
            )

def plot_snum(img_path, rrd_path, opt, tz=None):
    color_running_servers_line = '#00CF00FF'
    color_running_servers_area = '#00CF0044'
    if tz:
        utc = datetime.datetime.utcnow()
        time_string = pytz.timezone(tz).fromutc(utc).strftime('%b %d, %Y %H:%M:%S %z')
    else:
        time_string = time.strftime('%b %d, %Y %H:%M:%S %z')
    rrdtool.graph(
            img_path,
            '--imgformat', 'PNG',
            '--step', opt['step'],
            '--pango-markup',
            '--vertical-label', 'Servers',
            '--title', 'Servers count (%s)' % time_string,
            '--alt-autoscale-max',
            '--alt-autoscale-min',
            '--lower-limit', '0',
            '--y-grid', '1:1',
            '--units-exponent', '0',
            '--rigid',
            '--no-gridfit',
            '--slope-mode',
            '--x-grid', opt['x_grid'],
            '--end', opt['end'],
            '--start', opt['start'],
            '--width', '440',
            '--height', '100',
            '--font-render-mode', 'normal',
            '--border', '0',
            '--color', 'BACK#FFFFFF',

            'DEF:s_running=%s:s_running:AVERAGE' % rrd_path,
            'VDEF:s_running_last=s_running,LAST',
            'VDEF:s_running_avg=s_running,AVERAGE',
            'VDEF:s_running_max=s_running,MAXIMUM',
            'VDEF:s_running_min=s_running,MINIMUM',

            'COMMENT:<tt>                      Current    Average   Maximum   Minimum</tt>\l',

            'LINE1:s_running%s:<tt>Running servers    </tt>' % color_running_servers_line,
            'AREA:s_running%s:' % color_running_servers_area,
            'GPRINT:s_running_last:<tt>%3.0lf</tt>\\t',
            'GPRINT:s_running_avg:<tt>%3.0lf</tt>\\t',
            'GPRINT:s_running_max:<tt>%3.0lf</tt>\\t',
            'GPRINT:s_running_min:<tt>%3.0lf</tt>\l'
            )

def plot_io_bits(img_path, rrd_path, opt, tz=None):
    color_r = '#ff0000'
    color_w = '#0000ff'
    if tz:
        utc = datetime.datetime.utcnow()
        time_string = pytz.timezone(tz).fromutc(utc).strftime('%b %d, %Y %H:%M:%S %z')
    else:
        time_string = time.strftime('%b %d, %Y %H:%M:%S %z')
    rrdtool.graph(
            img_path,
            '--imgformat', 'PNG',
            '--step', opt['step'],
            '--pango-markup',
            '--vertical-label', 'Bits per second',
            '--title', 'Disk I/O (%s)' % time_string,
            '--lower-limit', '0',
            '--alt-autoscale-max',
            '--alt-autoscale-min',
            '--rigid',
            '--no-gridfit',
            '--slope-mode',
            '--x-grid', opt['x_grid'],
            '--end', opt['end'],
            '--start', opt['start'],
            '--width', '440',
            '--height', '100',
            '--font-render-mode', 'normal',
            '--border', '0',
            '--color', 'BACK#FFFFFF',

            'DEF:rbyte=%s:rbyte:AVERAGE' % rrd_path,
            'DEF:wbyte=%s:wbyte:AVERAGE' % rrd_path,
            'CDEF:rbits=rbyte,8,*',
            'CDEF:wbits=wbyte,8,*',
            'VDEF:rbits_last=rbits,LAST',
            'VDEF:rbits_avg=rbits,AVERAGE',
            'VDEF:rbits_max=rbits,MAXIMUM',
            'VDEF:wbits_last=wbits,LAST',
            'VDEF:wbits_avg=wbits,AVERAGE',
            'VDEF:wbits_max=wbits,MAXIMUM',

            'COMMENT:<tt>                Current    Average   Maximum</tt>\\l',

            'AREA:wbits%s:<tt>Write bits   </tt>' % color_w,
            'GPRINT:wbits_last:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:wbits_avg:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:wbits_max:<tt>%4.1lf%s</tt>\l',

            'AREA:rbits%s:<tt>Read  bits   </tt>' % color_r,
            'GPRINT:rbits_last:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:rbits_avg:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:rbits_max:<tt>%4.1lf%s</tt>\l'
            )

def plot_io_ops(img_path, rrd_path, opt, tz=None):
    color_r = '#ff0000'
    color_w = '#0000ff'
    if tz:
        utc = datetime.datetime.utcnow()
        time_string = pytz.timezone(tz).fromutc(utc).strftime('%b %d, %Y %H:%M:%S %z')
    else:
        time_string = time.strftime('%b %d, %Y %H:%M:%S %z')
    rrdtool.graph(
            img_path,
            '--imgformat', 'PNG',
            '--step', opt['step'],
            '--pango-markup',
            '--vertical-label', 'Operations per second',
            '--title', 'Disk I/O (%s)' % time_string,
            '--lower-limit', '0',
            '--alt-autoscale-max',
            '--alt-autoscale-min',
            '--rigid',
            '--no-gridfit',
            '--slope-mode',
            '--x-grid', opt['x_grid'],
            '--end', opt['end'],
            '--start', opt['start'],
            '--width', '440',
            '--height', '100',
            '--font-render-mode', 'normal',
            '--border', '0',
            '--color', 'BACK#FFFFFF',

            'DEF:read=%s:read:AVERAGE' % rrd_path,
            'DEF:write=%s:write:AVERAGE' % rrd_path,
            'VDEF:read_last=read,LAST',
            'VDEF:read_avg=read,AVERAGE',
            'VDEF:read_max=read,MAXIMUM',
            'VDEF:write_last=write,LAST',
            'VDEF:write_avg=write,AVERAGE',
            'VDEF:write_max=write,MAXIMUM',

            'COMMENT:<tt>             Current    Average   Maximum</tt>\\l',

            'AREA:write%s:<tt>Writes     </tt>' % color_w,
            'GPRINT:write_last:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:write_avg:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:write_max:<tt>%4.1lf%s</tt>\l',

            'AREA:read%s:<tt>Reads     </tt>' % color_r,
            'GPRINT:read_last:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:read_avg:<tt>%4.1lf%s</tt>\\t',
            'GPRINT:read_max:<tt>%4.1lf%s</tt>\l'
            )


import json
import os
import numpy as np
from matplotlib import pyplot as plt

def read_url_file(fname):

    with open(fname) as f:
        urls = f.readlines()
        urls = [x.strip() for x in urls]

    return urls

def process_json(data):

    hop_list = []
    result = data[0]['result']
    num_hops = len(result)
    num_asterisks = 0
    for item in result:
        hop_num = item['hop']
        hop_result = item['result'][0]
        ip = hop_result['from']
        if ip == '*':
            num_asterisks += 1
        hop_list.append(ip)

    return num_hops, num_asterisks, hop_list

def get_hop_differences(hop_list_all_runs):

    n = len(hop_list_all_runs)
    list_len = [len(x) for x in hop_list_all_runs]
    print(list_len)
    max_hops = max(list_len)
    num_ips_at_hop = []

    for i in range(0, max_hops):
        ip_at_hop = []
        for item in hop_list_all_runs:
            if len(item) > i:
                ip_at_hop.append(item[i])
        num_ips = len(set(ip_at_hop))
        if (num_ips == 1) & ('*' in ip_at_hop):
            num_ips = -1
        num_ips_at_hop.append(num_ips)
    return num_ips_at_hop

def process_file(output_dir, tag, num_runs=5):

    num_hops_list = []
    perc_asterisk_list = []
    hop_list_all_runs = []

    for ct in range(1, num_runs+1):
        fname = tag + str(ct) + ".json"
        fname = os.path.join(output_dir, fname)
        with open(fname) as f:
            try:
                data = json.loads(f.read())
                num_hops, num_asterisks, hop_list = process_json(data)
                num_hops_list.append(num_hops)
                perc_asterisk_list.append(num_asterisks/num_hops * 100)
                hop_list_all_runs.append(hop_list)
            except Exception as e:
                print(e)
    num_ips_at_hop = get_hop_differences(hop_list_all_runs)

    return num_hops_list, perc_asterisk_list, num_ips_at_hop

def plot_data(all_hops, all_perc_asterisk, all_ip_at_hop, urls):

    hops_mean = [np.mean(x) for x in all_hops]
    hops_std = [np.std(x) for x in all_hops]
    ind = np.arange(len(urls))

    plt.bar(ind, hops_mean, yerr=hops_std)
    plt.xticks(ind, urls, rotation='vertical')
    plt.ylabel("Number of hops")
    plt.show()

    ast_mean = [np.mean(x) for x in all_perc_asterisk]
    ast_std = [np.std(x) for x in all_perc_asterisk]
    plt.bar(ind, ast_mean, yerr=ast_std)
    plt.xticks(ind, urls, rotation='vertical')
    plt.ylabel("% asterisks in route")
    plt.show()

    for i in range(0, len(urls)):
        x_data = range(0, len(all_ip_at_hop[i]))
        plt.plot(x_data, all_ip_at_hop[i], 'o-', label=urls[i])
    plt.ylabel("Number of IPs seen")
    plt.xlabel("Hop")
    plt.legend()
    plt.show()

    for i in range(0, len(urls)):
        x_data = range(0, len(all_ip_at_hop[i]))
        x_data = [(x+1)/len(all_ip_at_hop[i]) * 100 for x in x_data]
        plt.plot(x_data, all_ip_at_hop[i], 'o-', label=urls[i])
    plt.legend()
    plt.ylabel("Number of IPs seen")
    plt.xlabel("Hop as a % of total route")
    plt.show()

def process_files(output_dir, url_file, num_runs=5):

    urls = read_url_file(url_file)[:5]
    filenames = os.listdir(output_dir)

    all_hops = []
    all_perc_asterisk = []
    all_ip_at_hop = []

    for i in range(0, len(urls)):
        tag = "out" + str(i) + "_"
        num_hops_list, perc_asterisk_list, num_ips_at_hop = process_file(output_dir, tag)
        all_hops.append(num_hops_list)
        all_perc_asterisk.append(perc_asterisk_list)
        all_ip_at_hop.append(num_ips_at_hop)

    plot_data(all_hops, all_perc_asterisk, all_ip_at_hop, urls)

if __name__ == "__main__":

    OUTPUT_DIR = "../outputsc"
    URL_FILE = "../urls_test"
    NUM_RUNS = 5
    process_files(OUTPUT_DIR, URL_FILE, NUM_RUNS)


import cv2

font1 = cv2.FONT_HERSHEY_SIMPLEX
img = cv2.imread(r"C:\Users\suley\Desktop\software\materials\opencv_materials\polygons.png")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 240, 255, cv2.THRESH_BINARY)
contours, ret2 = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# contour = bir rengin veya yogunluğunun sahip olduğu tum surekli noktaları birlestiren kapalı bir egridir

for cnt in contours:

    epsilon = 0.01 * cv2.arcLength(cnt, True)
    approx = cv2.approxPolyDP(cnt, epsilon, True)  # konturleri alip kenarlari sayan fonskiyon tanimlandi
    # approx bulunan her geomterik sekilde sira ile kose koordinatlarini 2 boyutlu sekilde aldi

    cv2.drawContours(img, [approx], 0, 0, 3)  # konturler cizildi

    x = approx.ravel()[0]  # iki boyutlu approx degerlerini tek boyuta cekildi ve degerleri x y degiskenine atandi
    y = approx.ravel()[1]  # bu sayede yazinin yazilacagi koordinat belirlenmis oldu

    if len(approx) == 3:
        cv2.putText(img, "triangle", (x + 10, y), font1, 0.5, (0, 0, 255))
    elif len(approx) == 4:
        cv2.putText(img, "rectangle", (x + 5, y + 20), font1, 0.5, (0, 0, 255))
    elif len(approx) == 5:
        cv2.putText(img, "pentagon", (x + 10, y), font1, 0.5, (0, 0, 255))
    elif len(approx) == 6:
        cv2.putText(img, "hexagon", (x + 10, y), font1, 0.5, (0, 0, 255))
    else:
        cv2.putText(img, "ellipse", (x + 10, y), font1, 0.5, (0, 0, 255))

cv2.imshow("img", img)
cv2.imshow("gray", gray)
cv2.imshow("thresh", thresh)
cv2.waitKey(0)
cv2.destroyAllWindows()


import numpy as np
import matplotlib.pyplot as plt
#
a = 1.4
b = 0.3
X = [(0, 0)]
for n in range(100000):
    X.append((X[-1][1] + 1 - a * X[-1][0]**2, b * X[-1][0]))
#
#fig = plt.figure()
#plt.plot([x[0] for x in X],[x[1] for x in X],'.b')

nbins = 200
H, xedges, yedges = np.histogram2d(
    [x[0] for x in X], [x[1] for x in X], bins=nbins)

# H needs to be rotated and flipped
H = np.rot90(H)
H = np.flipud(H)

# Mask zeros
Hmasked = np.ma.masked_where(H == 0, H)  # Mask pixels with a value of zero

# Plot 2D histogram using pcolor
fig2 = plt.figure()
plt.pcolormesh(xedges, yedges, Hmasked)
plt.xlabel('x')
plt.ylabel('y')
cbar = plt.colorbar()
cbar.ax.set_ylabel('Counts')
plt.show()