text:
"""
Particle Filter helper functions
"""
import configparser
import json
import math
import os
from collections import defaultdict
from io import BytesIO
from itertools import permutations
from itertools import product
from pathlib import Path

import imageio
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import requests
from PIL import Image
from scipy.ndimage.filters import gaussian_filter

from .definitions import RUN_DIR

def permute_particle(particle):
    return np.hstack((particle[4:], particle[:4]))

def particle_swap(env):
    # 2000 x 8
    particles = np.copy(env.pf.particles)
    n_targets = env.state.n_targets
    state_dim = 4

    # convert particles to cartesian
    for i in range(n_targets):
        x, y = pol2cart(particles[:, state_dim*i],
                        np.radians(particles[:, (state_dim*i)+1]))
        particles[:, state_dim*i] = x
        particles[:, (state_dim*i)+1] = y

    swapped = True
    k = 0
    while swapped and k < 10:
        k += 1
        swapped = False
        for i in range(len(particles)):
            original_particle = np.copy(particles[i])
            target_centroids = [
                np.mean(particles[:, state_dim*t:(state_dim*t)+2]) for t in range(n_targets)]
            distance = 0
            for t in range(n_targets):
                dif = particles[i, state_dim *
                                t:(state_dim*t)+2] - target_centroids[t]
                distance += np.dot(dif, dif)

            permuted_particle = permute_particle(particles[i])
            particles[i] = permuted_particle
            permuted_target_centroids = [
                np.mean(particles[:, state_dim*t:(state_dim*t)+2]) for t in range(n_targets)]
            permuted_distance = 0
            for t in range(n_targets):
                dif = particles[i, state_dim *
                                t:(state_dim*t)+2] - permuted_target_centroids[t]
                permuted_distance += np.dot(dif, dif)

            if distance < permuted_distance:
                particles[i] = original_particle
            else:
                swapped = True

    # convert particles to polar
    for i in range(n_targets):
        rho, phi = cart2pol(
            particles[:, state_dim*i], particles[:, (state_dim*i)+1])
        particles[:, state_dim*i] = rho
        particles[:, (state_dim*i)+1] = np.degrees(phi)

    env.pf.particles = particles

def pol2cart(rho, phi):
    """
    Transform polar to cartesian
    """
    x = rho * np.cos(phi)
    y = rho * np.sin(phi)
    return(x, y)

def cart2pol(x, y):
    """
    Transform cartesian to polar
    """
    rho = np.sqrt(x**2 + y**2)
    phi = np.arctan2(y, x)
    return rho, phi

def get_distance(coord1, coord2):
    """
    Get the distance between two coordinates
    """
    if (coord1 is None) or (coord2 is None):
        return None

    lat1, long1 = coord1
    lat2, long2 = coord2
    # approximate radius of earth in km
    R = 6373.0

    lat1 = np.radians(lat1)
    long1 = np.radians(long1)

    lat2 = np.radians(lat2)
    long2 = np.radians(long2)

    dlon = long2 - long1
    dlat = lat2 - lat1

    a = np.sin(dlat / 2)**2 + np.cos(lat1) * np.cos(lat2) * np.sin(dlon / 2)**2
    c = 2 * np.arctan2(np.sqrt(a), np.sqrt(1 - a))

    distance = R * c
    return distance*(1e3)

def get_bearing(coord1, coord2):
    """
    Get the bearing of two coordinates
    """
    if (coord1 is None) or (coord2 is None):
        return None

    lat1, long1 = coord1
    lat2, long2 = coord2
    dLon = (long2 - long1)
    x = np.cos(np.radians(lat2)) * np.sin(np.radians(dLon))
    y = np.cos(np.radians(lat1)) * np.sin(np.radians(lat2)) - \
        np.sin(np.radians(lat1)) * np.cos(np.radians(lat2)) * \
        np.cos(np.radians(dLon))
    brng = np.arctan2(x, y)
    brng = np.degrees(brng)

    return -brng + 90

def is_float(element):
    """
    Check if an element is a float or not
    """
    try:
        float(element)
        return True
    except (ValueError, TypeError):
        return False

class GPSVis:
    """
        modified from:
        https://github.com/tisljaricleo/GPS-visualization-Python
        MIT License
        Copyright (c) 2021 Leo Tišljarić

        Class for GPS data visualization using pre-downloaded OSM map in image format.
    """

    def __init__(self, position=None, map_path=None, bounds=None):
        """
        :param data_path: Path to file containing GPS records.
        :param map_path: Path to pre-downloaded OSM map in image format.
        :param bounds: Upper-left, and lower-right GPS points of the map (lat1, lon1, lat2, lon2).
        """
        self.position = position
        self.map_path = map_path
        self.bounds = bounds

        if self.map_path is not None and self.bounds is not None:
            self.img = self.create_image_from_map()
        elif self.position is not None:
            self.zoom = 17
            self.TILE_SIZE = 256
            distance = 100

            coord = self.position

            lat_dist = distance/111111
            lon_dist = distance / (111111 * np.cos(np.radians(coord[0])))
            top, bot = coord[0] + lat_dist, coord[0] - lat_dist
            lef, rgt = coord[1] - lon_dist, coord[1] + lon_dist
            self.bounds = [top, lef, bot, rgt]

            self.img = self.create_image_from_position()
        self.get_ticks()
        self.cell_size = 1
        self.xedges = np.arange(0, self.width_meters +
                                self.cell_size, self.cell_size)
        self.yedges = np.arange(0, self.height_meters +
                                self.cell_size, self.cell_size)

    def plot_map(self, axis1=None, output=None, save_as='resultMap.png'):
        """
        Method for plotting the map. You can choose to save it in file or to plot it.
        :param output: Type 'plot' to show the map or 'save' to save it. Default None
        :param save_as: Name and type of the resulting image.
        :return:
        """
        # create Fig and Axis if doesn't exist
        if axis1 is None:
            fig, axis1 = plt.subplots(figsize=(10, 13))

        # Plot background map
        axis1.imshow(np.flipud(self.img), alpha=0.7, origin='lower')

        # Set axis dimensions, labels and tick marks
        axis1.set_xlim(0, int(self.width_meters))
        axis1.set_ylim(0, int(self.height_meters))
        axis1.set_xlabel('Longitude')
        axis1.set_ylabel('Latitude')
        axis1.set_xticks(np.linspace(0, int(self.width_meters), num=8))
        axis1.set_xticklabels(self.x_ticks, rotation=30, ha='center')
        axis1.set_yticks(np.linspace(0, int(self.height_meters), num=8))
        axis1.set_yticklabels(self.y_ticks)
        axis1.grid()

        # Save or display
        if output == 'save':
            plt.savefig(save_as)
        elif output == 'plot':
            plt.show()

    def point_to_pixels(self, lat, lon, zoom):
        """convert gps coordinates to web mercator"""
        r = math.pow(2, zoom) * self.TILE_SIZE
        lat = math.radians(lat)

        x = int((lon + 180.0) / 360.0 * r)
        y = int(
            (1.0 - math.log(math.tan(lat) + (1.0 / math.cos(lat))) / math.pi) / 2.0 * r)

        return x, y

    def create_image_from_position(self):
        URL = 'https://tile.openstreetmap.org/{z}/{x}/{y}.png'.format

        top, lef, bot, rgt = self.bounds

        x0, y0 = self.point_to_pixels(top, lef, self.zoom)
        x1, y1 = self.point_to_pixels(bot, rgt, self.zoom)

        x0_tile, y0_tile = int(x0 / self.TILE_SIZE), int(y0 / self.TILE_SIZE)
        x1_tile, y1_tile = math.ceil(
            x1 / self.TILE_SIZE), math.ceil(y1 / self.TILE_SIZE)

        assert (x1_tile - x0_tile) * (y1_tile -
                                      y0_tile) < 50, "That's too many tiles!"

        # full size image we'll add tiles to
        img = Image.new('RGB', (
            (x1_tile - x0_tile) * self.TILE_SIZE,
            (y1_tile - y0_tile) * self.TILE_SIZE))

        # loop through every tile inside our bounded box
        for x_tile, y_tile in product(range(x0_tile, x1_tile), range(y0_tile, y1_tile)):
            with requests.get(URL(x=x_tile, y=y_tile, z=self.zoom)) as resp:
                tile_img = Image.open(BytesIO(resp.content))
            # add each tile to the full size image
            img.paste(
                im=tile_img,
                box=((x_tile - x0_tile) * self.TILE_SIZE, (y_tile - y0_tile) * self.TILE_SIZE))

        x, y = x0_tile * self.TILE_SIZE, y0_tile * self.TILE_SIZE

        img = img.crop((
            int(x0-x),  # left
            int(y0-y),  # top
            int(x1-x),  # right
            int(y1-y)))  # bottom

        self.width_meters = get_distance(
            (self.bounds[0], self.bounds[1]), (self.bounds[0], self.bounds[3]))
        self.height_meters = get_distance(
            (self.bounds[0], self.bounds[1]), (self.bounds[2], self.bounds[1]))
        img = img.resize((int(self.width_meters), int(self.height_meters)))

        return img

    def create_image_from_map(self):
        """
        Create the image that contains the original map and the GPS records.
        :param color: Color of the GPS records.
        :param width: Width of the drawn GPS records.
        :return:
        """

        img = Image.open(self.map_path, 'r')
        self.width_meters = get_distance(
            (self.bounds[0], self.bounds[1]), (self.bounds[0], self.bounds[3]))
        self.height_meters = get_distance(
            (self.bounds[0], self.bounds[1]), (self.bounds[2], self.bounds[1]))
        img = img.resize((int(self.width_meters), int(self.height_meters)))
        print('background image size (pixels) = ', img.size)

        return img

    def scale_to_img(self, lat_lon, w_h):
        """
        Conversion from latitude and longitude to the image pixels.
        It is used for drawing the GPS records on the map image.
        :param lat_lon: GPS record to draw (lat1, lon1).
        :param w_h: Size of the map image (w, h).
        :return: Tuple containing x and y coordinates to draw on map image.
        """
        # https://gamedev.stackexchange.com/questions/33441/how-to-convert-a-number-from-one-min-max-set-to-another-min-max-set/33445
        lat_old = (self.bounds[2], self.bounds[0])
        new = (0, w_h[1])
        y = ((lat_lon[0] - lat_old[0]) * (new[1] - new[0]) /
             (lat_old[1] - lat_old[0])) + new[0]
        lon_old = (self.bounds[1], self.bounds[3])
        new = (0, w_h[0])
        x = ((lat_lon[1] - lon_old[0]) * (new[1] - new[0]) /
             (lon_old[1] - lon_old[0])) + new[0]
        # y must be reversed because the orientation of the image in the matplotlib.
        # image - (0, 0) in upper left corner; coordinate system - (0, 0) in lower left corner
        return int(x), int(y)  # w_h[1] - int(y)

    def set_origin(self, lat_lon):

        self.origin = self.scale_to_img(
            lat_lon, (int(self.width_meters), int(self.height_meters)))

    def get_ticks(self):
        """
        Generates custom ticks based on the GPS coordinates of the map for the matplotlib output.
        :return:
        """
        self.x_ticks = map(
            lambda x: round(x, 4),
            np.linspace(self.bounds[1], self.bounds[3], num=8))
        self.y_ticks = map(
            lambda x: round(x, 4),
            np.linspace(self.bounds[2], self.bounds[0], num=8))
        # Ticks must be reversed because the orientation of the image in the matplotlib.
        # image - (0, 0) in upper left corner; coordinate system - (0, 0) in lower left corner
        self.y_ticks = list(self.y_ticks)  # sorted(y_ticks, reverse=True)
        self.x_ticks = list(self.x_ticks)

