import sys

# Step 0: Check Python version. NRPy+ is untested below Python 2.7-ish, but is compatible with 2.7+ and 3+
PYTHONVERSION3 = False
if sys.version_info[0]==2:
    if sys.version_info[1]<4:
        print("Sorry, NRPy won't work with Python < 2.4; sorting functs won't work. See https://docs.python.org/3/howto/sorting.html for details.")
        sys.exit(1)
if sys.version_info[0]==3:
    PYTHONVERSION3 = True

# Step 1: Print logo.
from NRPy_logo import *
#print_logo()

# Step 2: Initialize core parameter NRPy::MainModule,
#         which defines the desired main module.
#         E.g., scalarwave, BSSN_RHSs, BSSN_InitialData, etc.
# Contains parameter initialization, manipulation, and read-in routines
import NRPy_param_funcs as par

# Used to import needed modules dynamically
import importlib

# Initialize the MainModule parameter.
# This is the ONLY parameter initialized outside of a module!
MainModule = "scalarwave" # Default. To be overwritten later.
par.initialize_param(par.glb_param("char","NRPy","MainModule",MainModule))

# Step 4: Initialize NRPy+ as desired.

# Step 4a: Enter Interactive Mode if NRPy+ is run via
#   `python nrpy.py`
if(len(sys.argv) == 1):
    print("/* Run `python nrpy.py --help` for other command-line options */")
    print("/* Entering interactive mode                                  */\n")

#   Print help message if NRPy+ is run via
#    `python nrpy.py --help`
elif(len(sys.argv) == 2 and sys.argv[1] == "--help"):
    print("\n     \033[1m............................................\033[0m ")
    print("     -={ \033[1mNRPy+ supports multiple usage modes.\033[0m }=-\n")
    print("\033[1mUsage Mode 0\033[0m: `python nrpy.py`\n\t\t  initializes interactive session\n")
    print("\033[1mUsage Mode 1\033[0m: `python nrpy.py --help`\n\t\t  outputs this message\n")
    print("\033[1mUsage Mode 2\033[0m: `python nrpy.py --gen-defparam-file`\n\t\t generates default parameter file\n")
    print("\033[1mUsage Mode 3\033[0m: `python nrpy.py [PARAMETER FILE]`\n\t\t override default parameters with parameter file.")
    print("\t\t Parameter file takes the form of a list;")
    print("\t\t each list item has syntax `mainmodule:paramname=value`\n")
    print("\033[1mUsage Mode 4\033[0m: `python nrpy.py [PARAMETER FILE] [PARAMETER OVERRIDES]`")
    print("\t\t read parameter file, then override parameter file")
    print("\t\t settings with command-line parameters, with same")
    print("\t\t syntax (`mainmodule:paramname=value`)")
    print("     \033[1m............................................\033[0m ")
    sys.exit(0)

#    Run with parameter file & optional list of parameter overrides if NRPy+ is run via
#   `python nrpy.py [PARAMETER FILE] [(optional) PARAMETER OVERRIDES]`:
# Note that
# 1) parameters set in parameter file override parameter defaults, and
# 2) parameters set at command line override both parameter defaults
#    *and* parameter settings in parameter file
elif(len(sys.argv) >= 2):
    # When not in an interactive mode, the NRPy::MainModule parameter must be set,
    #   either in the param file (preferred!) or as a command line argument.
    with open(sys.argv[1], "r") as file:
        for line in file:
            par.set_paramsvals_value(line, sys.argv[1], FindMainModuleMode=True)
    # Search for NRPy::MainModule in the command line arguments
    for i in range(2,len(sys.argv)):
        par.set_paramsvals_value(sys.argv[i], "", FindMainModuleMode=True)
    # The NRPy::MainModule parameter has already been set,
    #   and parse_param_string__set__params_and_paramsvars()
    #   will error out with a "Critical Error" if it has not been set.
    idx = par.get_params_idx(par.glb_param("ignoretype", "NRPy", "MainModule", "ignoredefval"))
    MainModule = par.glb_paramsvals_list[idx]
    if MainModule == "NODEFAULT":
        print("Error: Could not find NRPy::MainModule defined in the parameter file \""+sys.argv[1]+"\" or on the command line!")
        sys.exit(1)

    # Next initialize all of MainModule's parameters.
    # Note that MainModule must also initialize parameters for modules
    # on which it depends, except outputC (which NRPy+ loads by default).
    # https://stackoverflow.com/questions/10675054/how-to-import-a-module-in-python-with-importlib-import-module
    importlib.import_module(MainModule+"."+MainModule)

    # Next overwrite default parameters with values specified in the parameter file.
    with open(sys.argv[1], "r") as file:
        for line in file:
            par.set_paramsvals_value(line, sys.argv[1])
    # Next overwrite default parameters and values specified in the parameter file with command-line parameter assignments.
    for i in range(2,len(sys.argv)):
        par.set_paramsvals_value(sys.argv[i], "")

# Next load the MainModule, if it hasn't been loaded already.
#importlib.import_module(MainModule+"."+MainModule)
getattr(importlib.import_module(MainModule+"."+MainModule), MainModule)()
# Initialize parameters for the core outputC module,
# which is the default MainModule.
# Call function initparams() from outputC module (in outputC.py):
# getattr(importlib.import_module(MainModule), 'initparams')()

# Step 3b (temporary): Set a SymPy expression to test processing
import sympy as sp
#from outputC import *
#getattr(importlib.import_module("outputC"),'outputC')([sympify("3*a*b**4+c*sin(a*b**4)"),sympify("6*a*b**4")],["output1","output2"])
#getattr(importlib.import_module("outputC"),'outputC')(sp.sympify("3*a*b**4+2*c*sin(a*b**4)"),"output1")


#Commenting for single

'''
Commenting for multiple lines
'''

#How to declare variables in Python
my_age = 40

#One variable can hold different data type
# Integer
my_var = 8
type(my_var)

# Float
my_var = 26.5
type(my_var)

# String
my_var = "FORSK"
type(my_var)

# Boolean
my_var = True
type(my_var)

# NoneType
my_var = None
type(my_var)

"""
Type Conversion using Global Functions
  int()
  float()
  str()
  bool()
"""

#How to convert the data type
int (10.6)
int ("10")

float (4)
float ("10")

str (4)
str (10.6)

bool (4)        # Any integer greater than zero is True
bool (0)

bool (10.6)     # Any float greater than 0.0 is True
bool(0.0)

bool(-90)

bool ("10")
bool("")

bool (None)

#Taking Integer Input from user
age = input ( "Enter your Age > ")
print (age)
print (type(age))

age = int(age)
print (age)
print (type(age))

#Taking Floating Point Input from user
temperature  = input ( "Enter your temperature of your city > ")
print (temperature)
print (type(temperature))

temperature = float(temperature)
print (temperature)
print (type(temperature))

#Taking String Input from user using raw_input function
name = input ( "Enter your Name >")
print (name)
print (type(name))

#Printing Output to the screen using single quote
print ( 'FORSK TECHNOLOGIES' )

#Printing Output to the screen using double quote
print ( "FORSK TECHNOLOGIES" )

#Using Triple Quotes to print quotation marks in string
print ("""FORSK"S TECHNOLOGIES""")

# Importing Modules

import math

math.sqrt ( 16 )
math.log ( 16, 2 )
math.cos ( 0 )
math.isnan(90)

# Importing Names from a Module Directly
#How to use specific functions from packages or modules in python
from math import sqrt
sqrt ( 16 )

#How to use specific functions from packages or modules
#and also aliasing
from math import sqrt as square
square ( 16 )

# How to find the function within the Module/Package
dir ( math )

help (math.sqrt)

#Slicing of strings

newstr = "Monty Python"

# Indexing using Left to Right

#START
print(newstr [ 0 ]) # 1st thing (0-indexed)
print(newstr [ -12 ])

# Indexing using Right to Left
print (newstr [ -1 ] ) # Last thing

#START and END
print(newstr[:3])  # First three things
print(newstr[-3:]) # Last three things

print(newstr[3:])  # Everything *except* the first three
print(newstr[:-3]) # Everything *except* the last three\

newstr [ 6:10 ]

newstr [ : 5 ]
newstr [ 6 : ]
newstr [ : ]

#Strings in python are Immutable

newstr = "Monty Python"

newstr [ 0 ] = "m"
#or
del newstr [ 0 ]

del newstr

"""
Global Inbuilt function ( len and del )
"""

newstr = "Monty Python"

len ( newstr )
print ( newstr )
del ( newstr )

# String functions
# ( lower, upper, find, replace, strip, lstrip, rstrip, split, join)
# creates a new copy of the string

newstr = "    Monty Python    "
print(newstr)

newstr.lower()
print(newstr)

newstr2= newstr.lower()
print(newstr2)

newstr.upper()

newstr.find('r')
newstr.find('P')
newstr.replace(' ','\n')

newstr.lstrip()
newstr.rstrip()
newstr.strip()

newstr.split()
newstr.index('M')

string="Rajasthan"
" ".join( string )

#to list all the functions for an object
dir ( str )

#to check the syntax for a specific function of the object
help ( str.strip )

#Take the age as input from the user and print
age = int(input("Enter your age>"))

#Take the age as input from the user and print
age = int(input("Enter your age>"))
if ( age > 0 ):
  print ("Valid Age")

else:
  print ("Invalid Age")

"""
Looping technique using while
"""

n = 0
while (n < 10):
  print (n)
  n = n + 1
  #n += 1

"""
List
"""

#List Creation
my_list = [ 1, 2, 3 ]
print(my_list)

#Adding single items in the list in the last
my_list.append( 5 )
print(my_list)

#Adding single item in the list at a specific position in the list
my_list.insert ( 0, 0 )
print(my_list)

#Remove a specific item by its value from the list
my_list.remove ( 4 )   #( ValueError here since 4 is not in the list )

# Accessing the values of the list using index
print(my_list[0])

#Sorting of the list items
print(my_list)
my_list.sort()
print (my_list)

# Membership Operators
# in   ,  not in

# Used to check if some single item is in a larger collection
# Return True if the item is in list
# Return False if the item is not in list