class Results:
    '''
    Results class for saving run results
    to file with common format.
    '''

    def __init__(self, method_name='', global_start_time='', num_iters=0, plotting=False, config={}):
        self.num_iters = num_iters
        self.method_name = method_name
        self.global_start_time = global_start_time
        self.plotting = plotting
        if not isinstance(self.plotting, bool):
            if self.plotting in ('true', 'True'):
                self.plotting = True
            else:
                self.plotting = False
        self.native_plot = config.get('native_plot', 'false').lower()
        self.plot_every_n = int(config.get('plot_every_n', 1))
        self.make_gif = config.get('make_gif', 'false').lower()

        self.namefile = f'{RUN_DIR}/{method_name}/{global_start_time}_data.csv'
        self.plot_dir = config.get(
            'plot_dir', f'{RUN_DIR}/{method_name}/{global_start_time}')
        self.logdir = f'{RUN_DIR}/{method_name}/{global_start_time}_logs/'
        if self.make_gif == 'true':
            Path(self.plot_dir+'/png/').mkdir(parents=True, exist_ok=True)
            Path(self.plot_dir+'/gif/').mkdir(parents=True, exist_ok=True)
        Path(self.logdir).mkdir(parents=True, exist_ok=True)
        self.col_names = ['time', 'run_time', 'target_state', 'sensor_state',
                          'action', 'observation', 'reward', 'collisions', 'lost',
                          'r_err', 'theta_err', 'heading_err', 'centroid_err', 'rmse', 'mae', 'inference_times', 'pf_cov']

        self.pf_stats = defaultdict(list)
        self.abs_target_hist = []
        self.abs_sensor_hist = []
        self.target_hist = []
        self.sensor_hist = []
        self.sensor_gps_hist = []
        self.history_length = 50
        self.time_step = 0
        self.texts = []
        self.openstreetmap = None
        self.transform = None
        self.expected_target_rssi = None

        if config:
            write_header_log(config, self.method_name, self.global_start_time)

    def write_dataframe(self, run_data):
        """
        Save dataframe to CSV file
        """
        if os.path.isfile(self.namefile):
            print('Updating file {}'.format(self.namefile))
        else:
            print('Saving file to {}'.format(self.namefile))
        df = pd.DataFrame(run_data, columns=self.col_names)
        df.to_csv(self.namefile)

    def save_gif(self, run, sub_run=None):
        filename = run if sub_run is None else '{}_{}'.format(run, sub_run)
        # Build GIF
        with imageio.get_writer('{}/gif/{}.gif'.format(self.plot_dir, filename), mode='I', fps=5) as writer:
            for png_filename in sorted(os.listdir(self.plot_dir+'/png/'), key=lambda x: (len(x), x)):
                image = imageio.imread(self.plot_dir+'/png/'+png_filename)
                writer.append_data(image)

    def live_plot(self, env, time_step=None, fig=None, ax=None, data=None):
        """
        Create a live plot
        """
        if self.openstreetmap is None and data.get('position', None) is not None and data.get('bearing', None) is not None:
            self.openstreetmap = GPSVis(
                position=data['position']
                # map_path='map_delta_park.png',  # Path to map downloaded from the OSM.
                # bounds=(45.60311,-122.68450, 45.59494, -122.67505) # upper left, lower right
            )
            self.openstreetmap.set_origin(data['position'])
            self.transform = np.array(
                [self.openstreetmap.origin[0], self.openstreetmap.origin[1]])

        self.time_step = time_step
        self.pf_stats['mean_hypothesis'].append(
            env.pf.mean_hypothesis if hasattr(env.pf, 'mean_hypothesis') else [None])
        self.pf_stats['map_hypothesis'].append(
            env.pf.map_hypothesis if hasattr(env.pf, 'map_hypothesis') else [None])
        self.pf_stats['mean_state'].append(
            env.pf.mean_state if hasattr(env.pf, 'mean_state') else [None])
        self.pf_stats['map_state'].append(
            env.pf.map_state if hasattr(env.pf, 'map_state') else [None])

        abs_sensor = env.state.sensor_state
        abs_particles = env.get_absolute_particles()
        self.sensor_hist.append(abs_sensor)

        target_bearing = None
        target_relative_bearing = None

        if data.get('position', None) is not None and data.get('drone_position', None) is not None and data.get('bearing', None) is not None:
            target_bearing = get_bearing(
                data['position'], data['drone_position'])
            target_relative_bearing = target_bearing - data['bearing']
            target_distance = get_distance(
                data['position'], data['drone_position'])
            self.expected_target_rssi = env.sensor.observation(
                [[target_distance, target_relative_bearing, None, None]])[0]

        ax.clear()
        if self.openstreetmap is not None:
            self.openstreetmap.plot_map(axis1=ax)
        # TODO get variables
        ax.set_title('Time = {}, Frequency = {}, Bandwidth = {}, Gain = {}'.format(
            time_step, None, None, None))

        color_array = [['salmon', 'darkred', 'red'],
                       ['lightskyblue', 'darkblue', 'blue']]
        lines = []  # https://matplotlib.org/3.5.0/api/_as_gen/matplotlib.pyplot.legend.html

        # Plot Particles
        for t in range(env.state.n_targets):
            particles_x, particles_y = pol2cart(
                abs_particles[:, t, 0], np.radians(abs_particles[:, t, 1]))
            if self.transform is not None:
                particles_x += self.transform[0]
                particles_y += self.transform[1]
            line1, = ax.plot(particles_x, particles_y, 'o',
                             color=color_array[t][0], markersize=4, markeredgecolor='black', label='particles', alpha=0.3, zorder=1)

            if self.openstreetmap:
                heatmap, xedges, yedges = np.histogram2d(particles_x, particles_y, bins=(
                    self.openstreetmap.xedges, self.openstreetmap.yedges))
                heatmap = gaussian_filter(heatmap, sigma=8)
                extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]]
                im = ax.imshow(heatmap.T, extent=extent, origin='lower',
                               cmap='jet', interpolation='nearest', alpha=0.2)
                # plt.colorbar(im)

            centroid_x = np.mean(particles_x)
            centroid_y = np.mean(particles_y)
            line2, = ax.plot(centroid_x, centroid_y, '*', color='magenta',
                             markeredgecolor='black', label='centroid', markersize=12, zorder=2)

            if t == 0:
                lines.extend([line1, line2])
            else:
                lines.extend([])

        # Plot Sensor
        sensor_x, sensor_y = pol2cart(np.array(self.sensor_hist)[
                                      :, 0], np.radians(np.array(self.sensor_hist)[:, 1]))
        if self.transform is not None:
            sensor_x += self.transform[0]
            sensor_y += self.transform[1]
        if len(self.sensor_hist) > 1:
            ax.arrow(sensor_x[-2], sensor_y[-2], 4*(sensor_x[-1]-sensor_x[-2]),
                     4*(sensor_y[-1]-sensor_y[-2]), width=1.5, color='blue', zorder=4)
            ax.plot(sensor_x[:-1], sensor_y[:-1], linewidth=3.0,
                    color='blue', markeredgecolor='black', markersize=4, zorder=4)
        line4, = ax.plot(sensor_x[-1], sensor_y[-1], 'H',
                         color='blue', label='sensor', markersize=10, zorder=4)
        lines.extend([line4])

        if self.openstreetmap and data.get('drone_position', None) is not None:
            self.target_hist.append(self.openstreetmap.scale_to_img(
                data['drone_position'], (self.openstreetmap.width_meters, self.openstreetmap.height_meters)))
            target_np = np.array(self.target_hist)
            if len(self.target_hist) > 1:
                ax.plot(target_np[:, 0], target_np[:, 1], linewidth=3.0,
                        color='maroon', zorder=3, markersize=4)
            line5, = ax.plot(target_np[-1, 0], target_np[-1, 1], 'o', color='maroon',
                             markeredgecolor='black', label='target', markersize=10, zorder=3)
            lines.extend([line5])

        # Legend
        ax.legend(handles=lines, loc='upper left', bbox_to_anchor=(
            1.04, 1.0), fancybox=True, shadow=True, ncol=1)

        # X/Y Limits
        if self.openstreetmap is None:
            map_width = 600
            min_map = -1*int(map_width/2)
            max_map = int(map_width/2)
            ax.set_xlim(min_map, max_map)
            ax.set_ylim(min_map, max_map)

        # Sidebar Text
        # actual_str = r'$\bf{Actual}$''\n' # prettier format but adds ~0.04 seconds ???
        actual_str = 'Actual\n'
        actual_str += 'Bearing = {:.0f} deg\n'.format(data.get(
            'bearing', None)) if data.get('bearing', None) else 'Bearing = unknown\n'
        actual_str += 'Speed = {:.2f} m/s'.format(data.get('action_taken', None)[
                                                  1]) if data.get('action_taken', None) else 'Speed = unknown\n'

        proposal_str = 'Proposed\n'
        proposal_str += 'Bearing = {:.0f} deg\n'.format(data.get('action_proposal', None)[
                                                        0]) if None not in data.get('action_proposal', (None, None)) else 'Bearing = unknown\n'
        proposal_str += 'Speed = {:.2f} m/s'.format(data.get('action_proposal', None)[
                                                    1]) if None not in data.get('action_proposal', (None, None)) else 'Speed = unknown\n'

        last_mean_hyp = self.pf_stats['mean_hypothesis'][-1][0]
        last_map_hyp = self.pf_stats['map_hypothesis'][-1][0]

        rssi_str = 'RSSI\n'
        rssi_str += 'Observed = {:.1f} dB\n'.format(
            env.last_observation) if env.last_observation else 'Observed = unknown\n'
        rssi_str += 'Expected = {:.1f} dB\n'.format(
            self.expected_target_rssi) if self.expected_target_rssi else 'Expected = unknown\n'
        rssi_str += 'Difference = {:.1f} dB\n'.format(env.last_observation - self.expected_target_rssi) if (
            env.last_observation and self.expected_target_rssi) else ''
        #rssi_str += 'Target bearing = {} \n'.format(target_bearing) if target_bearing else ''
        #rssi_str += 'Target relative bearing = {} \n'.format(target_relative_bearing) if target_relative_bearing else ''
        rssi_str += 'MLE estimate = {:.1f} dB\n'.format(
            last_mean_hyp) if last_mean_hyp else 'MLE estimate = unknown'
        rssi_str += 'MAP estimate = {:.1f} dB'.format(
            last_map_hyp) if last_map_hyp else 'MAP estimate = unknown'

        if len(fig.texts) == 0:
            props = dict(boxstyle='round', facecolor='palegreen', alpha=0.5)
            text = fig.text(1.04, 0.75, actual_str, transform=ax.transAxes,
                            fontsize=14, verticalalignment='top', bbox=props)
            props = dict(boxstyle='round',
                         facecolor='paleturquoise', alpha=0.5)
            text = fig.text(1.04, 0.5, proposal_str, transform=ax.transAxes,
                            fontsize=14, verticalalignment='top', bbox=props)
            props = dict(boxstyle='round', facecolor='khaki', alpha=0.5)
            text = fig.text(1.04, 0.25, rssi_str, transform=ax.transAxes,
                            fontsize=14, verticalalignment='top', bbox=props)
        else:
            fig.texts[0].set_text(actual_str)
            fig.texts[1].set_text(proposal_str)
            fig.texts[2].set_text(rssi_str)

        self.native_plot = 'true' if time_step % self.plot_every_n == 0 else 'false'
        if self.native_plot == 'true':
            plt.draw()
            plt.pause(0.001)
        if self.make_gif == 'true':
            png_filename = '{}/png/{}.png'.format(self.plot_dir, time_step)
            print('saving plots in {}'.format(png_filename))
            plt.savefig(png_filename, bbox_inches='tight')

    def build_multitarget_plots(self, env, time_step=None, fig=None, axs=None, centroid_distance_error=None, selected_plots=[1, 2, 3, 4, 5], simulated=True, textstr=None):
        xp = env.state.target_state
        belief = env.pf.particles.reshape(
            len(env.pf.particles), env.state.n_targets, 4)
        #print('sensor state = ',env.state.sensor_state)
        abs_sensor = env.state.sensor_state

        abs_particles = env.get_absolute_particles()

        if simulated:
            abs_target = np.array(env.get_absolute_target())
        else:
            abs_target = None

        # these are matplotlib.patch.Patch properties
        props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)

        if len(self.abs_target_hist) < self.history_length:
            self.abs_target_hist = [abs_target] * self.history_length
            self.abs_sensor_hist = [abs_sensor] * self.history_length
        else:
            self.abs_target_hist.pop(0)
            self.abs_target_hist.append(abs_target)
            self.abs_sensor_hist.pop(0)
            self.abs_sensor_hist.append(abs_sensor)

        if len(self.target_hist) == 150:
            self.target_hist = []
            self.sensor_hist = []
            self.rel_sensor_hist = []

        self.target_hist.append(abs_target)
        self.sensor_hist.append(abs_sensor)

        plt.tight_layout()
        # Put space between plots
        plt.subplots_adjust(wspace=0.7, hspace=0.2)

        color_array = [['salmon', 'darkred', 'red'],
                       ['lightskyblue', 'darkblue', 'blue']]

        plot_count = 0
        if axs is None:
            axs = {}

        map_width = 600
        min_map = -1*int(map_width/2)
        max_map = int(map_width/2)
        cell_size = int((max_map - min_map)/max_map)
        cell_size = 2
        xedges = np.arange(min_map, max_map+cell_size, cell_size)
        yedges = np.arange(min_map, max_map+cell_size, cell_size)

        if 1 in selected_plots:
            # Plot 1: Particle Plot (Polar)
            plot_count += 1
            if 1 not in axs:
                axs[1] = fig.add_subplot(
                    1, len(selected_plots), plot_count, polar=True)
            ax = axs[1]
            ax.clear()

            for t in range(env.state.n_targets):
                # plot particles
                plot_theta = np.radians(belief[:, t, 1])
                plot_r = belief[:, t, 0]  # [row[0] for row in belief]

                ax.plot(plot_theta, plot_r, 'o', color=color_array[t][0], markersize=4,
                        markeredgecolor='black', label='particles', alpha=0.3, zorder=1)

                # plot targets
                plot_x_theta = np.radians(xp[t, 1])
                plot_x_r = xp[t, 0]

            ax.set_ylim(0, 300)
        if 2 in selected_plots:
            # Plot 2: Particle Plot (Polar) with Interpolation
            plot_count += 1
            if 2 not in axs:
                axs[2] = fig.add_subplot(
                    1, len(selected_plots), plot_count, polar=True)
            ax = axs[2]

            for t in range(env.state.n_targets):
                # Create grid values first via histogram.
                nbins = 10
                plot_theta = np.radians(belief[:, t, 1])
                plot_r = belief[:, t, 0]  # [row[0] for row in belief]
                counts, xbins, ybins = np.histogram2d(
                    plot_theta, plot_r, bins=nbins)
                # Make a meshgrid for theta, r values
                tm, rm = np.meshgrid(xbins[:-1], ybins[:-1])
                # Build contour plot
                ax.contourf(tm, rm, counts)
                # True position
                plot_x_theta = np.radians(xp[t, 1])
                plot_x_r = xp[t, 0]
                ax.plot(plot_x_theta, plot_x_r, 'X')

            ax.set_ylim(0, 300)
        if 3 in selected_plots:
            # Plot 3: Heatmap Plot (Cartesian)
            plot_count += 1
            if 3 not in axs:
                axs[3] = fig.add_subplot(1, len(selected_plots), plot_count)
            ax = axs[3]

            # COMBINED; UNCOMMENT AFTER PAPER PLOT
            all_particles_x, all_particles_y = [], []

            for t in range(env.state.n_targets):
                cart = np.array(
                    list(map(pol2cart, belief[:, t, 0], np.radians(belief[:, t, 1]))))
                x = cart[:, 0]
                y = cart[:, 1]
                all_particles_x.extend(x)
                all_particles_y.extend(y)

            heatmap, xedges, yedges = np.histogram2d(
                all_particles_x, all_particles_y, bins=(xedges, yedges))
            heatmap = gaussian_filter(heatmap, sigma=8)
            extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]]
            im = ax.imshow(heatmap.T, extent=extent, origin='lower',
                           cmap='jet', interpolation='nearest')
            plt.colorbar(im)
            ax.set_xlim(min_map, max_map)
            ax.set_ylim(min_map, max_map)
        if 4 in selected_plots:
            # Plot 4: Absolute Polar coordinates
            plot_count += 1
            if 4 not in axs:
                axs[4] = fig.add_subplot(
                    1, len(selected_plots), plot_count, polar=True)
            ax = axs[4]
            ax.clear()

            lines = []  # https://matplotlib.org/3.5.0/api/_as_gen/matplotlib.pyplot.legend.html
            for t in range(env.state.n_targets):
                particles_x, particles_y = pol2cart(
                    abs_particles[:, t, 0], np.radians(abs_particles[:, t, 1]))
                centroid_x = np.mean(particles_x)
                centroid_y = np.mean(particles_y)
                centroid_r, centroid_theta = cart2pol(centroid_x, centroid_y)
                target_r, target_theta, target_x, target_y = [], [], [], []

                for i in range(5):
                    target_r.append(
                        self.abs_target_hist[10*(i+1)-1][env.state.n_targets-1-t][0])
                    target_theta.append(np.radians(
                        self.abs_target_hist[10*(i+1)-1][env.state.n_targets-1-t][1]))
                target_x, target_y = pol2cart(target_r, target_theta)
                if len(self.target_hist) > 1:
                    ax.plot(np.radians(np.array(self.target_hist)[:-1, t, 1]), np.array(self.target_hist)[
                            :-1, t, 0], linewidth=4.0, color='limegreen', zorder=3, markersize=12)

                line0, = ax.plot(target_theta[4], target_r[4], 'X', color='limegreen',
                                 markeredgecolor='black', label='targets', markersize=20, zorder=4)

                line1, = ax.plot(np.radians(abs_particles[:, t, 1]), abs_particles[:, t, 0], 'o', color=color_array[t]
                                 [0], markersize=4, markeredgecolor='black', label='particles', alpha=0.3, zorder=1)
                if t == 0:
                    lines.extend([line0, line1])
                else:
                    lines.extend([line0])

            if len(self.sensor_hist) > 1:
                ax.plot(np.radians(np.array(self.sensor_hist)[:-1, 1]), np.array(self.sensor_hist)[
                        :-1, 0], linewidth=4.0, color='mediumorchid', zorder=3, markersize=12)

            line4, = ax.plot(np.radians(self.sensor_hist[-1][1]), self.sensor_hist[-1][0], 'H',
                             color='mediumorchid', markeredgecolor='black', label='sensor', markersize=20, zorder=3)
            lines.extend([line4])
            ax.legend(handles=lines, loc='center left', bbox_to_anchor=(
                1.08, 0.5), fancybox=True, shadow=True,)
            ax.set_ylim(0, 250)
        if 5 in selected_plots:
            # Plot 5: Absolute Cartesian coordinates
            plot_count += 1
            if 5 not in axs:
                axs[5] = fig.add_subplot(1, len(selected_plots), plot_count)
            ax = axs[5]

            xedges = np.arange(min_map, max_map, cell_size)
            yedges = np.arange(min_map, max_map, cell_size)
            heatmap_combined = None
            all_particles_x, all_particles_y = [], []
            for t in range(env.state.n_targets):

                particles_x, particles_y = pol2cart(
                    abs_particles[:, t, 0], np.radians(abs_particles[:, t, 1]))
                all_particles_x.extend(particles_x)
                all_particles_y.extend(particles_y)
                centroid_x = np.mean(particles_x)
                centroid_y = np.mean(particles_y)
                centroid_r, centroid_theta = cart2pol(centroid_x, centroid_y)
                target_r, target_theta, target_x, target_y = [], [], [], []
                for i in range(5):
                    target_r.append(self.abs_target_hist[10*(i+1)-1][t][0])
                    target_theta.append(np.radians(
                        self.abs_target_hist[10*(i+1)-1][t][1]))
                target_x, target_y = pol2cart(target_r, target_theta)

                ax.plot(centroid_x, centroid_y, '*',
                        label='centroid', markersize=12)

                ax.plot(target_x[4], target_y[4], 'X',
                        label='target', markersize=12)
            sensor_r, sensor_theta, sensor_x, sensor_y = [], [], [], []
            for i in range(5):
                sensor_r.append(self.abs_sensor_hist[10*(i+1)-1][0])
                sensor_theta.append(np.radians(
                    self.abs_sensor_hist[10*(i+1)-1][1]))
            sensor_x, sensor_y = pol2cart(sensor_r, sensor_theta)
            ax.plot(sensor_x[4], sensor_y[4], 'p',
                    label='sensor', markersize=12)

            heatmap, xedges, yedges = np.histogram2d(
                all_particles_x, all_particles_y, bins=(xedges, yedges))
            heatmap = gaussian_filter(heatmap, sigma=8)
            extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]]
            im = ax.imshow(heatmap.T, extent=extent, origin='lower',
                           cmap='jet', interpolation='nearest')
            plt.colorbar(im)

            ax.legend(loc='center left', bbox_to_anchor=(
                1.2, 0.5), fancybox=True, shadow=True,)
            ax.set_xlim(min_map, max_map)
            ax.set_ylim(min_map, max_map)
        if 6 in selected_plots:
            # Plot 1: Particle Plot (Polar)
            plot_count += 1
            if 6 not in axs:
                axs[6] = fig.add_subplot(1, len(selected_plots), plot_count)
            ax = axs[6]
            ax.clear()

            for t in range(env.state.n_targets):
                # plot particles
                plot_theta = np.radians(belief[:, t, 1])
                plot_r = belief[:, t, 0]
                particles_x, particles_y = pol2cart(
                    belief[:, t, 0], np.radians(belief[:, t, 1]))
                ax.plot(particles_x, particles_y, 'o',
                        color=color_array[t][0], markersize=4, markeredgecolor='black', label='particles', alpha=0.3, zorder=1)

                # plot targets
                plot_x_theta = np.radians(xp[t, 1])
                plot_x_r = xp[t, 0]

            ax.set_xlim(min_map, max_map)
            ax.set_ylim(min_map, max_map)

            sensor_x, sensor_y = pol2cart(
                self.sensor_hist[-1][0], np.radians(self.sensor_hist[-1][1]))
        if 7 in selected_plots:
            plot_count += 1
            if 7 not in axs:
                axs[7] = fig.add_subplot(1, len(selected_plots), plot_count)
            ax = axs[7]
            ax.clear()

            lines = []  # https://matplotlib.org/3.5.0/api/_as_gen/matplotlib.pyplot.legend.html
            for t in range(env.state.n_targets):
                particles_x, particles_y = pol2cart(
                    abs_particles[:, t, 0], np.radians(abs_particles[:, t, 1]))
                centroid_x = np.mean(particles_x)
                centroid_y = np.mean(particles_y)
                centroid_r, centroid_theta = cart2pol(centroid_x, centroid_y)
                target_r, target_theta, target_x, target_y = [], [], [], []

                for i in range(5):
                    target_r.append(
                        self.abs_target_hist[10*(i+1)-1][env.state.n_targets-1-t][0])
                    target_theta.append(np.radians(
                        self.abs_target_hist[10*(i+1)-1][env.state.n_targets-1-t][1]))
                target_x, target_y = pol2cart(target_r, target_theta)
                target_x, target_y = pol2cart(np.array(self.target_hist)[
                                              :, t, 0], np.radians(np.array(self.target_hist)[:, t, 1]))

                if len(self.target_hist) > 1:
                    ax.plot(target_x[:-1], target_y[:-1], linewidth=4.0,
                            color='limegreen', zorder=3, markersize=12)

                line0, = ax.plot(target_x[-1], target_y[-1], 'X', color='limegreen',
                                 markeredgecolor='black', label='targets', markersize=20, zorder=4)

                line1, = ax.plot(particles_x, particles_y, 'o',
                                 color=color_array[t][0], markersize=4, markeredgecolor='black', label='particles', alpha=0.3, zorder=1)
                #ax.plot(centroid_theta, centroid_r, '*', color=color_array[t][1],markeredgecolor='white', label='centroid', markersize=12, zorder=2)
                if t == 0:
                    lines.extend([line0, line1])
                else:
                    lines.extend([line0])

            sensor_x, sensor_y = pol2cart(np.array(self.sensor_hist)[
                                          :, 0], np.radians(np.array(self.sensor_hist)[:, 1]))
            if len(self.sensor_hist) > 1:
                ax.plot(sensor_x[:-1], sensor_y[:-1], linewidth=4.0,
                        color='mediumorchid', zorder=3, markersize=12)

            line4, = ax.plot(sensor_x[-1], sensor_y[-1], 'H', color='mediumorchid',
                             markeredgecolor='black', label='sensor', markersize=20, zorder=3)
            lines.extend([line4])
            ax.legend(handles=lines, loc='center left', bbox_to_anchor=(
                1.08, 0.5), fancybox=True, shadow=True,)

            ax.set_xlim(min_map, max_map)
            ax.set_ylim(min_map, max_map)
        if 8 in selected_plots:
            plot_count += 1
            if 8 not in axs:
                axs[8] = fig.add_subplot(1, len(selected_plots), plot_count)
            ax = axs[8]
            ax.clear()

            lines = []  # https://matplotlib.org/3.5.0/api/_as_gen/matplotlib.pyplot.legend.html
            for t in range(env.state.n_targets):
                particles_x, particles_y = pol2cart(
                    abs_particles[:, t, 0], np.radians(abs_particles[:, t, 1]))
                centroid_x = np.mean(particles_x)
                centroid_y = np.mean(particles_y)
                centroid_r, centroid_theta = cart2pol(centroid_x, centroid_y)

                line1, = ax.plot(particles_x, particles_y, 'o',
                                 color=color_array[t][0], markersize=4, markeredgecolor='black', label='particles', alpha=0.3, zorder=1)
                if t == 0:
                    lines.extend([line1])
                else:
                    lines.extend([])

            sensor_x, sensor_y = pol2cart(np.array(self.sensor_hist)[
                                          :, 0], np.radians(np.array(self.sensor_hist)[:, 1]))
            if len(self.sensor_hist) > 1:
                ax.plot(sensor_x[:-1], sensor_y[:-1], linewidth=4.0,
                        color='mediumorchid', zorder=3, markersize=12)

            line4, = ax.plot(sensor_x[-1], sensor_y[-1], 'H', color='mediumorchid',
                             markeredgecolor='black', label='sensor', markersize=20, zorder=3)
            lines.extend([line4])
            ax.legend(handles=lines, loc='upper center', bbox_to_anchor=(
                0.5, -0.05), fancybox=True, shadow=True, ncol=2)

            ax.set_xlim(min_map, max_map)
            ax.set_ylim(min_map, max_map)
            if textstr:
                props = dict(boxstyle='round',
                             facecolor='palegreen', alpha=0.5)
                ax.text(1.04, 0.75, textstr[0], transform=ax.transAxes,
                        fontsize=14, verticalalignment='top', bbox=props)
                props = dict(boxstyle='round',
                             facecolor='paleturquoise', alpha=0.5)
                ax.text(1.04, 0.5, textstr[1], transform=ax.transAxes,
                        fontsize=14, verticalalignment='top', bbox=props)

        png_filename = '{}/png/{}.png'.format(self.plot_dir, time_step)
        return axs

    def build_plots(self, xp=[], belief=[], abs_sensor=None, abs_target=None, abs_particles=None, time_step=None, fig=None, ax=None):
        print(belief.shape)
        if len(self.abs_target_hist) < self.history_length:
            self.abs_target_hist = [abs_target] * self.history_length
            self.abs_sensor_hist = [abs_sensor] * self.history_length
        else:
            self.abs_target_hist.pop(0)
            self.abs_target_hist.append(abs_target)
            self.abs_sensor_hist.pop(0)
            self.abs_sensor_hist.append(abs_sensor)

        fig = plt.figure(figsize=(30, 6))
        plt.tight_layout()
        # Put space between plots
        plt.subplots_adjust(wspace=0.2, hspace=0.2)

        # Plot 1: Particle Plot (Polar)
        ax = fig.add_subplot(1, 5, 1, polar=True)
        grid_r, grid_theta = [], []
        plot_r = [row[0] for row in belief]
        plot_theta = np.radians(np.array([row[1] for row in belief]))
        plot_x_theta = np.radians(xp[1])
        plot_x_r = xp[0]
        ax.plot(plot_theta, plot_r, 'ro')
        ax.plot(plot_x_theta, plot_x_r, 'bo')
        ax.set_ylim(-150, 150)
        ax.set_title('iteration {}'.format(time_step), fontsize=16)

        # Plot 2: Particle Plot (Polar) with Interpolation
        ax = fig.add_subplot(1, 5, 2, polar=True)
        # Create grid values first via histogram.
        nbins = 10
        counts, xbins, ybins = np.histogram2d(plot_theta, plot_r, bins=nbins)
        # Make a meshgrid for theta, r values
        tm, rm = np.meshgrid(xbins[:-1], ybins[:-1])
        # Build contour plot
        ax.contourf(tm, rm, counts)
        # True position
        ax.plot(plot_x_theta, plot_x_r, 'bo')
        ax.set_ylim(-150, 150)
        ax.set_title('Interpolated Belief'.format(time_step), fontsize=16)

        # Plot 3: Heatmap Plot (Cartesian)
        ax = fig.add_subplot(1, 5, 3)
        cart = np.array(
            list(map(pol2cart, belief[:, 0], np.radians(belief[:, 1]))))
        x = cart[:, 0]
        y = cart[:, 1]
        xedges = np.arange(-150, 153, 3)
        yedges = np.arange(-150, 153, 3)
        heatmap, xedges, yedges = np.histogram2d(x, y, bins=(xedges, yedges))
        heatmap = gaussian_filter(heatmap, sigma=5)
        extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]]
        im = ax.imshow(heatmap.T, extent=extent,
                       origin='lower', cmap='coolwarm')
        plt.colorbar(im)
        ax.set_xlim(-200, 200)
        ax.set_ylim(-200, 200)
        ax.set_title('Particle heatmap (relative to sensor)')

        # Plots 4 & 5: Absolute Particle/Sensor/Target Plot
        # particles/centroid coordinates
        particles_x, particles_y = pol2cart(
            abs_particles[:, 0], np.radians(abs_particles[:, 1]))
        centroid_x = np.mean(particles_x)
        centroid_y = np.mean(particles_y)
        centroid_r, centroid_theta = cart2pol(centroid_x, centroid_y)
        sensor_r, sensor_theta, sensor_x, sensor_y = [], [], [], []
        target_r, target_theta, target_x, target_y = [], [], [], []
        for i in range(5):
            sensor_r.append(self.abs_sensor_hist[10*(i+1)-1][0])
            sensor_theta.append(np.radians(
                self.abs_sensor_hist[10*(i+1)-1][1]))
            target_r.append(self.abs_target_hist[10*(i+1)-1][0])
            target_theta.append(np.radians(
                self.abs_target_hist[10*(i+1)-1][1]))
            sensor_x[i], sensor_y[i] = pol2cart(sensor_r, sensor_theta)
            target_x[i], target_y[i] = pol2cart(target_r, target_theta)

        # Plot 4: Absolute Polar coordinates
        ax = fig.add_subplot(1, 5, 4, polar=True)
        ax.plot(np.radians(
            abs_particles[:, 1]), abs_particles[:, 0], 'ro', label='particles', alpha=0.5)
        ax.plot(centroid_theta, centroid_r, 'c*',
                label='centroid', markersize=12)
        ax.plot(sensor_theta[4], sensor_r[4], 'gp',
                label='sensor', markersize=12)
        ax.plot(target_theta[4], target_r[4], 'bX',
                label='target', markersize=12)
        for i in range(4):
            ax.plot(sensor_theta[i], sensor_r[i],
                    'gp', markersize=6, alpha=0.75)
            ax.plot(target_theta[i], target_r[i],
                    'bX', markersize=6, alpha=0.75)
        ax.legend()
        ax.set_title('Absolute positions (polar)'.format(
            time_step), fontsize=16)

        # Plot 5: Absolute Cartesian coordinates
        ax = fig.add_subplot(1, 5, 5)
        xedges = np.arange(-100, 103, 3)
        yedges = np.arange(-100, 103, 3)
        heatmap, xedges, yedges = np.histogram2d(
            particles_x, particles_y, bins=(xedges, yedges))
        heatmap = gaussian_filter(heatmap, sigma=2)
        extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]]
        im = ax.imshow(heatmap.T, extent=extent,
                       origin='lower', cmap='coolwarm')
        plt.colorbar(im)
        ax.plot(centroid_x, centroid_y, 'c*', label='centroid', markersize=12)
        ax.plot(sensor_x[4], sensor_y[4], 'gp', label='sensor', markersize=12)
        ax.plot(target_x[4], target_y[4], 'bX', label='target', markersize=12)
        for i in range(4):
            ax.plot(sensor_x[i], sensor_y[i], 'gp', markersize=6, alpha=0.55)
            ax.plot(target_x[i], target_y[i], 'bX', markersize=6, alpha=0.55)
        ax.legend()
        ax.set_xlim(-150, 150)
        ax.set_ylim(-150, 150)
        ax.set_title('Absolute positions (cartesian)'.format(
            time_step), fontsize=16)

        r_error, theta_error, heading_error, centroid_distance_error, rmse, mae = tracking_error(
            abs_target, abs_particles)

        png_filename = '{}/png/{}.png'.format(self.plot_dir, time_step)
        print('saving plots in {}'.format(png_filename))
        plt.savefig(png_filename)
        plt.close(fig)

##################################################################
# Logging
##################################################################
def write_header_log(config, method, global_start_time):

    if type(config) == configparser.ConfigParser:
        config2log = {section: dict(config[section])
                      for section in config.sections()}
    else:
        config2log = dict(config)

    # write output header
    if not os.path.isdir(f'{RUN_DIR}/{method}/'):
        os.makedirs(f'{RUN_DIR}/{method}/')
    header_filename = f'{RUN_DIR}/{method}/{global_start_time}_header.txt'
    with open(header_filename, 'w', encoding='UTF-8') as f:
        f.write(json.dumps(config2log))

def read_header_log(filename):
    with open(filename, 'r', encoding='UTF-8') as f:
        config = json.load(f)
    return config

def particles_mean_belief(particles):
    particles_r = particles[:, 0]
    particles_theta = np.radians(particles[:, 1])
    particles_x, particles_y = pol2cart(particles_r, particles_theta)

    # centroid of particles x,y
    mean_x = np.mean(particles_x)
    mean_y = np.mean(particles_y)

    # centroid of particles r,theta
    mean_r, mean_theta = cart2pol(mean_x, mean_y)

    particles_heading = particles[:, 2]
    particles_heading_rad = np.radians(particles_heading)
    mean_heading_rad = np.arctan2(
        np.mean(np.sin(particles_heading_rad)), np.mean(np.cos(particles_heading_rad)))
    mean_heading = np.degrees(mean_heading_rad)

    mean_spd = np.mean(particles[:, 3])

    return particles_x, particles_y, mean_x, mean_y, mean_r, mean_theta, mean_heading, mean_spd