# Example
some_list = [1,2,3,5,6,2,4,3,5,6,7,8,1,2,3]

3 in some_list  # will return True

3 not in some_list # will return False

7 not in some_list  # will return True

# Hand on Challenge
while (3 in some_list):
    some_list.remove(3)
print (some_list)

"""
Looping technique using for each
"""
my_list = [0,1,2,3,4,5,6]
for number in my_list:
  print (number)

# default the range starts from 0

our_list = list(range(13))
print (type(our_list))
print (our_list)

for number in list(range (13)):
  print (number)

for number in list(range (1,13)):
  print (number)

"""
dictionary
"""

phone_book = { 'Vidhan':8504982228, 'Aayushi':8905336615, 'Vibhooti':9414701291 }
print(phone_book)
print(type(phone_book))

# Creation of dictionaries
dict1 = {'fname':'John', 'lname':'Mille', 'profession':'plumber',  'age':'32'}
print(dict1)

# Add/Update
dict1['lname'] = 'Miller'
dict1['profession'] = 'electrician'
dict1['age'] = '36'
dict1['city'] = 'NY' #add
print(dict1)

dict1['city'] = 'MA' #update
print(dict1)

dict1.update ( {'age':32, 'city':'NY' } )
print(dict1)

# Printing Values
print (dict1["lname"])
print (dict1.get('lname'))
print (dict1.get('name'))
print (dict1.get('name', 'Not Found'))

dict1 = {'fname':'John', 'lname':'Miller', 'profession':'plumber',  'age':'32'}

# To list all the keys
a  = dict1.keys()
print(a)
print(type(a))

# To list all the values
print(dict1.values())

# To list all the values
print(dict1.items())

# To list all values and keys
for key in dict1:
  print ( key , dict1[key] )

for key in dict1:
  print ( key , dict1.get(key) )

"""
NumPy
"""

a = [0,1,2,3,4,5,6,7,8]
print (type(a))
print (a)
# it always prints the values with comma seperated , thats list

# Convert your list data to NumPy arrays
import numpy as np

x = np.array( a )
print (type(x))

print (x)
# it always prints the values WITHOUT comma seperated , thats ndarray

# to print the data type of the elements of array
print (x.dtype)

# to print the dimension of the array
print (x.ndim)

# to print the shape of the array
# returns a tuple listing the length of the array along each dimension
# For a 1D array, the shape would be (n,)
# where n is the number of elements in your array.
print (x.shape)

# Array Indexing will always return the data type object
print (x[0])
print (x[2])
print (x[-1])

"""
Series
"""

#Import Python Libraries

import pandas as pd

# Create an Empty Series
s = pd.Series()
print (type(s))
print (s)

# Create a Series from ndarray
import numpy as np
data = np.array(['a','b','c','d'])
print (type(data ))

s = pd.Series(data)
print (type(s))
print (s)
# We did not pass any index, so by default,
# it assigned the indexes ranging from 0 to len(data)-1, i.e., 0 to 3.

#retrieve the first element
print (s[0])

#retrieve the first three element
print (s[:3])

#retrieve the last three element
print (s[-3:])

# Customised Index value
data = np.array(['a','b','c','d'])
s = pd.Series(data,index=[100,101,102,103])
print (s)

"""
DataFrame
"""

# A Data frame is a two-dimensional data structure, i.e.,
# data is aligned in a tabular fashion in rows and columns.
# You can think of it as an SQL table or a spreadsheet data representation

import pandas as pd

#Create an Empty DataFrame
df = pd.DataFrame()
print (df)

# Create a DataFrame from Lists
data = [1,2,3,4,5]
df = pd.DataFrame(data)
print (df)

# Create a DataFrame from List of Lists
data = [['Alex',10],['Bob',12],['Clarke',13]]
df = pd.DataFrame(data,columns=['Name','Age'])
print (df)

"""
Exploratory Data Analysis of Salaries Data
"""

"""
1. Which Male and Female Professor has the highest and the lowest salaries.
2. Which Professor takes the highest and lowest salaries.
3. Missing Salaries - should be mean salaries.
4. Missing phd - should be mean phd.
5. How many are Male Staff and How many are Female Staff.
6. How many are Prof, AssocProf and AsstProf.
7. Who are the senior and junior most employees in the organization.
"""

import pandas as pd
#Read csv file
df = pd.read_csv("data/Salaries.csv")

# Not a good technique to print the Data Frame
print (df)

df.info()

#List first 5 records
df.head()

#Can you guess how to view the last few records;
df.tail(5)

# Gives the row Indexes
df.index

#list the column names / column Indexes
df.columns

#Check types for all the columns
df.dtypes

#numpyrepresentation of the data
df.values

# generate descriptive statistics (for numeric columns only)
# Standard Deviation is quite useful tool to figure out
# how the data is spread above or below the mean.
# The higher the value, the less is reliable or vice versa.
df.describe() # Numeric Columns

#return max/min values for all columns
df.max()
df.min()

#return max/min values for all numeric columns
df.mean()
df.median()
df.std()

#returns a random sample of the data frame
df.sample(5)

"""
Data Frames: method loc

If we need to select a range of rows, using their labels/index
we can use method loc
"""

df.loc[:1]

df.loc[10:20,['rank','sex']]

"""
Data Frames: method iloc

If we need to select a range of rows and/or columns,
using their positions we can use method iloc
"""
df.iloc[:2]

df.iloc[ 10:21 , [0,4] ]

"""
Selecting a column in a Data Frame with all rows
"""

df.iloc[:,2]

df.loc[:,'phd']

# Read the data from a specific Series
df.phd

# Dont use this technique
df.rank

# This is the best practice
df['phd']

#Select column rank and salary:
df[['rank','salary']]

# Find unique values in a Series / Column
df['rank'].unique()
df['discipline'].unique()
df['sex'].unique()
list1 = df['sex'].unique().tolist()

# intuition about a Rank Series
df['rank']
df['rank'].value_counts()

# to show in Percentage
df['rank'].value_counts(normalize = True)

# To know the count of male and female candidates
df['sex']
df['sex'].value_counts()
df['sex'].value_counts(normalize = True)

#calculate the basic statstics on the salary column
df['salary'].mean()
df['salary'].std()
df['salary'].describe()

#Find how many values in the salary column which are non NaN (use count method);
df['salary'].count()
df['phd'].count()

# Boolean Indexing
# Find those rows which has null values in salary/phd column
df['salary'].isnull()
df[df['salary'].isnull()]

df['phd'].isnull()
df[df['phd'].isnull()]

"""
Data Frames groupby method
"""
#Group data using rank
df_rank= df.groupby(['rank'])

df_rank.size()
df_rank.count()
df_rank.groups
# Groups returns a dictionary object
df_rank.groups['AssocProf']
df_rank.groups['AssocProf'][0]

#group data using rank followed  by discipline and sex
df_rank=df.groupby(['rank', 'discipline','sex'])
df_rank.groups
df_rank.count()

#Calculate mean value for each numeric column per each group
df_rank.mean()

#Calculate mean salary for each type of professor rank:
df.groupby('rank')[['salary','phd']].min()
df.groupby('rank')[['salary','phd']].max()
df.groupby('rank')[['salary','phd']].mean()

"""
Data Frame: filtering

To subset the data we can apply Boolean indexing.
This indexing is commonly known as a filter.
For example if we want to subset the rows in which the salary
 value is greater than $120K:

"""

# Boolean Indexing in Pandas
# select only those professors who has salary more than 120000
df['salary'] > 120000
df_sub= df[(df['salary'] > 120000) ]
df_sub

#or

df.loc[df['salary'] > 120000]

# to display only the selected series/column
df.loc[df['salary'] > 120000,'salary']

#filter using multiple columns

df_sub= df[(df['salary'] > 120000) & \
           (df['phd'] > 10) & \
           (df['sex'] == 'Female' )
           ]
df_sub
# Or

df.loc[(df['salary'] > 120000) & \
           (df['phd'] > 10) & \
           (df['sex'] == 'Female' )]

#Select only those rows that contain female professors:
df_sub = df[df['sex'] == 'Female' ][['salary','sex']]
df_sub

# Or

df.loc[df['sex'] == 'Female' ][['salary','sex']]

"""
DataFrame sorting
"""

# Create a new data frame from the original sorted by the column Salary
df_sorted= df.sort_values( by='service')
df_sorted.head()

# To find the lowest salary of the employee
df_sorted= df.sort_values( by='salary', ascending = [True])
df_sorted.head(1)

# To find the highest salary of the employee
df_sorted= df.sort_values( by='salary', ascending = [False])
df_sorted.head(1)

#We can sort the data using 2 or more columns:
df_sorted= df.sort_values( by=['service','salary'], ascending = [True,True])
df_sorted.head(10)

df_sorted= df.sort_values( by=['service','salary'], ascending = [True,False])
df_sorted.head(10)

"""
Missing Values
"""

df.info()

df[df['phd'].isnull()]

df[df['salary'].isnull()]

# mark zero values as missing or NaN
df['salary'] = df['salary'].replace(0, np.NaN)

#There are a number of methods to deal with missing values in the data frame:
new_df = df.dropna()
new_df.count()

new_df2 = df.fillna(0)
new_df2.count()

# Fill All columns with missing values, with mean of that column
df = df.fillna(round(df.mean(),0))
df

# fill all the records with missing values, with mean of that column
df['phd'] = df['phd'].fillna(df['phd'].mean())

# fill all the records with missing values, with mean of that column
df['salary'] = df['salary'].fillna(df['salary'].median())

# How to drop columns
df.drop('discipline',axis=1, inplace=True)

"""
Matplotlib
"""

import matplotlib.pyplot as plt

x = [1,2,3,4,5,6,7,8,9,10]

y = [1,2,3,4,5,6,7,8,9,10]

# Setting the title
plt.title("A Line Graph")

# Setting the X Label
plt.xlabel("X")

# Setting the Y Label
plt.ylabel("Y")

# Displaying the Grid
plt.grid(True)

# Changing the x axes limits of the scale
plt.xlim(0, 10)