def particles_centroid_xy(particles):
    particles_r = particles[:, 0]
    particles_theta = np.radians(particles[:, 1])
    particles_x, particles_y = pol2cart(particles_r, particles_theta)

    # centroid of particles x,y
    mean_x = np.mean(particles_x)
    mean_y = np.mean(particles_y)

    return [mean_x, mean_y]

def angle_diff(angle):

    diff = angle % 360

    diff = (diff + 360) % 360

    diff[diff > 180] -= 360
    return diff

def tracking_error(all_targets, all_particles):
    """
    Calculate different tracking errors
    """
    results = []
    n_targets = len(all_particles[0])//4

    # reorder targets to fit closest particles
    min_distance = None
    optimal_target_permutation = None

    for idxs in list(permutations(range(n_targets))):
        target_permutation = all_targets[list(idxs)]

        distance = 0
        for t in range(n_targets):
            particle_centroid = np.array(
                particles_centroid_xy(all_particles[:, 4*t:4*(t+1)]))
            target = np.array(
                pol2cart(target_permutation[t][0], np.radians(target_permutation[t][1])))
            distance += np.linalg.norm(particle_centroid-target)**2
        if min_distance is None or distance < min_distance:
            min_distance = distance
            optimal_target_permutation = target_permutation

    for t in range(n_targets):
        target = optimal_target_permutation[t]
        particles = all_particles[:, 4*t:4*(t+1)]

        target_r = target[0]
        target_theta = np.radians(target[1])
        target_heading = target[2]
        target_x, target_y = pol2cart(target_r, target_theta)

        particles_x, particles_y, mean_x, mean_y, mean_r, mean_theta, mean_heading, mean_spd = particles_mean_belief(
            particles)

        r_error = np.mean(np.abs(target_r - particles[:, 0]))
        theta_error = np.mean(np.abs(angle_diff(target[1] - particles[:, 1])))
        heading_diff = np.abs(np.mean(target_heading - particles[:, 2])) % 360
        heading_error = heading_diff if heading_diff <= 180 else 360-heading_diff

        # centroid euclidean distance error x,y
        centroid_distance_error = np.sqrt(
            (mean_x - target_x)**2 + (mean_y - target_y)**2)

        mae = np.mean(np.sqrt((particles_x-target_x) **
                      2 + (particles_y - target_y)**2))

        # root mean square error
        rmse = np.sqrt(np.mean((particles_x - target_x) **
                       2 + (particles_y - target_y)**2))

        results.append([r_error, theta_error, heading_error,
                       centroid_distance_error, rmse, mae])
    results = np.array(results).T

    r_error = results[0]
    theta_error = results[1]
    heading_error = results[2]
    centroid_distance_error = results[3]
    rmse = results[4]
    mae = results[5]

    return r_error, theta_error, heading_error, centroid_distance_error, rmse, mae

max_stars_repo_name: ltindall/BirdsEye

max_issues_repo_name: ltindall/BirdsEye

max_forks_repo_name: ltindall/BirdsEye


text:
#
#  Licensed to the Apache Software Foundation (ASF) under one or more
#  contributor license agreements.  See the NOTICE file distributed with
#  this work for additional information regarding copyright ownership.
#  The ASF licenses this file to You under the Apache License, Version 2.0
#  (the "License"); you may not use this file except in compliance with
#  the License.  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.
#

import unittest
import datetime
import os

from ocw import dataset_processor as dp
from ocw import dataset as ds
from ocw.data_source import local
import numpy as np
import numpy.ma as ma

import logging
logging.basicConfig(level=logging.CRITICAL)

class TestEnsemble(unittest.TestCase):
    def test_unequal_dataset_shapes(self):
        self.ten_year_dataset = ten_year_monthly_dataset()
        self.two_year_dataset = two_year_daily_dataset()
        with self.assertRaises(ValueError):
            self.ensemble_dataset = dp.ensemble([self.ten_year_dataset, self.two_year_dataset])

    def test_ensemble_logic(self):
        self.datasets = []
        self.datasets.append(build_ten_cube_dataset(1))
        self.datasets.append(build_ten_cube_dataset(2))
        self.three = build_ten_cube_dataset(3)
        self.datasets.append(self.three)
        self.datasets.append(build_ten_cube_dataset(4))
        self.datasets.append(build_ten_cube_dataset(5))
        self.ensemble = dp.ensemble(self.datasets)
        self.ensemble_flat = self.ensemble.values.flatten()
        self.three_flat = self.three.values.flatten()
        np.testing.assert_array_equal(self.ensemble_flat, self.three_flat)

    def test_ensemble_name(self):
        self.ensemble_dataset_name = "Dataset Ensemble"
        self.datasets = []
        self.datasets.append(build_ten_cube_dataset(1))
        self.datasets.append(build_ten_cube_dataset(2))
        self.ensemble = dp.ensemble(self.datasets)
        self.assertEquals(self.ensemble.name, self.ensemble_dataset_name)