# Changing the y axes limits of the scale
plt.ylim(0, 10)

# Or
plt.axis([0, 10, 0, 10]);

# Showing the points on the graph
plt.scatter(x, y)

# Simple Line plot
plt.plot(x, y)

plt.savefig("data/scatter.jpg")

plt.show()

# Changing the color of the line
plt.plot(x, y, color='green') # #000000

# Changing the style of the line
plt.plot(x, y, linestyle='dashed') # solid dashed  dashdot dotted

# For Plotting Scatter Plot
plt.plot(x, y, 'd', color='black'); # o  .  , x  +  v  ^  <  >  s d

# Scatter Plot with scatter method
plt.scatter(x, y, marker='.', color='black',label="marker='{0}'".format('.')); # o  .  , x  +  v  ^  <  >  s d
plt.legend(numpoints=1)

"""
Pie chart, where the slices will be ordered and plotted counter-clockwise:
"""

labels = 'CSE', 'ECE', 'IT', 'EE'
sizes = [15, 30, 25, 10]
colors = ['gold', 'yellowgreen', 'lightcoral', 'lightskyblue']
explode = (0.1, 0, 0, 0)  # explode 1st slice

#plt.pie(sizes, labels=labels, autopct='%.0f%%')

# or

plt.pie(sizes, explode=explode, labels=labels, colors=colors, autopct='%1.1f%%', shadow=True, startangle=90)

plt.axis('equal')  # Equal aspect ratio ensures that pie is drawn as a circle.
plt.show()

"""
Plotting a bar chart
"""

import matplotlib.pyplot as plt;

objects = ('Python', 'C++', 'Java', 'Perl', 'Scala', 'Lisp')
performance = [10,8,6,4,2,1]

plt.bar([0,1,2,3,4,5], performance, align='center', alpha=1.0)
plt.xticks([0,1,2,3,4,5], objects)
plt.ylabel('Usage')
plt.title('Programming Language Usage')

plt.show()

"""
Showing bubbles
"""

import numpy as np
import matplotlib.pyplot as plt

# Define the number of values
num_vals = 40

# Generate random values
x = np.random.rand(num_vals)
y = np.random.rand(num_vals)

# Define area for each bubble
# Max radius is set to a specified value
max_radius = 25
area = np.pi * (max_radius*np.random.rand(num_vals)) ** 2

# Generate colors
colors = np.random.rand(num_vals)

# Plot the points
plt.scatter(x, y, s=area, c=colors, alpha=.5)
plt.show()

rng = np.random.RandomState(0)
x = rng.randn(100)
y = rng.randn(100)
colors = rng.rand(100)
sizes = 1000 * rng.rand(100)

plt.scatter(x, y, c=colors, s=sizes, alpha=0.3,
            cmap='viridis')
plt.colorbar();  # show color scale
# In this way, the color and size of points can be used to convey information in the visualization,
# in order to visualize multidimensional data.

"""
Now make a pie chart for all car makers
"""

import pandas as pd
import matplotlib.pyplot as plt

df = pd.read_csv("data/Automobile.csv")

series = df["make"].value_counts()

print (series.index[0:11])
print (series.values[0:11])

explode = (0.5,0,0,0,0,0,0,0,0,0,0)

plt.pie(series.values[0:11], explode = explode, labels=series.index[0:11], autopct='%2.2f%%')

# Equal aspect ratio ensures that pie is drawn as a circle.
plt.axis('equal')

plt.show()

for x,y in zip(series.index, series.values):
    print (x,y)

''' Feedback Form'''


from __future__ import division, print_function
# coding=utf-8
import sys
import os
import glob
import re
import numpy as np
import tensorflow as tf
import tensorflow as tf

from tensorflow.compat.v1 import ConfigProto
from tensorflow.compat.v1 import InteractiveSession

config = ConfigProto()
config.gpu_options.per_process_gpu_memory_fraction = 0.2
config.gpu_options.allow_growth = True
session = InteractiveSession(config=config)
# Keras
from tensorflow.keras.applications.resnet50 import preprocess_input
from tensorflow.keras.models import load_model
from tensorflow.keras.preprocessing import image

# Flask utils
from flask import Flask, redirect, url_for, request, render_template
from werkzeug.utils import secure_filename
#from gevent.pywsgi import WSGIServer

# Define a flask app
app = Flask(__name__)

# Model saved with Keras model.save()
MODEL_PATH ='animal.h5'

# Load your trained model
model = load_model(MODEL_PATH)

def model_predict(img_path, model):
    print(img_path)
    img = image.load_img(img_path, target_size=(224, 224))

    # Preprocessing the image
    x = image.img_to_array(img)
    # x = np.true_divide(x, 255)
    ## Scaling
    x=x/255
    x = np.expand_dims(x, axis=0)

    # Be careful how your trained model deals with the input
    # otherwise, it won't make correct prediction!
   # x = preprocess_input(x)

    preds = model.predict(x)
    preds=np.argmax(preds, axis=1)
    if preds==89:
        preds="zebra"
    elif preds==88:
        preds="woodpecker"
    elif preds==87:
        preds="wombat"
    elif preds==86:
        preds="wolf"
    elif preds==85:
        preds="whale"
    elif preds==84:
        preds="turtle"
    elif preds==83:
        preds="turkey"
    elif preds==82:
        preds="tiger"
    elif preds==81:
        preds="swan"
    elif preds==80:
        preds="starfish"
    elif preds==79:
        preds="squirrel"
    elif preds==78:
        preds="squid"
    elif preds==77:
        preds="sparrow"
    elif preds==76:
        preds="snake"
    elif preds==75:
        preds="sheep"
    elif preds==74:
        preds="shark"
    elif preds==73:
        preds="seal"
    elif preds==72:
        preds="seahorse"
    elif preds==71:
        preds="sandpiper"
    elif preds==70:
        preds="rhinoceros"
    elif preds==69:
        preds="reindeer"
    elif preds==68:
        preds="rat"
    elif preds==67:
        preds="raccon"
    elif preds==66:
        preds="possum"
    elif preds==65:
        preds="porcupine"
    elif preds==64:
        preds="pigeon"
    elif preds==63:
        preds="pig"
    elif preds==62:
        preds="penguine"
    elif preds==61:
        preds="pelecaniformes"
    elif preds==60:
        preds="parrot"
    elif preds==59:
        preds="panda"
    elif preds==58:
        preds="oyster"
    elif preds==57:
        preds="ox"
    elif preds==56:
        preds="owl"
    elif preds==55:
        preds="otter"
    elif preds==54:
        preds="orangutan"
    elif preds==53:
        preds="okapi"
    elif preds==52:
        preds="octopus"
    elif preds==51:
        preds="mouse"
    elif preds==50:
        preds="moth"
    elif preds==49:
        preds="mosquito"
    elif preds==48:
        preds="lobster"
    elif preds==47:
        preds="lizard"
    elif preds==46:
        preds="lion"
    elif preds==45:
        preds="leopard"
    elif preds==44:
        preds="ladybugs"
    elif preds==43:
        preds="Koala"
    elif preds==42:
        preds="Kangaroo"
    elif preds==41:
        preds="jellyfish"
    elif preds==40:
        preds="hyena"
    elif preds==39:
        preds="hummingbird"
    elif preds==38:
        preds="hourse"
    elif preds==37:
        preds="hornbill"
    elif preds==36:
        preds="hipopotamus"
    elif preds==35:
        preds="hedgehog"
    elif preds==34:
        preds="hare"
    elif preds==33:
        preds="hamster"
    elif preds==32:
        preds="grasshopper"
    elif preds==31:
        preds="gorilla"
    elif preds==30:
        preds="goose"
    elif preds==29:
        preds="goldfish"
    elif preds==28:
        preds="goat"
    elif preds==27:
        preds="fox"
    elif preds==26:
        preds="fly"
    elif preds==25:
        preds="flamingo"
    elif preds==24:
        preds="elephant"
    elif preds==23:
        preds="eagle"
    elif preds==22:
        preds="duck"
    elif preds==21:
        preds="dragonfly"
    elif preds==20:
        preds="donky"
    elif preds==19:
        preds="dolphin"
    elif preds==18:
        preds="dog"
    elif preds==17:
        preds="deer"
    elif preds==16:
        preds="crow"
    elif preds==15:
        preds="crab"
    elif preds==14:
        preds="coyote"
    elif preds==13:
        preds="cow"
    elif preds==12:
        preds="cockroach"
    elif preds==11:
        preds="chimpanzee"
    elif preds==10:
        preds="caterpillar"
    elif preds==9:
        preds="cat"
    elif preds==8:
        preds="butterfly"
    elif preds==7:
        preds="boar"
    elif preds==6:
        preds="bison"
    elif preds == 5:
        preds = "beetle"
    elif preds == 4:
        preds = "bee"
    elif preds == 3:
        preds = "bear"
    elif preds == 2:
        preds = "bat"
    elif preds == 1:
        preds = "badger"
    elif preds == 0:
        preds = "antelope"

    return preds

@app.route('/', methods=['GET'])
def index():
    # Main page
    return render_template('app.html')

@app.route('/predict', methods=['GET', 'POST'])
def upload():
    if request.method == 'POST':
        # Get the file from post request
        f = request.files['file']

        # Save the file to ./uploads
        basepath = os.path.dirname(__file__)
        file_path = os.path.join(
            basepath, 'uploads', secure_filename(f.filename))
        f.save(file_path)

        # Make prediction
        preds = model_predict(file_path, model)
        result=preds
        return result
    return None

if __name__ == '__main__':
    app.run(port=5001,debug=True)


"""
Repr formatting support
"""

def coeff_repr(c, is_latex=False):
    r"""
    String representing coefficients in a linear combination.

    INPUT:

    - ``c`` -- a coefficient (i.e., an element of a ring)

    OUTPUT:

    A string

    EXAMPLES::

        sage: from sage.misc.repr import coeff_repr
        sage: coeff_repr(QQ(1/2))
        '1/2'
        sage: coeff_repr(-x^2)
        '(-x^2)'
        sage: coeff_repr(QQ(1/2), is_latex=True)
        '\\frac{1}{2}'
        sage: coeff_repr(-x^2, is_latex=True)
        '\\left(-x^{2}\\right)'
    """
    if not is_latex:
        try:
            return c._coeff_repr()
        except AttributeError:
            pass
    if isinstance(c, (int, float)):
        return str(c)
    if is_latex and hasattr(c, '_latex_'):
        s = c._latex_()
    else:
        s = str(c).replace(' ', '')
    if s.find("+") != -1 or s.find("-") != -1:
        if is_latex:
            return "\\left(%s\\right)" % s
        else:
            return "(%s)" % s
    return s

def repr_lincomb(terms, is_latex=False, scalar_mult="*", strip_one=False,
                 repr_monomial=None, latex_scalar_mult=None):
    """
    Compute a string representation of a linear combination of some
    formal symbols.

    INPUT:

    - ``terms`` -- list of terms, as pairs (support, coefficient)
    - ``is_latex`` -- whether to produce latex (default: ``False``)
    - ``scalar_mult`` -- string representing the multiplication (default:``'*'``)
    - ``latex_scalar_mult`` -- latex string representing the multiplication
      (default: a space if ``scalar_mult`` is ``'*'``; otherwise ``scalar_mult``)
    - ``coeffs`` -- for backward compatibility

    OUTPUT:

    -  ``str`` - a string

    EXAMPLES::

        sage: repr_lincomb([('a',1), ('b',-2), ('c',3)])
        'a - 2*b + 3*c'
        sage: repr_lincomb([('a',0), ('b',-2), ('c',3)])
        '-2*b + 3*c'
        sage: repr_lincomb([('a',0), ('b',2), ('c',3)])
        '2*b + 3*c'
        sage: repr_lincomb([('a',1), ('b',0), ('c',3)])
        'a + 3*c'
        sage: repr_lincomb([('a',-1), ('b','2+3*x'), ('c',3)])
        '-a + (2+3*x)*b + 3*c'
        sage: repr_lincomb([('a', '1+x^2'), ('b', '2+3*x'), ('c', 3)])
        '(1+x^2)*a + (2+3*x)*b + 3*c'
        sage: repr_lincomb([('a', '1+x^2'), ('b', '-2+3*x'), ('c', 3)])
        '(1+x^2)*a + (-2+3*x)*b + 3*c'
        sage: repr_lincomb([('a', 1), ('b', -2), ('c', -3)])
        'a - 2*b - 3*c'
        sage: t = PolynomialRing(RationalField(),'t').gen()
        sage: repr_lincomb([('a', -t), ('s', t - 2), ('', t^2 + 2)])
        '-t*a + (t-2)*s + (t^2+2)'

    Examples for ``scalar_mult``::

        sage: repr_lincomb([('a',1), ('b',2), ('c',3)], scalar_mult='*')
        'a + 2*b + 3*c'
        sage: repr_lincomb([('a',2), ('b',0), ('c',-3)], scalar_mult='**')
        '2**a - 3**c'
        sage: repr_lincomb([('a',-1), ('b',2), ('c',3)], scalar_mult='**')
        '-a + 2**b + 3**c'

    Examples for ``scalar_mult`` and ``is_latex``::

        sage: repr_lincomb([('a',-1), ('b',2), ('c',3)], is_latex=True)
        '-a + 2 b + 3 c'
        sage: repr_lincomb([('a',-1), ('b',-1), ('c',3)], is_latex=True, scalar_mult='*')
        '-a - b + 3 c'
        sage: repr_lincomb([('a',-1), ('b',2), ('c',-3)], is_latex=True, scalar_mult='**')
        '-a + 2**b - 3**c'
        sage: repr_lincomb([('a',-2), ('b',-1), ('c',-3)], is_latex=True, latex_scalar_mult='*')
        '-2*a - b - 3*c'
        sage: repr_lincomb([('a',-2), ('b',-1), ('c',-3)], is_latex=True, latex_scalar_mult='')
        '-2a - b - 3c'

    Examples for ``strip_one``::

        sage: repr_lincomb([ ('a',1), (1,-2), ('3',3) ])
        'a - 2*1 + 3*3'
        sage: repr_lincomb([ ('a',-1), (1,1), ('3',3) ])
        '-a + 1 + 3*3'
        sage: repr_lincomb([ ('a',1), (1,-2), ('3',3) ], strip_one = True)
        'a - 2 + 3*3'
        sage: repr_lincomb([ ('a',-1), (1,1), ('3',3) ], strip_one = True)
        '-a + 1 + 3*3'
        sage: repr_lincomb([ ('a',1), (1,-1), ('3',3) ], strip_one = True)
        'a - 1 + 3*3'

    Examples for ``repr_monomial``::

        sage: repr_lincomb([('a',1), ('b',2), ('c',3)], repr_monomial = lambda s: s+"1")
        'a1 + 2*b1 + 3*c1'

    TESTS:

    Verify that :trac:`31672` is fixed::

        sage: alpha = var("alpha")
        sage: repr_lincomb([(x, alpha)], is_latex=True)
        '\\alpha x'
        sage: A.<psi> = PolynomialRing(QQ)
        sage: B.<t> = FreeAlgebra(A)
        sage: (psi * t)._latex_()
        '\\psi t'
    """
    # Setting scalar_mult: symbol used for scalar multiplication
    if is_latex:
        if latex_scalar_mult is not None:
            scalar_mult = latex_scalar_mult
        elif scalar_mult == "*":
            scalar_mult = " "

    if repr_monomial is None:
        if is_latex:

            def repr_monomial(monomial):
                return monomial._latex_() if hasattr(monomial, '_latex_') else str(monomial)
        else:
            repr_monomial = str

    s = ""
    first = True

    if scalar_mult is None:
        scalar_mult = "" if is_latex else "*"

    for (monomial, c) in terms:
        if c != 0:
            coeff = coeff_repr(c)
            negative = False
            if len(coeff) and coeff[0] == "-":
                negative = True
            try:
                if c < 0:
                    negative = True
            except (NotImplementedError, TypeError):
                # comparisons may not be implemented for some coefficients
                pass
            if negative:
                coeff = coeff_repr(-c, is_latex)
            else:
                coeff = coeff_repr(c, is_latex)
            if coeff == "1":
                coeff = ""
            if coeff != "0":
                if negative:
                    if first:
                        sign = "-"  # add trailing space?
                    else:
                        sign = " - "
                else:
                    if first:
                        sign = ""
                    else:
                        sign = " + "
                b = repr_monomial(monomial)
                if len(b):
                    if coeff != "":
                        if b == "1" and strip_one:
                            b = ""
                        else:
                            b = scalar_mult + b
                s += "%s%s%s" % (sign, coeff, b)
                first = False
    if first:
        return "0"
        # this can happen only if are only terms with coeff_repr(c) == "0"
    # elif s == "":
        # return "1"  # is empty string representation invalid?
    else:
        return s


import pytest
import numpy as np
from example_module import sqrt

def test_sqrt():

    # Cannot square root a negative number with this function
    with pytest.raises(ValueError):
        _ = sqrt(-1.0)

    # but can with positive numbers
    assert np.isclose(sqrt(1.0), 1.0)
    assert np.isclose(sqrt(4.0), 2.0)


# -*- coding: utf-8 -*-