class TestTemporalRebin(unittest.TestCase):

    def setUp(self):
        self.ten_year_monthly_dataset = ten_year_monthly_dataset()
        self.ten_year_annual_times = np.array([datetime.datetime(year, 7, 2) for year in range(2000, 2010)])
        self.two_years_daily_dataset = two_year_daily_dataset()

    def test_monthly_to_annual_rebin(self):
        annual_dataset = dp.temporal_rebin(self.ten_year_monthly_dataset, "annual")
        np.testing.assert_array_equal(annual_dataset.times, self.ten_year_annual_times)

    def test_monthly_to_full_rebin(self):
        full_dataset = dp.temporal_rebin(self.ten_year_monthly_dataset, "full")
        full_times = [datetime.datetime(2005, 1, 1)]
        self.assertEqual(full_dataset.times, full_times)

    def test_daily_to_monthly_rebin(self):
        """This test takes a really long time to run.  TODO: Figure out where the performance drag is"""
        monthly_dataset = dp.temporal_rebin(self.two_years_daily_dataset, "monthly")
        bins = list(set([datetime.datetime(time_reading.year, time_reading.month, 15) for time_reading in self.two_years_daily_dataset.times]))
        bins = np.array(bins)
        bins.sort()
        np.testing.assert_array_equal(monthly_dataset.times, bins)

    def test_daily_to_annual_rebin(self):
        annual_dataset = dp.temporal_rebin(self.two_years_daily_dataset, "annual")
        bins = list(set([datetime.datetime(time_reading.year, 7, 2) for time_reading in self.two_years_daily_dataset.times]))
        bins = np.array(bins)
        bins.sort()
        np.testing.assert_array_equal(annual_dataset.times, bins)

    def test_non_rebin(self):
        """This will take a monthly dataset and ask for a monthly rebin of 28 days.  The resulting
        dataset should have the same time values"""
        monthly_dataset = dp.temporal_rebin(self.ten_year_monthly_dataset, "monthly")
        bins = list(set([datetime.datetime(time_reading.year, time_reading.month, 15) for time_reading in self.ten_year_monthly_dataset.times]))
        bins = np.array(bins)
        bins.sort()
        np.testing.assert_array_equal(monthly_dataset.times, bins)

    def test_variable_propagation(self):
        annual_dataset = dp.temporal_rebin(self.ten_year_monthly_dataset,
                                           "annual")
        self.assertEquals(annual_dataset.name,
                          self.ten_year_monthly_dataset.name)
        self.assertEquals(annual_dataset.variable,
                          self.ten_year_monthly_dataset.variable)

class TestRcmesSpatialRegrid(unittest.TestCase):

    def test_return_array_shape(self):
        spatial_values = np.ones([90,180])
        spatial_values = ma.array(spatial_values)

        lat_range = ma.array(range(-89, 90, 2))
        lon_range = ma.array(range(-179, 180, 2))

        lons, lats = np.meshgrid(lon_range, lat_range)
        # Convert these to masked arrays
        lats = ma.array(lats)
        lons = ma.array(lons)

        lat2_range = np.array(range(-89, 90, 4))
        lon2_range = np.array(range(-179, 180, 4))

        lons2, lats2 = np.meshgrid(lon2_range, lat2_range)
        # Convert to masked arrays
        lats2 = ma.array(lats2)
        lons2 = ma.array(lons2)

        regridded_values = dp._rcmes_spatial_regrid(spatial_values, lats, lons, lats2, lons2)
        self.assertEqual(regridded_values.shape, lats2.shape)
        self.assertEqual(regridded_values.shape, lons2.shape)

class TestSpatialRegrid(unittest.TestCase):

    def setUp(self):
        self.input_dataset = ten_year_monthly_dataset()
        self.new_lats = np.array(range(-89, 90, 4))
        self.new_lons = np.array(range(-179, 180, 4))
        self.regridded_dataset = dp.spatial_regrid(self.input_dataset, self.new_lats, self.new_lons)

    def test_returned_lats(self):
        np.testing.assert_array_equal(self.regridded_dataset.lats, self.new_lats)

    def test_returned_lons(self):
        np.testing.assert_array_equal(self.regridded_dataset.lons, self.new_lons)

    def test_shape_of_values(self):
        regridded_data_shape = self.regridded_dataset.values.shape
        expected_data_shape = (len(self.input_dataset.times), len(self.new_lats), len(self.new_lons))
        self.assertSequenceEqual(regridded_data_shape, expected_data_shape)

    def test_variable_propagation(self):
        self.assertEquals(self.input_dataset.name, self.regridded_dataset.name)
        self.assertEquals(self.input_dataset.variable, self.regridded_dataset.variable)

class TestNormalizeDatasetDatetimes(unittest.TestCase):
    def setUp(self):
        self.monthly_dataset = ten_year_monthly_15th_dataset()
        self.daily_dataset = two_year_daily_2hr_dataset()

    def test_daily(self):
        new_ds = dp.normalize_dataset_datetimes(self.monthly_dataset, 'daily')

        # Check that all the days have been shifted to the first of the month
        self.assertTrue(all(x.hour == 0 for x in new_ds.times))

    def test_montly(self):
        new_ds = dp.normalize_dataset_datetimes(self.monthly_dataset, 'monthly')

        # Check that all the days have been shifted to the first of the month
        self.assertTrue(all(x.day == 1 for x in new_ds.times))

class TestSubset(unittest.TestCase):
    def setUp(self):
        self.target_dataset = ten_year_monthly_dataset()
        self.name = 'foo'

        self.subregion = ds.Bounds(
            -81, 81,
            -161, 161,
            datetime.datetime(2001, 1, 1),
            datetime.datetime(2004, 1, 1)
        )
        self.non_exact_spatial_subregion = ds.Bounds(
            -80.25, 80.5,
            -160.25, 160.5,
            datetime.datetime(2001, 1, 1),
            datetime.datetime(2004, 1, 1)
        )
        self.non_exact_temporal_subregion = ds.Bounds(
            -80.25, 80.5,
            -160.25, 160.5,
            datetime.datetime(2001, 1, 15),
            datetime.datetime(2004, 2, 15)
        )

    def test_subset(self):
        subset = dp.subset(self.subregion, self.target_dataset)
        self.assertEqual(subset.lats.shape[0], 82)
        self.assertSequenceEqual(list(np.array(range(-81, 82, 2))),
                list(subset.lats))
        self.assertEqual(subset.lons.shape[0], 162)
        self.assertEqual(subset.times.shape[0], 37)
        self.assertEqual(subset.values.shape, (37, 82, 162))

    def test_subset_name(self):
        subset = dp.subset(self.subregion, self.target_dataset)
        self.assertEqual(subset.name, self.name)

    def test_subset_name_propagation(self):
        subset_name = 'foo_subset_name'
        subset = dp.subset(self.subregion, self.target_dataset,subset_name)
        self.assertEqual(subset.name, subset_name)

    def test_subset_using_non_exact_spatial_bounds(self):
        index_slices = dp._get_subregion_slice_indices(self.non_exact_spatial_subregion,  self.target_dataset)
        control_index_slices = {"lat_start"  : 5,
                                "lat_end"    : 84,
                                "lon_start"  : 10,
                                "lon_end"    : 169,
                                "time_start" : 12,
                                "time_end"   : 48}
        self.assertDictEqual(index_slices, control_index_slices)

    def test_subset_using_non_exact_temporal_bounds(self):
        index_slices = dp._get_subregion_slice_indices(self.non_exact_temporal_subregion,  self.target_dataset)
        control_index_slices = {"lat_start"  : 5,
                                "lat_end"    : 84,
                                "lon_start"  : 10,
                                "lon_end"    : 169,
                                "time_start" : 13,
                                "time_end"   : 49}
        self.assertDictEqual(index_slices, control_index_slices)

class TestSafeSubset(unittest.TestCase):
    def setUp(self):
        lats = np.array(range(-60, 61, 1))
        lons = np.array(range(-170, 171, 1))
        times = np.array([datetime.datetime(year, month, 1)
                          for year in range(2000, 2010)
                          for month in range(1, 13)])
        values = np.ones([len(times), len(lats), len(lons)])
        self.target_dataset = ds.Dataset(lats,
                                         lons,
                                         times,
                                         values,
                                         variable="test variable name",
                                         units='test variable units',
                                         name='foo')

        self.spatial_out_of_bounds = ds.Bounds(
            -165, 165,
            -180, 180,
            datetime.datetime(2001, 1, 1),
            datetime.datetime(2004, 1, 1)
        )

        self.temporal_out_of_bounds = ds.Bounds(
            -40, 40,
            -160.25, 160.5,
            datetime.datetime(1999, 1, 15),
            datetime.datetime(2222, 2, 15)
        )

        self.everything_out_of_bounds = ds.Bounds(
            -165, 165,
            -180, 180,
            datetime.datetime(1999, 1, 15),
            datetime.datetime(2222, 2, 15)
        )

    def test_partial_spatial_overlap(self):
        '''Ensure that safe_subset can handle out of bounds spatial values'''
        ds = dp.safe_subset(self.spatial_out_of_bounds, self.target_dataset)
        spatial_bounds = ds.spatial_boundaries()
        self.assertEquals(spatial_bounds[0], -60)
        self.assertEquals(spatial_bounds[1], 60)
        self.assertEquals(spatial_bounds[2], -170)
        self.assertEquals(spatial_bounds[3], 170)

    def test_partial_temporal_overlap(self):
        '''Ensure that safe_subset can handle out of bounds temporal values'''
        ds = dp.safe_subset(self.temporal_out_of_bounds, self.target_dataset)
        temporal_bounds = ds.time_range()
        start = datetime.datetime(2000, 1, 1)
        end = datetime.datetime(2009, 12, 1)

        self.assertEquals(temporal_bounds[0], start)
        self.assertEquals(temporal_bounds[1], end)

    def test_entire_bounds_overlap(self):
        ds = dp.safe_subset(self.everything_out_of_bounds, self.target_dataset)
        spatial_bounds = ds.spatial_boundaries()
        temporal_bounds = ds.time_range()
        start = datetime.datetime(2000, 1, 1)
        end = datetime.datetime(2009, 12, 1)

        self.assertEquals(spatial_bounds[0], -60)
        self.assertEquals(spatial_bounds[1], 60)
        self.assertEquals(spatial_bounds[2], -170)
        self.assertEquals(spatial_bounds[3], 170)
        self.assertEquals(temporal_bounds[0], start)
        self.assertEquals(temporal_bounds[1], end)

class TestFailingSubset(unittest.TestCase):
    def setUp(self):
        self.target_dataset = ten_year_monthly_dataset()
        self.target_dataset.lats = np.array(range(-89, 88, 2))
        self.target_dataset.lons = np.array(range(-179, 178, 2))

        self.subregion = ds.Bounds(
            -81, 81,
            -161, 161,
            datetime.datetime(2001, 1, 1),
            datetime.datetime(2004, 1, 1)
        )

    def test_out_of_dataset_bounds_lat_min(self):
        self.subregion.lat_min = -90
        with self.assertRaises(ValueError):
            dp.subset(self.subregion, self.target_dataset)

    def test_out_of_dataset_bounds_lat_max(self):
        self.subregion.lat_max = 90
        with self.assertRaises(ValueError):
            dp.subset(self.subregion, self.target_dataset)

    def test_out_of_dataset_bounds_lon_min(self):
        self.subregion.lon_min = -180
        with self.assertRaises(ValueError):
            dp.subset(self.subregion, self.target_dataset)

    def test_out_of_dataset_bounds_lon_max(self):
        self.subregion.lon_max = 180
        with self.assertRaises(ValueError):
            dp.subset(self.subregion, self.target_dataset)

    def test_out_of_dataset_bounds_start(self):
        self.subregion.start = datetime.datetime(1999, 1, 1)
        with self.assertRaises(ValueError):
            dp.subset(self.subregion, self.target_dataset)

    def test_out_of_dataset_bounds_end(self):
        self.subregion.end = datetime.datetime(2011, 1, 1)
        with self.assertRaises(ValueError):
            dp.subset(self.subregion, self.target_dataset)

class TestNetCDFWrite(unittest.TestCase):
    def setUp(self):
        self.ds = ten_year_monthly_dataset()
        self.file_name = 'test.nc'

    def tearDown(self):
        if os.path.isfile(self.file_name):
            os.remove(self.file_name)

    def test_file_write(self):
        dp.write_netcdf(self.ds, self.file_name)
        self.assertTrue(os.path.isfile(self.file_name))

    def test_that_file_contents_are_valid(self):
        dp.write_netcdf(self.ds, self.file_name)
        new_ds = local.load_file(self.file_name, self.ds.variable)

        self.assertEqual(self.ds.variable, new_ds.variable)
        np.testing.assert_array_equal(self.ds.lats, new_ds.lats)
        np.testing.assert_array_equal(self.ds.lons, new_ds.lons)
        np.testing.assert_array_equal(self.ds.times, new_ds.times)
        np.testing.assert_array_equal(self.ds.values, new_ds.values)

def ten_year_monthly_dataset():
    lats = np.array(range(-89, 90, 2))
    lons = np.array(range(-179, 180, 2))
    # Ten Years of monthly data
    times = np.array([datetime.datetime(year, month, 1) for year in range(2000, 2010) for month in range(1, 13)])
    values = np.ones([len(times), len(lats), len(lons)])
    input_dataset = ds.Dataset(lats, lons, times, values, variable="test variable name", units='test variable units', name='foo')
    return input_dataset

def ten_year_monthly_15th_dataset():
    lats = np.array(range(-89, 90, 2))
    lons = np.array(range(-179, 180, 2))
    # Ten Years of monthly data
    times = np.array([datetime.datetime(year, month, 1) for year in range(2000, 2010) for month in range(1, 13)])
    values = np.ones([len(times), len(lats), len(lons)])
    input_dataset = ds.Dataset(lats, lons, times, values, variable="test variable name", units='test variable units')
    return input_dataset

def two_year_daily_dataset():
    lats = np.array(range(-89, 90, 2))
    lons = np.array(range(-179, 180, 2))
    times = np.array([datetime.datetime(2001, 1, 1) + datetime.timedelta(days=d) for d in range(730)])
    values = np.ones([len(times), len(lats), len(lons)])
    dataset = ds.Dataset(lats, lons, times, values, variable='random data',units='test variable units')
    return dataset

def two_year_daily_2hr_dataset():
    lats = np.array(range(-89, 90, 2))
    lons = np.array(range(-179, 180, 2))
    times = np.array([datetime.datetime(2001, 1, 1) + datetime.timedelta(days=d, hours=2) for d in range(730)])
    values = np.ones([len(times), len(lats), len(lons)])
    dataset = ds.Dataset(lats, lons, times, values, variable='random data', units='test variable units')
    return dataset

def build_ten_cube_dataset(value):
    lats = np.array(range(-89, 90, 18))
    lons = np.array(range(-179, 180, 36))
    times = np.array([datetime.datetime(year, 1, 1) for year in range(2000, 2010)])
    values = np.ones([len(times), len(lats), len(lons)])
    values = values * value
    dataset = ds.Dataset(lats, lons, times, values)
    return dataset

if __name__ == '__main__':
    unittest.main()

ext: py

max_stars_repo_name: NunoEdgarGFlowHub/climate

max_issues_repo_name: NunoEdgarGFlowHub/climate

max_forks_repo_name: NunoEdgarGFlowHub/climate

reason: import numpy


text:
#!/usr/bin/python3
#Paquetes
import numpy as np
from numpy.random import randint
from PIL import Image
from bitstring import BitArray
import matplotlib.pyplot as plt

class modulation():

	'''
	Esta es una clase que contiene los
	metodos necesarios para implementar
	un modulador PAM, con medio ideal y
	ruidoso, asi como un demodulador.
	Debe usarse junto a las clases
	source() y sys_com() de las sim-
	mulacuones anteriores para ensamblar
	el sistema de comunicaciones completo
	'''

    #El constructor:
	def __init__(self, m, k, n):

		#numero de paquetes 1 x k:
		self.m = m

		#dimension de cada paquete de bits:
		self.k = k

		#dimension de paquetes 1 x n:
		self.n = n # n > k

	#================METODOS==================

	'''
	Se crea una funcion que le asigna simbolos a
	cada secuencia de bits que sale del canal bcT
	se sabe que M=2^k siendo k=16. M=65536. Aqui
	k es n, es la salida del codificador de canal
	'''
	def symbol_modulator(self, bcT):
		x, y = bcT.shape
		'''
		se pasa el vector de bits obtenido en el
		canal a senal codigo se pasan de bits a
		números del 0 a 2^16.
		'''
		an = []
		for i in range(x):
			 decimal = BitArray(bcT[i])
			 an.append(decimal.uint)

		return an
	#==========================================

	'''
	Funcion para simular la senal PAM que va ser
	transmitida por el medio. Para simplificacion,
	solo se toman los primeros 15 simbolos de an
	y se repiten 30 veces cada una para que se
	vea bien la grafica
	'''
	def PAM(self,an):
		dt = 0.1
		t = np.arange(0, 45, dt)
		p = []
		for i in range(15):
		    an[i]
		    for j in range(30):
		        p.append(an[i])
		plt.plot(t,p)
		plt.xlabel('Tiempo [s]')
		plt.ylabel('Amplitud')
		plt.title('Señal modulada PAM')
		plt.show()

	#===========================================
	'''
	Un metodo que simula un medio de
	transmision ruidoso. Pide por
	parametro an, que corresponde a
	la secuencia de simbolos y N,
	el porcentaje de ruido deseado
	entre [0 - 100]
	'''
	def noised_transmitter(self, an, N):
		#cantidad de ruido
		noise = round(len(an) * (N / 100))

		#simbolos aleatorios
		a = randint(0, 2**16, size = (noise, 1))
		symbs = a.transpose()[0]

		#indices aleatorios
		b = randint(0, self.m, size = (noise, 1))
		index = b.transpose()[0]

		#insertando errores en an:
		k = 0
		for i in index:
			an[i] = symbs[k]
			k += 1

		return an

	#=============================================
	def symbol_demodulator(self, an):
		x = []; bits_sec = []
		#pasa de decimal a binario con 16 bits:
		for i in range(len(an)):
			x.append(bin(an[i])[2:].zfill(16))

		#Se pasan a vectores tipo enteros:
		for i in range(len(x)):
			bits_sec.append([int(i) for i in x[i]])
		'''
		se ordena en una matriz de tal forma
		que de igual a bcT:
		'''
		yn = np.reshape(bits_sec,(len(x), 16))

		return yn
	#==============================================