import colorsys
import os
import cv2
from timeit import default_timer as timer
from skimage.morphology import skeletonize
import numpy as np
from keras import backend as K
from keras.models import load_model
from keras.layers import Input
from PIL import Image, ImageFont, ImageDraw
from keras.callbacks import ModelCheckpoint, ReduceLROnPlateau
from yolo3.model import yolo_eval, yolo_body, tiny_yolo_body
from yolo3.utils import letterbox_image
import os
from keras.utils import multi_gpu_model,to_categorical
from keras.layers import Conv2D,GlobalAveragePooling2D,Dropout,Dense,Flatten,BatchNormalization
from keras.optimizers import Adam
from keras import Model
#from Motor_Control import Motorize
class YOLO(object):
    _defaults = {
        "model_path": 'model_data/yolo.h5',
        "anchors_path": 'model_data/yolo_anchors.txt',
        "classes_path": 'model_data/coco_classes.txt',
        "score" : 0.3,
        "iou" : 0.45,
        "model_image_size" : (416, 416),
        "gpu_num" : 1,
    }

    @classmethod
    def get_defaults(cls, n):
        if n in cls._defaults:
            return cls._defaults[n]
        else:
            return "Unrecognized attribute name '" + n + "'"

    def __init__(self):#, **kwargs):
        self.__dict__.update(self._defaults) # set up default values
        #self.__dict__.update(kwargs) # and update with user overrides
        self.class_names = self._get_class()
        self.anchors = self._get_anchors()
        self.sess = K.get_session()
        self.boxes, self.scores, self.classes = self.generate()

    def _get_class(self):
        classes_path = os.path.expanduser(self.classes_path)
        with open(classes_path) as f:
            class_names = f.readlines()
        class_names = [c.strip() for c in class_names]
        return class_names

    def _get_anchors(self):
        anchors_path = os.path.expanduser(self.anchors_path)
        with open(anchors_path) as f:
            anchors = f.readline()
        anchors = [float(x) for x in anchors.split(',')]
        return np.array(anchors).reshape(-1, 2)

    def generate(self):
        model_path = os.path.expanduser(self.model_path)
        assert model_path.endswith('.h5'), 'Keras model or weights must be a .h5 file.'

        # Load model, or construct model and load weights.
        num_anchors = len(self.anchors)
        num_classes = len(self.class_names)
        is_tiny_version = num_anchors==6 # default setting
        try:
            self.yolo_model = load_model(model_path, compile=False)
        except:
            self.yolo_model = tiny_yolo_body(Input(shape=(None,None,3)), num_anchors//2, num_classes) \
                if is_tiny_version else yolo_body(Input(shape=(None,None,3)), num_anchors//3, num_classes)
            self.yolo_model.load_weights(self.model_path) # make sure model, anchors and classes match
        else:
            assert self.yolo_model.layers[-1].output_shape[-1] == \
                num_anchors/len(self.yolo_model.output) * (num_classes + 5), \
                'Mismatch between model and given anchor and class sizes'

        print('{} model, anchors, and classes loaded.'.format(model_path))

        # Generate colors for drawing bounding boxes.
        hsv_tuples = [(x / len(self.class_names), 1., 1.)
                      for x in range(len(self.class_names))]
        self.colors = list(map(lambda x: colorsys.hsv_to_rgb(*x), hsv_tuples))
        self.colors = list(
            map(lambda x: (int(x[0] * 255), int(x[1] * 255), int(x[2] * 255)),
                self.colors))
        np.random.seed(10101)  # Fixed seed for consistent colors across runs.
        np.random.shuffle(self.colors)  # Shuffle colors to decorrelate adjacent classes.
        np.random.seed(None)  # Reset seed to default.

        # Generate output tensor targets for filtered bounding boxes.
        self.input_image_shape = K.placeholder(shape=(2, ))
        if self.gpu_num>=2:
            self.yolo_model = multi_gpu_model(self.yolo_model, gpus=self.gpu_num)
        boxes, scores, classes = yolo_eval(self.yolo_model.output, self.anchors,
                len(self.class_names), self.input_image_shape,
                score_threshold=self.score, iou_threshold=self.iou)
        return boxes, scores, classes

    def detect_image(self, image):
        start = timer()

        if self.model_image_size != (None, None):
            assert self.model_image_size[0]%32 == 0, 'Multiples of 32 required'
            assert self.model_image_size[1]%32 == 0, 'Multiples of 32 required'
            boxed_image = letterbox_image(image, tuple(reversed(self.model_image_size)))
        else:
            new_image_size = (image.width - (image.width % 32),
                              image.height - (image.height % 32))
            boxed_image = letterbox_image(image, new_image_size)
        image_data = np.array(boxed_image, dtype='float32')

        print(image_data.shape)
        image_data /= 255.
        image_data = np.expand_dims(image_data, 0)  # Add batch dimension.

        out_boxes, out_scores, out_classes = self.sess.run(
            [self.boxes, self.scores, self.classes],
            feed_dict={
                self.yolo_model.input: image_data,
                self.input_image_shape: [image.size[1], image.size[0]],
                K.learning_phase(): 0
            })

        print('Found {} boxes for {}'.format(len(out_boxes), 'img'))

        font = ImageFont.truetype(font='font/FiraMono-Medium.otf',
                    size=np.floor(3e-2 * image.size[1] + 0.5).astype('int32'))
        thickness = (image.size[0] + image.size[1]) // 300

        for i, c in reversed(list(enumerate(out_classes))):
            predicted_class = self.class_names[c]
            box = out_boxes[i]
            score = out_scores[i]

            label = '{} {:.2f}'.format(predicted_class, score)
            draw = ImageDraw.Draw(image)
            label_size = draw.textsize(label, font)

            top, left, bottom, right = box
            top = max(0, np.floor(top + 0.5).astype('int32'))
            left = max(0, np.floor(left + 0.5).astype('int32'))
            bottom = min(image.size[1], np.floor(bottom + 0.5).astype('int32'))
            right = min(image.size[0], np.floor(right + 0.5).astype('int32'))
            print(label, (left, top), (right, bottom))

            if top - label_size[1] >= 0:
                text_origin = np.array([left, top - label_size[1]])
            else:
                text_origin = np.array([left, top + 1])

            # My kingdom for a good redistributable image drawing library.
            for i in range(thickness):
                draw.rectangle(
                    [left + i, top + i, right - i, bottom - i],
                    outline=self.colors[c])
            draw.rectangle(
                [tuple(text_origin), tuple(text_origin + label_size)],
                fill=self.colors[c])
            draw.text(text_origin, label, fill=(0, 0, 0), font=font)
            del draw

        end = timer()
        print(end - start)
        return image

    def detect_person(self, image):
        start = timer()

        if self.model_image_size != (None, None):
            assert self.model_image_size[0]%32 == 0, 'Multiples of 32 required'
            assert self.model_image_size[1]%32 == 0, 'Multiples of 32 required'
            boxed_image = letterbox_image(image, tuple(reversed(self.model_image_size)))
        else:
            new_image_size = (image.width - (image.width % 32),
                              image.height - (image.height % 32))
            boxed_image = letterbox_image(image, new_image_size)
        image_data = np.array(boxed_image, dtype='float32')
        pre = image_data
        print(image_data.shape)
        image_data /= 255.
        image_data = np.expand_dims(image_data, 0)  # Add batch dimension.
        print("Pre model feed")

        cv2.imshow("IMAGE PRE",pre)
        cv2.waitKey(1)
        out_boxes, out_scores, out_classes = self.sess.run(
            [self.boxes, self.scores, self.classes],
            feed_dict={
                self.yolo_model.input: image_data,
                self.input_image_shape: [image.size[1], image.size[0]],
                K.learning_phase(): 0
            })

        print('Found {} boxes for {}'.format(len(out_boxes), 'img'))

        font = ImageFont.truetype(font='font/FiraMono-Medium.otf',
                    size=np.floor(3e-2 * image.size[1] + 0.5).astype('int32'))
        thickness = (image.size[0] + image.size[1]) // 300

        cc=0
        existing=False
        persons_detected=[]
        for i, c in reversed(list(enumerate(out_classes))):
            predicted_class = self.class_names[c]
            box = out_boxes[i]
            score = out_scores[i]
            if predicted_class=="person":
                top, left, bottom, right = box
                top = max(0, np.floor(top + 0.5).astype('int32'))
                left = max(0, np.floor(left + 0.5).astype('int32'))
                bottom = min(image.size[1], np.floor(bottom + 0.5).astype('int32'))
                right = min(image.size[0], np.floor(right + 0.5).astype('int32'))
                cc+=1
                persons_detected.append([left,top,right,bottom])
        if cc>0:
            existing=True
        return existing,persons_detected

    def close_session(self):
        self.sess.close()

def save_pics(yolo):
    import cv2
    targets_available=["Non_Sign","Ped_Sign","Pol_Sign"]
    id_selected=0
    for i in range(3):
        id_selected = i
        target =targets_available[id_selected]
        for (root, dirs, files) in os.walk('Img/'+str(target)):
            if files:
                for f in files:
                    print(f)
                    path = os.path.join(root, f)
                    frame = cv2.imread(path)
                    image = Image.fromarray(frame)
                    same_frame = np.copy(image)
                    # image = yolo.detect_image(image)
                    same_frame = cv2.blur(same_frame,(5,5))
                    imgray = cv2.cvtColor(same_frame, cv2.COLOR_BGR2GRAY)
                    thresh = cv2.adaptiveThreshold(imgray, 1, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2)
                    sk = skeletonize(thresh)
                    sk = np.asarray(sk, dtype=np.uint8)
                    sk = sk * 255
                    #cv2.imshow('skel', sk)
                    someone, roi_coords = yolo.detect_person(image)
                    if someone:
                        roi_coords = np.asarray(roi_coords)
                        for t in range(roi_coords.shape[0]):
                            left, top, right, bottom = roi_coords[t]
                            roi_sk = sk[top:bottom, left:right]
                            print(roi_coords[t])
                            #cv2.imshow("test" + str(t), roi_sk)
                            cv2.imwrite('Img/' + str(target)+'/res/'+f,roi_sk)
                            #cv2.waitKey(1)

def load_data():
    import cv2
    targets_available = ["Non_Sign", "Ped_Sign", "Pol_Sign"]
    data=np.uint8
    temp_label=[]
    temp_data=[]
    Y=[]
    otro = []
    images = np.array([], dtype=object)
    c=0
    for id_selected in range(3):
        temp_label = to_categorical(id_selected,3)
        #print("Temp_label"+str(temp_label))
        target = targets_available[id_selected]
        for (root, dirs, files) in os.walk('Img/' + str(target)+'/res/'):
            if files:
                for f in files:
                    #print(f)
                    path = os.path.join(root, f)
                    print(path)
                    print(temp_label)
                    frame = cv2.imread(path,0)
                    print(np.asarray(frame).shape)
                    frame = cv2.resize(frame,(44,146))
                    print(np.asarray(frame).shape)
                    frame = np.asarray(frame)
                    #cv2.imshow("fr",frame)
                    #cv2.waitKey(1)
                    #print(frame.shape)
                    #frame = np.reshape(frame,(-1,frame.shape[0],frame.shape[1],1))
                    frame = frame/255
                    print(frame)
                    frame = np.reshape(frame,(frame.shape[0],frame.shape[1],1))
                    temp_label = np.reshape(temp_label,(3))
                    temp_data.append(frame)
                    c+=1
                    Y.append(temp_label)

    return  temp_data,Y,c

def build_cnn():
    in_layer = Input(shape=(146, 44, 1))
    x = BatchNormalization()(in_layer)
    x = Conv2D(128, (4, 4), activation='elu')(x)  # single stride 4x4 filter for 16 maps
    x = Conv2D(64, (4, 4), activation='elu')(x)  # single stride 4x4 filter for 32 maps
    x = Dropout(0.5)(x)
    x = Conv2D(64, (4, 4), activation='elu')(x)  # single stride 4x4 filter for 64 maps
    x = Dropout(0.5)(x)
    x = Conv2D(128, (1, 1))(x)  # finally 128 maps for global average-pool
    x = Flatten()(x) # pseudo-dense 128 layer
    output_layer = Dense(3, activation="softmax")(x)  # softmax output
    model = Model(inputs=in_layer, outputs=output_layer)
    learning_rate = 1e-3
    optm = Adam(lr=learning_rate)
    model.compile(optimizer=optm, loss='categorical_crossentropy', metrics=['accuracy'])
    model.summary()
    #model.load_weights("alex_weights.h5")
    return model

def detect_video_save_pics(yolo):
    save_pics(yolo)

def detect_video_train(yolo):
    model=build_cnn()
    data,Y,ra =load_data()
    print("training..")
    factor = 1. / np.sqrt(2)

    model_checkpoint = ModelCheckpoint("final_alex.h5", verbose=1,
                                       monitor='val_acc', save_best_only=True, save_weights_only=True)
    reduce_lr = ReduceLROnPlateau(monitor='val_acc', patience=100, mode='max',
                                  factor=factor, cooldown=0, min_lr=1e-4, verbose=2)
    callback_list = [model_checkpoint, reduce_lr]

    model.fit(x=np.array(data),y=np.array(Y),verbose=2,epochs=100,callbacks=callback_list,validation_split=0.15)

    print("done")

def detect_video(yolo):
    import cv2
    #print("preparing to build... cnn")
    #model = build_cnn()
    #print ("CNN done")
    print("video capture pre log")
    vid = cv2.VideoCapture(0)
    print("video capture post log")
    if not vid.isOpened():
        raise IOError("Couldn't open webcam or video")
    video_FourCC    = int(vid.get(cv2.CAP_PROP_FOURCC))
    video_fps       = vid.get(cv2.CAP_PROP_FPS)
    video_size      = (int(vid.get(cv2.CAP_PROP_FRAME_WIDTH)),
                        int(vid.get(cv2.CAP_PROP_FRAME_HEIGHT)))
    accum_time = 0
    curr_fps = 0
    fps = "FPS: ??"
    prev_time = timer()
    targets_available = ["None Signed", "Pedestrian Sign", "Police Sign"]
    print("Entering... loop")
    while True:
        print("call_1")
        return_value, frame = vid.read()
        print("call_2")
        image = Image.fromarray(frame)
        print("call_3")
        same_frame = np.copy(image)
        print("call_4")
        result = np.asarray(image)
        print("call_5")
        same_frame = cv2.blur(same_frame,(5,5))
        imgray = cv2.cvtColor(same_frame, cv2.COLOR_BGR2GRAY)
        thresh = cv2.adaptiveThreshold(imgray, 1, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2)
        sk = skeletonize(thresh)
        sk = np.asarray(sk, dtype=np.uint8)
        sk = sk*255#sk[sk == 1] = 255
        #cv2.imshow('skel', sk)
        someone,roi_coords = yolo.detect_person(image)
        Sign_Boolean =False
        if someone:
            roi_coords = np.asarray(roi_coords)
            for t in range(roi_coords.shape[0]):
                left, top, right, bottom = roi_coords[t]
                roi_sk = sk[top:bottom , left:right]
                print(roi_coords[t])
                cv2.imshow("Person_"+str(t),roi_sk)
                feed_net = cv2.resize(roi_sk, (44, 146))
                feed_net = np.asarray(feed_net)
                feed_net = feed_net /255
                feed_net = np.reshape(feed_net, (-1,feed_net.shape[0], feed_net.shape[1], 1))

                prediction = 0#model.predict(feed_net)[0]

                max_pred = 0#np.argmax(prediction)

                # cv2.imshow("fr",frame)
                # cv2.waitKey(1)
                # print(frame.shape)
                # frame = np.reshape(frame,(-1,frame.shape[0],frame.shape[1],1))
                Show_text = targets_available[max_pred]
                print("PREDICTED : "+str(Show_text)+" - "+str(prediction))
                cv2.putText(result, text=Show_text, org=(3, 50), fontFace=cv2.FONT_HERSHEY_SIMPLEX,
                            fontScale=2.50, color=(255, 0, 0), thickness=2)

        curr_time = timer()
        exec_time = curr_time - prev_time
        prev_time = curr_time
        accum_time = accum_time + exec_time
        curr_fps = curr_fps + 1
        if accum_time > 1:
            accum_time = accum_time - 1
            fps = "FPS: " + str(curr_fps)
            curr_fps = 0
        cv2.putText(result, text=fps, org=(3, 15), fontFace=cv2.FONT_HERSHEY_SIMPLEX,
                    fontScale=0.50, color=(255, 0, 0), thickness=2)
        cv2.namedWindow("camera_view", cv2.WINDOW_NORMAL)
        cv2.imshow("camera_view", result)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    yolo.close_session()


#!/usr/bin/env python3

import unittest
from unittest.mock import patch
import numpy as np
import pandas as pd

from tmc import points

from tmc.utils import load, get_out, patch_helper

module_name="src.powers_of_series"
powers_of_series = load(module_name, "powers_of_series")
main = load(module_name, "main")
ph = patch_helper(module_name)

@points('p04-02.1')
class PowersOfSeries(unittest.TestCase):

    def test_type(self):
        s = pd.Series([1,2,3,4], index=list("abcd"))
        k = 2
        df = powers_of_series(s, k)
        self.assertIsInstance(df, pd.DataFrame, msg="powers_of_series should return a DataFrame!")

    def test_dimensions(self):
        ind=list("abcdefghijklmnopqrstuvwxyz")
        k=3
        for n in range(4):
            L=np.random.randint(-10, 10, n)
            s = pd.Series(L, index=ind[:n])
            df = powers_of_series(s, k)
            self.assertEqual(df.shape, (n, k),
                             msg="The DataFrame had wrong shape for call powers_of_series(%s, %i)!" % (s,k))

    def test_content(self):
        ind=list("abcdefghijklmnopqrstuvwxyz")
        k=3
        for n in range(4, 0, -1):
            L=np.random.randint(-10, 10, n)
            s = pd.Series(L, index=ind[:n])
            df = powers_of_series(s, k)
            self.assertTrue(np.issubdtype(df.columns.dtype, np.integer),
                            msg="Expected column indices to have integer type!")
            for i in range(1,k+1):
                np.testing.assert_array_equal(df[i], s**i, err_msg="Incorrect values in column %i for Series\n%s!" % ( i, s))

    def test_called(self):
        with patch(ph("powers_of_series"), wraps=powers_of_series) as ppos:
            main()
            ppos.assert_called()

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


# coding: utf-8

# Deep Learning
# =============
#
# Assignment 1
# ------------
#
# The objective of this assignment is to learn about simple data curation practices, and familiarize you with some of the data we'll be reusing later.
#
# This notebook uses the [notMNIST](http://yaroslavvb.blogspot.com/2011/09/notmnist-dataset.html) dataset to be used with python experiments. This dataset is designed to look like the classic [MNIST](http://yann.lecun.com/exdb/mnist/) dataset, while looking a little more like real data: it's a harder task, and the data is a lot less 'clean' than MNIST.

# In[2]:

# These are all the modules we'll be using later. Make sure you can import them
# before proceeding further.
import matplotlib.pyplot as plt
import numpy as np
import os
import tarfile
import urllib
from IPython.display import display, Image
from scipy import ndimage
from sklearn.linear_model import LogisticRegression
import pickle

# First, we'll download the dataset to our local machine. The data consists of characters rendered in a variety of fonts on a 28x28 image. The labels are limited to 'A' through 'J' (10 classes). The training set has about 500k and the testset 19000 labelled examples. Given these sizes, it should be possible to train models quickly on any machine.

# In[4]:

url = 'http://yaroslavvb.com/upload/notMNIST/'

def maybe_download(filename, expected_bytes):
  """Download a file if not present, and make sure it's the right size."""
  if not os.path.exists(filename):
    filename, _ = urllib.urlretrieve(url + filename, filename)
  statinfo = os.stat(filename)
  if statinfo.st_size == expected_bytes:
    print('Found and verified', filename)
  else:
    raise Exception(
      'Failed to verify' + filename + '. Can you get to it with a browser?')
  return filename

train_filename = maybe_download('notMNIST_large.tar.gz', 247336696)
test_filename = maybe_download('notMNIST_small.tar.gz', 8458043)

# Extract the dataset from the compressed .tar.gz file.
# This should give you a set of directories, labelled A through J.

# In[11]:

num_classes = 10

def extract(filename):
  tar = tarfile.open(filename)
  tar.extractall()
  tar.close()
  root = os.path.splitext(os.path.splitext(filename)[0])[0]  # remove .tar.gz
  data_folders = [os.path.join(root, d) for d in sorted(os.listdir(root))]
  if len(data_folders) != num_classes:
    raise Exception(
      'Expected %d folders, one per class. Found %d instead.' % (
        num_folders, len(data_folders)))
  print(data_folders)
  return data_folders

#train_folders = extract(train_filename)
test_folders = extract(test_filename)

# ---
# Problem 1
# ---------
#
# Let's take a peek at some of the data to make sure it looks sensible. Each exemplar should be an image of a character A through J rendered in a different font. Display a sample of the images that we just downloaded. Hint: you can use the package IPython.display.
#
# ---

# In[17]:

import IPython.display as display
import os
file_to_display = os.path.join(test_folders[0], os.listdir(test_folders[0])[0])
print(file_to_display)
display.display_png(file_to_display)

# Now let's load the data in a more manageable format.
#
# We'll convert the entire dataset into a 3D array (image index, x, y) of floating point values, normalized to have approximately zero mean and standard deviation ~0.5 to make training easier down the road. The labels will be stored into a separate array of integers 0 through 9.
#
# A few images might not be readable, we'll just skip them.

# In[16]:

image_size = 28  # Pixel width and height.
pixel_depth = 255.0  # Number of levels per pixel.

def load(data_folders, min_num_images, max_num_images):
  dataset = np.ndarray(
    shape=(max_num_images, image_size, image_size), dtype=np.float32)
  labels = np.ndarray(shape=(max_num_images), dtype=np.int32)
  label_index = 0
  image_index = 0
  for folder in data_folders:
    print(folder)
    for image in os.listdir(folder):
      if image_index >= max_num_images:
        raise Exception('More images than expected: %d >= %d' % (
          num_images, max_num_images))
      image_file = os.path.join(folder, image)
      try:
        image_data = (ndimage.imread(image_file).astype(float) -
                      pixel_depth / 2) / pixel_depth
        if image_data.shape != (image_size, image_size):
          raise Exception('Unexpected image shape: %s' % str(image_data.shape))
        dataset[image_index, :, :] = image_data
        labels[image_index] = label_index
        image_index += 1
      except IOError as e:
        print('Could not read:', image_file, ':', e, '- it\'s ok, skipping.')
    label_index += 1
  num_images = image_index
  dataset = dataset[0:num_images, :, :]
  labels = labels[0:num_images]
  if num_images < min_num_images:
    raise Exception('Many fewer images than expected: %d < %d' % (
        num_images, min_num_images))
  print('Full dataset tensor:', dataset.shape)
  print('Mean:', np.mean(dataset))
  print('Standard deviation:', np.std(dataset))
  print('Labels:', labels.shape)
  return dataset, labels
#train_dataset, train_labels = load(train_folders, 450000, 550000)
test_dataset, test_labels = load(test_folders, 18000, 20000)

# ---
# Problem 2
# ---------
#
# Let's verify that the data still looks good. Displaying a sample of the labels and images from the ndarray. Hint: you can use matplotlib.pyplot.
#
# ---

# Next, we'll randomize the data. It's important to have the labels well shuffled for the training and test distributions to match.

# In[ ]:

np.random.seed(133)
def randomize(dataset, labels):
  permutation = np.random.permutation(labels.shape[0])
  shuffled_dataset = dataset[permutation,:,:]
  shuffled_labels = labels[permutation]
  return shuffled_dataset, shuffled_labels
train_dataset, train_labels = randomize(train_dataset, train_labels)
test_dataset, test_labels = randomize(test_dataset, test_labels)

# ---
# Problem 3
# ---------
# Convince yourself that the data is still good after shuffling!
#
# ---

# ---
# Problem 4
# ---------
# Another check: we expect the data to be balanced across classes. Verify that.
#
# ---

# Prune the training data as needed. Depending on your computer setup, you might not be able to fit it all in memory, and you can tune train_size as needed.
#
# Also create a validation dataset for hyperparameter tuning.

# In[ ]:

train_size = 200000
valid_size = 10000

valid_dataset = train_dataset[:valid_size,:,:]
valid_labels = train_labels[:valid_size]
train_dataset = train_dataset[valid_size:valid_size+train_size,:,:]
train_labels = train_labels[valid_size:valid_size+train_size]
print 'Training', train_dataset.shape, train_labels.shape
print 'Validation', valid_dataset.shape, valid_labels.shape

# Finally, let's save the data for later reuse:

# In[ ]:

pickle_file = 'notMNIST.pickle'

try:
  f = open(pickle_file, 'wb')
  save = {
    'train_dataset': train_dataset,
    'train_labels': train_labels,
    'valid_dataset': valid_dataset,
    'valid_labels': valid_labels,
    'test_dataset': test_dataset,
    'test_labels': test_labels,
    }
  pickle.dump(save, f, pickle.HIGHEST_PROTOCOL)
  f.close()
except Exception as e:
  print 'Unable to save data to', pickle_file, ':', e
  raise

# In[ ]:

statinfo = os.stat(pickle_file)
print 'Compressed pickle size:', statinfo.st_size

# ---
# Problem 5
# ---------
#
# By construction, this dataset might contain a lot of overlapping samples, including training data that's also contained in the validation and test set! Overlap between training and test can skew the results if you expect to use your model in an environment where there is never an overlap, but are actually ok if you expect to see training samples recur when you use it.
# Measure how much overlap there is between training, validation and test samples.
# Optional questions:
# - What about near duplicates between datasets? (images that are almost identical)
# - Create a sanitized validation and test set, and compare your accuracy on those in subsequent assignments.
# ---

# ---
# Problem 6
# ---------
#
# Let's get an idea of what an off-the-shelf classifier can give you on this data. It's always good to check that there is something to learn, and that it's a problem that is not so trivial that a canned solution solves it.
#
# Train a simple model on this data using 50, 100, 1000 and 5000 training samples. Hint: you can use the LogisticRegression model from sklearn.linear_model.
#
# Optional question: train an off-the-shelf model on all the data!
#
# ---


import numpy as np
import tensorflow as tf
import pdb

pdb.set_trace()
x = np.random.uniform()
y = np.random.uniform()
pdb.set_trace()

sumval = x+y

print(sumval)

'''
Run using python example.py
The pdb.set_trace() line is where a breakpoint is added.
Commands:
1. `next` - move to next line
2. `p something` - check the value of the variable something.
3. `whatis something` - check the type of variable something.
4. `c` - continue to next breakpoint
5. `ctrl-d` - exit pdb.
'''


"""
.. _tut-erp:

EEG processing and Event Related Potentials (ERPs)
==================================================

This tutorial shows how to perform standard ERP analyses in MNE-Python. Most of
the material here is covered in other tutorials too, but for convenience the
functions and methods most useful for ERP analyses are collected here, with
links to other tutorials where more detailed information is given.

As usual we'll start by importing the modules we need and loading some example
data. Instead of parsing the events from the raw data's :term:`stim channel`
(like we do in :ref:`this tutorial <tut-events-vs-annotations>`), we'll load
the events from an external events file. Finally, to speed up computations so
our documentation server can handle them, we'll crop the raw data from ~4.5
minutes down to 90 seconds.
"""

import os
import numpy as np
import matplotlib.pyplot as plt
import mne

sample_data_folder = mne.datasets.sample.data_path()
sample_data_raw_file = os.path.join(sample_data_folder, 'MEG', 'sample',
                                    'sample_audvis_filt-0-40_raw.fif')
raw = mne.io.read_raw_fif(sample_data_raw_file, preload=False)

sample_data_events_file = os.path.join(sample_data_folder, 'MEG', 'sample',
                                       'sample_audvis_filt-0-40_raw-eve.fif')
events = mne.read_events(sample_data_events_file)

raw.crop(tmax=90)  # in seconds; happens in-place
# discard events >90 seconds (not strictly necessary: avoids some warnings)
events = events[events[:, 0] <= raw.last_samp]

###############################################################################
# The file that we loaded has already been partially processed: 3D sensor
# locations have been saved as part of the ``.fif`` file, the data have been
# low-pass filtered at 40 Hz, and a common average reference is set for the
# EEG channels, stored as a projector (see :ref:`section-avg-ref-proj` in the
# :ref:`tut-set-eeg-ref` tutorial for more info about when you may want to do
# this). We'll discuss how to do each of these below.
#
# Since this is a combined EEG+MEG dataset, let's start by restricting the data
# to just the EEG and EOG channels. This will cause the other projectors saved
# in the file (which apply only to magnetometer channels) to be removed. By
# looking at the measurement info we can see that we now have 59 EEG channels
# and 1 EOG channel.

raw.pick(['eeg', 'eog']).load_data()
raw.info

###############################################################################
# Channel names and types
# ^^^^^^^^^^^^^^^^^^^^^^^
#
# In practice it's quite common to have some channels labelled as EEG that are
# actually EOG channels. `~mne.io.Raw` objects have a
# `~mne.io.Raw.set_channel_types` method that you can use to change a channel
# that is labeled as ``eeg`` into an ``eog`` type. You can also rename channels
# using the `~mne.io.Raw.rename_channels` method. Detailed examples of both of
# these methods can be found in the tutorial :ref:`tut-raw-class`. In this data
# the channel types are all correct already, so for now we'll just rename the
# channels to remove a space and a leading zero in the channel names, and
# convert to lowercase:

channel_renaming_dict = {name: name.replace(' 0', '').lower()
                         for name in raw.ch_names}
_ = raw.rename_channels(channel_renaming_dict)  # happens in-place

###############################################################################
# Channel locations
# ^^^^^^^^^^^^^^^^^
#
# The tutorial :ref:`tut-sensor-locations` describes MNE-Python's handling of
# sensor positions in great detail. To briefly summarize: MNE-Python
# distinguishes :term:`montages <montage>` (which contain sensor positions in
# 3D: ``x``, ``y``, ``z``, in meters) from :term:`layouts <layout>` (which
# define 2D arrangements of sensors for plotting approximate overhead diagrams
# of sensor positions). Additionally, montages may specify *idealized* sensor
# positions (based on, e.g., an idealized spherical headshape model) or they
# may contain *realistic* sensor positions obtained by digitizing the 3D
# locations of the sensors when placed on the actual subject's head.
#
# This dataset has realistic digitized 3D sensor locations saved as part of the
# ``.fif`` file, so we can view the sensor locations in 2D or 3D using the
# `~mne.io.Raw.plot_sensors` method:

raw.plot_sensors(show_names=True)
fig = raw.plot_sensors('3d')

###############################################################################
# If you're working with a standard montage like the `10-20 <ten_twenty_>`_
# system, you can add sensor locations to the data like this:
# ``raw.set_montage('standard_1020')``.  See :ref:`tut-sensor-locations` for
# info on what other standard montages are built-in to MNE-Python.
#
# If you have digitized realistic sensor locations, there are dedicated
# functions for loading those digitization files into MNE-Python; see
# :ref:`reading-dig-montages` for discussion and :ref:`dig-formats` for a list
# of supported formats. Once loaded, the digitized sensor locations can be
# added to the data by passing the loaded montage object to
# ``raw.set_montage()``.
#
#
# Setting the EEG reference
# ^^^^^^^^^^^^^^^^^^^^^^^^^
#
# As mentioned above, this data already has an EEG common average reference
# added as a :term:`projector`. We can view the effect of this on the raw data
# by plotting with and without the projector applied:

for proj in (False, True):
    fig = raw.plot(n_channels=5, proj=proj, scalings=dict(eeg=50e-6))
    fig.subplots_adjust(top=0.9)  # make room for title
    ref = 'Average' if proj else 'No'
    fig.suptitle(f'{ref} reference', size='xx-large', weight='bold')

###############################################################################
# The referencing scheme can be changed with the function
# `mne.set_eeg_reference` (which by default operates on a *copy* of the data)
# or the `raw.set_eeg_reference() <mne.io.Raw.set_eeg_reference>` method (which
# always modifies the data in-place). The tutorial :ref:`tut-set-eeg-ref` shows
# several examples of this.
#
#
# Filtering
# ^^^^^^^^^
#
# MNE-Python has extensive support for different ways of filtering data. For a
# general discussion of filter characteristics and MNE-Python defaults, see
# :ref:`disc-filtering`. For practical examples of how to apply filters to your
# data, see :ref:`tut-filter-resample`. Here, we'll apply a simple high-pass
# filter for illustration:

raw.filter(l_freq=0.1, h_freq=None)

###############################################################################
# Evoked responses: epoching and averaging
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#
# The general process for extracting evoked responses from continuous data is
# to use the `~mne.Epochs` constructor, and then average the resulting epochs
# to create an `~mne.Evoked` object. In MNE-Python, events are represented as
# a :class:`NumPy array <numpy.ndarray>` of sample numbers and integer event
# codes. The event codes are stored in the last column of the events array:

np.unique(events[:, -1])

###############################################################################
# The :ref:`tut-event-arrays` tutorial discusses event arrays in more detail.
# Integer event codes are mapped to more descriptive text using a Python
# :class:`dictionary <dict>` usually called ``event_id``. This mapping is
# determined by your experiment code (i.e., it reflects which event codes you
# chose to use to represent different experimental events or conditions). For
# the :ref:`sample-dataset` data has the following mapping:

event_dict = {'auditory/left': 1, 'auditory/right': 2, 'visual/left': 3,
              'visual/right': 4, 'face': 5, 'buttonpress': 32}

###############################################################################
# Now we can extract epochs from the continuous data. An interactive plot
# allows you to click on epochs to mark them as "bad" and drop them from the
# analysis (it is not interactive on the documentation website, but will be
# when you run `epochs.plot() <mne.Epochs.plot>` in a Python console).

epochs = mne.Epochs(raw, events, event_id=event_dict, tmin=-0.3, tmax=0.7,
                    preload=True)
fig = epochs.plot()

###############################################################################
# It is also possible to automatically drop epochs, when first creating them or
# later on, by providing maximum peak-to-peak signal value thresholds (pass to
# the `~mne.Epochs` constructor as the ``reject`` parameter; see
# :ref:`tut-reject-epochs-section` for details).  You can also do this after
# the epochs are already created, using the `~mne.Epochs.drop_bad` method:

reject_criteria = dict(eeg=100e-6,  # 100 µV
                       eog=200e-6)  # 200 µV
_ = epochs.drop_bad(reject=reject_criteria)

###############################################################################
# Next we generate a barplot of which channels contributed most to epochs
# getting rejected. If one channel is responsible for lots of epoch rejections,
# it may be worthwhile to mark that channel as "bad" in the `~mne.io.Raw`
# object and then re-run epoching (fewer channels w/ more good epochs may be
# preferable to keeping all channels but losing many epochs). See
# :ref:`tut-bad-channels` for more info.

epochs.plot_drop_log()

###############################################################################
# Another way in which epochs can be automatically dropped is if the
# `~mne.io.Raw` object they're extracted from contains :term:`annotations` that
# begin with either ``bad`` or ``edge`` ("edge" annotations are automatically
# inserted when concatenating two separate `~mne.io.Raw` objects together). See
# :ref:`tut-reject-data-spans` for more information about annotation-based
# epoch rejection.
#
# Now that we've dropped the bad epochs, let's look at our evoked responses for
# some conditions we care about. Here the `~mne.Epochs.average` method will
# create and `~mne.Evoked` object, which we can then plot. Notice that we\
# select which condition we want to average using the square-bracket indexing
# (like a :class:`dictionary <dict>`); that returns a smaller epochs object
# containing just the epochs from that condition, to which we then apply the
# `~mne.Epochs.average` method:

l_aud = epochs['auditory/left'].average()
l_vis = epochs['visual/left'].average()

###############################################################################
# These `~mne.Evoked` objects have their own interactive plotting method
# (though again, it won't be interactive on the documentation website):
# click-dragging a span of time will generate a scalp field topography for that
# time span. Here we also demonstrate built-in color-coding the channel traces
# by location:

fig1 = l_aud.plot()
fig2 = l_vis.plot(spatial_colors=True)

###############################################################################
# Scalp topographies can also be obtained non-interactively with the
# `~mne.Evoked.plot_topomap` method. Here we display topomaps of the average
# field in 50 ms time windows centered at -200 ms, 100 ms, and 400 ms.

l_aud.plot_topomap(times=[-0.2, 0.1, 0.4], average=0.05)

###############################################################################
# Considerable customization of these plots is possible, see the docstring of
# `~mne.Evoked.plot_topomap` for details.
#
# There is also a built-in method for combining "butterfly" plots of the
# signals with scalp topographies, called `~mne.Evoked.plot_joint`. Like
# `~mne.Evoked.plot_topomap` you can specify times for the scalp topographies
# or you can let the method choose times automatically, as is done here:

l_aud.plot_joint()

###############################################################################
# Global field power (GFP)
# ^^^^^^^^^^^^^^^^^^^^^^^^
#
# Global field power :footcite:`Lehmann1980,Lehmann1984,Murray2008` is,
# generally speaking, a measure of agreement of the signals picked up by all
# sensors across the entire scalp: if all sensors have the same value at a
# given time point, the GFP will be zero at that time point; if the signals
# differ, the GFP will be non-zero at that time point. GFP
# peaks may reflect "interesting" brain activity, warranting further
# investigation. Mathematically, the GFP is the population standard
# deviation across all sensors, calculated separately for every time point.
#
# You can plot the GFP using `evoked.plot(gfp=True) <mne.Evoked.plot>`. The GFP
# trace will be black if ``spatial_colors=True`` and green otherwise. The EEG
# reference does not affect the GFP:

# sphinx_gallery_thumbnail_number=11
for evk in (l_aud, l_vis):
    evk.plot(gfp=True, spatial_colors=True, ylim=dict(eeg=[-12, 12]))

###############################################################################
# To plot the GFP by itself you can pass ``gfp='only'`` (this makes it easier
# to read off the GFP data values, because the scale is aligned):

l_aud.plot(gfp='only')

###############################################################################
# As stated above, the GFP is the population standard deviation of the signal
# across channels. To compute it manually, we can leverage the fact that
# `evoked.data <mne.Evoked.data>` is a :class:`NumPy array <numpy.ndarray>`,
# and verify by plotting it using matplotlib commands:

gfp = l_aud.data.std(axis=0, ddof=0)

# Reproducing the MNE-Python plot style seen above
fig, ax = plt.subplots()
ax.plot(l_aud.times, gfp * 1e6, color='lime')
ax.fill_between(l_aud.times, gfp * 1e6, color='lime', alpha=0.2)
ax.set(xlabel='Time (s)', ylabel='GFP (µV)', title='EEG')

###############################################################################
# Analyzing regions of interest (ROIs): averaging across channels
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#
# Since our sample data is responses to left and right auditory and visual
# stimuli, we may want to compare left versus right ROIs. To average across
# channels in a region of interest, we first find the channel indices we want.
# Looking back at the 2D sensor plot above, we might choose the following for
# left and right ROIs:

left = ['eeg17', 'eeg18', 'eeg25', 'eeg26']
right = ['eeg23', 'eeg24', 'eeg34', 'eeg35']

left_ix = mne.pick_channels(l_aud.info['ch_names'], include=left)
right_ix = mne.pick_channels(l_aud.info['ch_names'], include=right)

###############################################################################
# Now we can create a new Evoked with 2 virtual channels (one for each ROI):
roi_dict = dict(left_ROI=left_ix, right_ROI=right_ix)
roi_evoked = mne.channels.combine_channels(l_aud, roi_dict, method='mean')
print(roi_evoked.info['ch_names'])
roi_evoked.plot()

###############################################################################
# Comparing conditions
# ^^^^^^^^^^^^^^^^^^^^
#
# If we wanted to compare our auditory and visual stimuli, a useful function is
# `mne.viz.plot_compare_evokeds`. By default this will combine all channels in
# each evoked object using global field power (or RMS for MEG channels); here
# instead we specify to combine by averaging, and restrict it to a subset of
# channels by passing ``picks``:

evokeds = dict(auditory=l_aud, visual=l_vis)
picks = [f'eeg{n}' for n in range(10, 15)]
mne.viz.plot_compare_evokeds(evokeds, picks=picks, combine='mean')

###############################################################################
# We can also easily get confidence intervals by treating each epoch as a
# separate observation using the `~mne.Epochs.iter_evoked` method. A confidence
# interval across subjects could also be obtained, by passing a list of
# `~mne.Evoked` objects (one per subject) to the
# `~mne.viz.plot_compare_evokeds` function.

evokeds = dict(auditory=list(epochs['auditory/left'].iter_evoked()),
               visual=list(epochs['visual/left'].iter_evoked()))
mne.viz.plot_compare_evokeds(evokeds, combine='mean', picks=picks)

###############################################################################
# We can also compare conditions by subtracting one `~mne.Evoked` object from
# another using the `mne.combine_evoked` function (this function also allows
# pooling of epochs without subtraction).

aud_minus_vis = mne.combine_evoked([l_aud, l_vis], weights=[1, -1])
aud_minus_vis.plot_joint()

###############################################################################
# .. warning::
#
#     The code above yields an **equal-weighted difference**. If you have
#     imbalanced trial numbers, you might want to equalize the number of events
#     per condition first by using `epochs.equalize_event_counts()
#     <mne.Epochs.equalize_event_counts>` before averaging.
#
#
# Grand averages
# ^^^^^^^^^^^^^^
#
# To compute grand averages across conditions (or subjects), you can pass a
# list of `~mne.Evoked` objects to `mne.grand_average`. The result is another
# `~mne.Evoked` object.

grand_average = mne.grand_average([l_aud, l_vis])
print(grand_average)

###############################################################################
# For combining *conditions* it is also possible to make use of :term:`HED`
# tags in the condition names when selecting which epochs to average. For
# example, we have the condition names:

list(event_dict)

###############################################################################
# We can select the auditory conditions (left and right together) by passing:

epochs['auditory'].average()

###############################################################################
# see :ref:`tut-section-subselect-epochs` for details.
#
# The tutorials :ref:`tut-epochs-class` and :ref:`tut-evoked-class` have many
# more details about working with the `~mne.Epochs` and `~mne.Evoked` classes.
#
# .. _ten_twenty: https://en.wikipedia.org/wiki/10%E2%80%9320_system_(EEG)
#
#
# References
# ----------
# .. footbibliography::