reason: import numpy,from numpy


text:
import numpy as np
from PIL import Image
from scipy import ndimage, interpolate, signal

def ndarray2img(input, width=4096, height=4096, range_x=None, range_y=None):
    channel_num = 3  # RGB
    if range_x == None:
        range_x = (np.min(input[:, 0]), np.max(input[:, 0]))
    if range_y == None:
        range_y = (np.min(input[:, 1]), np.max(input[:, 1]))
    xx = np.linspace(np.min(range_x), np.max(range_x), width)
    yy = np.linspace(np.min(range_y), np.max(range_y), height)
    grid_x, grid_y = np.meshgrid(xx, yy)

    # Color
    colors = np.ndarray((input.shape[0], channel_num))
    # Detect color schema
    if np.sum(input[0, 4:7]) / 3 > np.sum(input[0, 3]):
        # RGB
        colors[:, 0:3] = input[:, 4:7]
    else:
        # Intensity to RGB
        for i in range(channel_num):
            colors[:, i] = input[:, 3]

    grids = []
    for i in range(channel_num):
        color = colors[:, i]
        grid = interpolate.griddata(
            input[:, 0:2], color, (grid_x, grid_y), method='nearest') * 255
        grids.append(grid.reshape(grid.shape + (1,)))

    # Alpha
    alpha, _, _ = np.histogram2d(input[:, 0], input[:, 1],
                                 range=[range_x, range_y],
                                 bins=[width, height])
    alpha[alpha > 0] = 255
    # alpha = signal.medfilt(alpha, kernel_size=3)
    alpha = alpha.reshape(width, height, 1)
    alpha = np.fliplr(ndimage.rotate(alpha, 270))
    grids.append(alpha)

    rgbarray = np.concatenate(grids, axis=2).astype(np.uint8)
    img = Image.fromarray(ndimage.rotate(np.fliplr(rgbarray), 180))
    return img, xx, yy

reason: import numpy,from scipy


text:
import numpy as np
from vispy import scene, app
from vispy.util import keys
from .color_scheme import palette
# from ..base.CLU import CLU
from ..view import Picker
from ..utils import Timer
from itertools import cycle
from vispy.color import get_colormaps, BaseColormap

opaque_cmaps = cycle(get_colormaps())
opaque_cmap = next(opaque_cmaps)

class TransGrays(BaseColormap):
    def __init__(self, alpha):
        self.colors = [(1.0, 1.0, 1.0, alpha),]

        self.glsl_map = """
        vec4 translucent_grays(float t) {
            return vec4(t, t, t, $color_0[3]*t);
        }
        """

        self.glsl_map = self.glsl_map.replace('$color_0[3]', str(alpha))

class volume_view(scene.SceneCanvas):

    def __init__(self, nvbs=1, show=False, debug=False):
        scene.SceneCanvas.__init__(self, size=(800, 600), keys='interactive')

        self.unfreeze()
        self.grid = self.central_widget.add_grid()
        self.grid.unfreeze()

        self.vbs = {}
        self.vol = {}
        self.data = {}

        self._transparency = 0.03
        self._control_transparency = False
        self.key_option = 0

        for i in range(nvbs):
            self.init_vb(i)

        # self._timer = app.Timer(0.0)
        # self._timer.connect(self.on_timer)
        # self._timer.start()

        # TODO: for Picker

        # Add a 3D axis to keep us oriented
        # scene.visuals.XYZAxis(parent=self.view.scene)
        if show is True:
            self.show()

    def __call__(self, nvbs=1):
        self.unfreeze()
        self.grid = self.central_widget.add_grid()
        self.vbs = {}
        self.vol = {}
        self.data = {}
        for i in range(nvbs):
            self.init_vb(i)

        for i in range(nvbs):
            self.init_vb(i)

    def init_vb(self, i):
        self.vbs[i] = self.grid.add_view(name='vb'+str(i), border_color=palette[i])
        self.vbs[i].camera = 'turntable'
        self.vol[i] = scene.visuals.Volume()
        self.vol[i].unfreeze()
        self.vol[i].method = 'translucent'
        self.vol[i].cmap = TransGrays(alpha=self._transparency)
        # self.vol[i].cmap = opaque_cmap
        self.vbs[i].add(self.vol[i])

    def set_data(self, data, vb_id=0, clim=None):
        # volumetric data for example: data.shape = (128,128,128)

        self.data[vb_id] = data
        self.vol[vb_id].set_data(data, clim)
        cam = scene.cameras.TurntableCamera(parent=self.vbs[vb_id].scene, fov=60)
        self.vbs[vb_id].camera = cam

    @property
    def transparency(self):
        return self._transparency

    @transparency.setter
    def transparency(self, v):
        self._transparency = v
        if self._transparency >= 0.99:
            self._transparency = 0.99
        elif self._transparency <= 0.001:
            self._transparency = 0.001

        for _vol in self.vol.values():
            # _vol.method = 'translucent'
            _vol.cmap = TransGrays(alpha=self._transparency)

    # def on_mouse_wheel(self, e):
    #     if keys.CONTROL in e.modifiers:
    #         self.transparency *= np.exp(e.delta[1]/4)

    def on_key_press(self, e):

        # if e.key.name == 'Escape':
        #     self.clu.select(np.array([]))

        if e.text == '/':
            for _vol in self.vol.values():
                if _vol.method == 'translucent':
                    _vol.method = 'mip'
                    self.transparency = 1
                else:
                    _vol.method = 'translucent'
                    self.transparency = 0.03

        if e.text == '=':
            self.transparency += 0.0025

        if e.text == '-':
            self.transparency -= 0.0025

        # if keys.CONTROL in e.modifiers and not self._control_transparency:
        #     self.view.events.mouse_wheel.disconnect(self.view.camera
        #             .viewbox_mouse_event)
        #     self._control_transparency = not self._control_transparency
        # self.key_option = e.key.name
                # _vol.cmap = TransGrays(alpha=0.01)

        # if e.text == 'd':
        #     self.mode = 'dimension'
        #     self.dimension = []

        # if self.mode == 'dimension':
        #     if e.text.isdigit() and len(self.dimension)<3:
        #         self.dimension.append(int(e.text))
        #         self.dimension_text.text = str(self.dimension)
        #         if len(self.dimension)==3:
        #             self.set_dimension(self.dimension)

        # if self.mode != 'dimension':
        #     if e.text == 'e':
        #         self.toggle_noise_clu()

    # def on_key_release(self, e):
    #     if self._control_transparency:
    #         self.view.events.mouse_wheel.connect(self.view.camera.viewbox_mouse_event)
    #         self._control_transparency = not self._control_transparency
    #     self.key_option = 0

max_stars_repo_name: aliddell/spiketag

max_issues_repo_name: aliddell/spiketag

max_forks_repo_name: aliddell/spiketag


text:
"""
    Implementation of activation functions along with
    their derivatives
"""

import math
import numpy as np

def sigmoid(x, deri=False):
    """
        Sigmoid activation function:
        Parameters:
            x    (array)  : A numpy array
            deri (boolean): If set to True function calulates the derivative of sigmoid
        Returns:
            x    (array)  : Numpy array after applying the approprite function
    """
    if deri:
        return x*(1-x)
    else:
        return 1/(1+np.exp(-x))

def relu(x,deri=False):
    if deri:
        x[x<=0] = 0
        x[x>0] = 1
        return x
    else:
        return np.maximum(0,x)

def softmax(X, deri=False):
    if deri:
        return np.multiply( X, 1 - X ) + sum(
            # handle the off-diagonal values
            - X * np.roll( X, i, axis = 1 )
            for i in range(1, X.shape[1] )
        )
    else:
        expo = np.exp(X)
        expo_sum = np.sum(np.exp(X))
        return expo/expo_sum

def apply(array,activation,deriv=False):
    if activation=='sigmoid':
        return sigmoid(array,deriv)

    if activation=='relu':
        return relu(array,deriv)

    if activation=='softmax':
        return softmax(array,deriv)

    else:
        print("Invalid activation using linear")
        return array

max_stars_repo_name: bit-shashank/tinn

max_issues_repo_name: bit-shashank/tinn

max_forks_repo_name: bit-shashank/tinn


text:
# coding: utf-8

import sys
sys.path.append('..')
import numpy as np
from common.optimizer import SGD
from dataset import spiral
import matplotlib.pyplot as plt
from my_two_layer_net import TwoLayerNet

# ハイパラ
max_epoch = 300
batch_size = 30
hidden_size = 10
learning_rate = 1.0

# load, make model & optimizer
x, t = spiral.load_data()
model = TwoLayerNet(input_size=2, hidden_size=hidden_size, output_size=3)
optimizer = SGD(lr=learning_rate)

# variable for train
data_size = len(x)
max_iters = data_size // batch_size # 切捨て除算。ミニバッチ内のキリが良いデータ数
total_loss = 0
loss_count = 0
loss_list = []

for epoch in range(max_epoch):
    # shuffle data
    idx = np.random.permutation(data_size) # ランダムに並び替える
    x = x[idx]
    t = t[idx]

    for iters in range(max_iters):
        batch_x = x[iters*batch_size:(iters+1)*batch_size] # ミニバッチを取り出す
        batch_t = t[iters*batch_size:(iters+1)*batch_size]

        # grad & update params
        loss = model.forward(batch_x, batch_t)
        model.backward()
        optimizer.update(model.params, model.grads)

        total_loss += loss
        loss_count += 1

        # 定期的に学習結果を出力
        if (iters+1) % 10 == 0: # ミニバッチの区切りが10の倍数になったら
            avg_loss = total_loss / loss_count
            # print('| epoch %d | iter %d / %d | loss %.2f' % (epoch+1, iters+1, max_iters, avg_loss))
            loss_list.append(avg_loss)
            total_loss, loss_count = 0, 0

plt.plot(loss_list)
plt.show()