# Notebook from Juanreyna3/3D-Visualization-of-SARS-CoV-19-Protein-with-Biopython
Path: Master (1).ipynb

# 3D SARS-CoV-19 Protein Visualisation With Biopython_____no_output_____# Table of contents:

1. [Attributes of Biopython](#1.-Attributes-of-Biopython)
2. [Understand FASTA file format](#2.-Understanding-FASTA-file-format)
3. [Sequence manipulation using Biopython](#3.-Sequence-manipulation-using-Biopython)
4. [Transcription & Translation studies](#4.-Transcription-&-Translation-Studies)
5. [Perform Basic Local Alignment using NCBI-BLAST](#5.-Basic-Local-Alignment-Using-NCBI-BLAST)
6. [Reading PDB file](#6.-Reading-PDB-file)
7. [Visualizing SARS-CoV-19 Protein structure](#7.-Visualizing-SARS-CoV-19-Protein-structure)_____no_output_____## Biopython_____no_output_____

- Set of **tools** for **Biological computation**

- Written in **Python**

- Distributed **collaborative effort** to develop Python libraries and applications

- Address the needs of current and future work in **Bioinformatics**

_____no_output_____### Applications_____no_output_____

1. **Sequence Analysis** (DNA/RNA/Protein)

2. **Transcription** & **Translation studies**

3. Accessing **Bioinformatics Databases**

a. NCBI

b. PDB

4. **3D Structure** Analysis

_____no_output_____## MODULES_____no_output_____

import Bio
# import heapq
import pylab
import urllib
import pandas as pd
import nglview as nv
from Bio.Seq import Seq
from Bio.Blast import NCBIWWW
from Bio.Alphabet import IUPAC
from collections import Counter
from Bio.Data import CodonTable
from Bio import SeqIO, SearchIO
from Bio.PDB import PDBParser,MMCIFParser
from Bio.SeqUtils import GC,molecular_weight
# from dna_features_viewer import GraphicFeature, GraphicRecord
from Bio.Alphabet import generic_dna,generic_rna,generic_protein_____no_output_____

## 1. Attributes of Biopython_____no_output_____

# Check Attributes of Biopython
dir(Bio)_____no_output_____

## 2. Understanding FASTA file format

#### SEQUENCE SOURCE

 **COVID SEQUENCE FROM NCBI**_____no_output_____### 2.1. FASTA Format_____no_output_____### GENETIC MATERIAL

**DNA** (Deoxy-Ribonucleic Acid) constitutes of 4 Bases **A T G C**

**RNA** (Ribonucleic Acid) is composed of **U** instead of **T**

_____no_output_____### FASTA File

**\> Description_of_DNA_sequence**

ATGCTGCGAGACAGACAGACATACTATCATCTCAGACGCAG

ATGCTGCGAGACAGACAGACATACTATCATCTCAGACGCAG

_____no_output_____### 2.2. Reading from file_____no_output_____

# Loading FASTA file
seq_file_read = SeqIO.read("Sequence_data/sequence.fasta", "fasta")
# seq_file_parse = SeqIO.parse("sequence.fasta", "fasta")_____no_output_____type(seq_file_read)#,type(seq_file_parse)_____no_output_____

### 2.3 Sequence details_____no_output_____

# list sequence details
seq_file_read.id_____no_output_____# list sequence details
for record in SeqIO.parse("Sequence_data/sequence.fasta","fasta"):
    print(record)ID: MN908947.3
Name: MN908947.3
Description: MN908947.3 Severe acute respiratory syndrome coronavirus 2 isolate Wuhan-Hu-1, complete genome
Number of features: 0
Seq('ATTAAAGGTTTATACCTTCCCAGGTAACAAACCAACCAACTTTCGATCTCTTGT...AAA', SingleLetterAlphabet())
print(record.id)MN908947.3
# store sequence for later analysis
seqfromfile = record.seq
seqfromfile_____no_output_____# length of sequence
len(seqfromfile)_____no_output_____#molecular weight
molecular_weight(seqfromfile)_____no_output_____

## 3. Sequence manipulation using Biopython_____no_output_____

- indexing/slicing

- concatination

- codon search

- GC content

- complement

_____no_output_____### 3.1. Indexing / Slicing_____no_output_____

# CODON
seqfromfile[0:3]_____no_output_____

### 3.2. Concatination_____no_output_____

seqfromfile[0:3]+seqfromfile[-3:]_____no_output_____

### 3.3. Codon Search_____no_output_____

seqfromfile.find('AGA')_____no_output_____

### 3.4. GC Content_____no_output_____

# LOGIC
(seqfromfile.count('G') + seqfromfile.count('C'))/(len(seqfromfile)) * 100_____no_output_____#GC content using Biopython
GC(seqfromfile)_____no_output_____

### 3.5. Complement_____no_output_____

In **DNA**

    **A** Bonds with **T** (DOUBLE BOND)

    **G** Bonds with **C** (TRIPLE BOND)

_____no_output_____

seqfromfile[0:6]_____no_output_____#complement

seqfromfile[0:6].complement()_____no_output_____#reverse complement

seqfromfile[0:6].reverse_complement()_____no_output_____

## 4. Transcription & Translation Studies

DNA > RNA = Transcription

mRNA > amino acid (protein) = Translation

_____no_output_____### 4.1. Transcription_____no_output_____

#Transcribe

mRNA = seqfromfile.transcribe()
mRNA[:10]_____no_output_____#Back transcribe

mRNA.back_transcribe()[:10]_____no_output_____

### 4.2. Translation_____no_output_____

print(CodonTable.unambiguous_dna_by_id[1])Table 1 Standard, SGC0

  |  T      |  C      |  A      |  G      |
--+---------+---------+---------+---------+--
T | TTT F   | TCT S   | TAT Y   | TGT C   | T
T | TTC F   | TCC S   | TAC Y   | TGC C   | C
T | TTA L   | TCA S   | TAA Stop| TGA Stop| A
T | TTG L(s)| TCG S   | TAG Stop| TGG W   | G
--+---------+---------+---------+---------+--
C | CTT L   | CCT P   | CAT H   | CGT R   | T
C | CTC L   | CCC P   | CAC H   | CGC R   | C
C | CTA L   | CCA P   | CAA Q   | CGA R   | A
C | CTG L(s)| CCG P   | CAG Q   | CGG R   | G
--+---------+---------+---------+---------+--
A | ATT I   | ACT T   | AAT N   | AGT S   | T
A | ATC I   | ACC T   | AAC N   | AGC S   | C
A | ATA I   | ACA T   | AAA K   | AGA R   | A
A | ATG M(s)| ACG T   | AAG K   | AGG R   | G
--+---------+---------+---------+---------+--
G | GTT V   | GCT A   | GAT D   | GGT G   | T
G | GTC V   | GCC A   | GAC D   | GGC G   | C
G | GTA V   | GCA A   | GAA E   | GGA G   | A
G | GTG V   | GCG A   | GAG E   | GGG G   | G
--+---------+---------+---------+---------+--
protein_seq = seqfromfile.translate()
protein_seq[:10]/home/rhyme/.local/lib/python3.6/site-packages/Bio/Seq.py:2742: BiopythonWarning: Partial codon, len(sequence) not a multiple of three. Explicitly trim the sequence or add trailing N before translation. This may become an error in future.
  BiopythonWarning,
len(protein_seq)_____no_output_____len(seqfromfile)_____no_output_____

### Can protein sequences be reverse translated ?

Note : there is no function called `back_translate` so we'll make use of `back_transcribe`.

_____no_output_____

protein_seq[-10:]_____no_output_____protein_seq.back_transcribe()[-10:]_____no_output_____

### This error is true for all the biological life too...

- we can't perform an exact "reverse translation" of course, since several amino acids are produced by the same codon.

_____no_output_____

print(CodonTable.unambiguous_dna_by_id[1])Table 1 Standard, SGC0

  |  T      |  C      |  A      |  G      |
--+---------+---------+---------+---------+--
T | TTT F   | TCT S   | TAT Y   | TGT C   | T
T | TTC F   | TCC S   | TAC Y   | TGC C   | C
T | TTA L   | TCA S   | TAA Stop| TGA Stop| A
T | TTG L(s)| TCG S   | TAG Stop| TGG W   | G
--+---------+---------+---------+---------+--
C | CTT L   | CCT P   | CAT H   | CGT R   | T
C | CTC L   | CCC P   | CAC H   | CGC R   | C
C | CTA L   | CCA P   | CAA Q   | CGA R   | A
C | CTG L(s)| CCG P   | CAG Q   | CGG R   | G
--+---------+---------+---------+---------+--
A | ATT I   | ACT T   | AAT N   | AGT S   | T
A | ATC I   | ACC T   | AAC N   | AGC S   | C
A | ATA I   | ACA T   | AAA K   | AGA R   | A
A | ATG M(s)| ACG T   | AAG K   | AGG R   | G
--+---------+---------+---------+---------+--
G | GTT V   | GCT A   | GAT D   | GGT G   | T
G | GTC V   | GCC A   | GAC D   | GGC G   | C
G | GTA V   | GCA A   | GAA E   | GGA G   | A
G | GTG V   | GCG A   | GAG E   | GGG G   | G
--+---------+---------+---------+---------+--
# Listing the most common amino acids

common_amino = Counter(protein_seq)
common_amino.most_common(10)_____no_output_____del common_amino['*']_____no_output_____# visualize all 20 amino acid occurrences in the form of a histogram

pylab.bar(common_amino.keys(),common_amino.values())

pylab.title("%i protein sequences\n frquency %i to %i"
            % (len(common_amino.values()),
               min(common_amino.values()),
               max(common_amino.values())))

pylab.xlabel("Amino acid")
pylab.ylabel("frequency")
pylab.show()_____no_output_____

### Since stop codon * signifies end of a protein we can split the sequence using ( * )_____no_output_____

protein_list = [str(i) for i in protein_seq.split('*')]
protein_list[:10]_____no_output_____# convert sequences to dataframe
large_proteins = [x for x in protein_list if len(x)> 10]
df = pd.DataFrame({'protein_seq':large_proteins})_____no_output_____# Add a column with sequence lengths

df['length'] = df['protein_seq'].apply(len)
df.head()_____no_output_____# sort sequence data

df.sort_values(by = ['length'], ascending = False)[:10]_____no_output_____# let's take a single protein from the table

one_large_protein = df.nlargest(1,'length')
single_prot = one_large_protein.iloc[0,0]
single_prot_____no_output_____# write to a file

with open("Sequence_data/single_seq.fasta","w") as file:
    file.write(">largest_seq \n"+single_prot)
    _____no_output_____

## 5. Basic Local Alignment Using NCBI-BLAST_____no_output_____

# Read single_seq.fasta

read = SeqIO.read("Sequence_data/single_seq.fasta", "fasta")
read.seq_____no_output_____%%time

# based on the server load this query might take 2-3 minutes to run

result_handle = NCBIWWW.qblast("blastp","pdb",read.seq)

blast_qresult = SearchIO.read(result_handle, "blast-xml")CPU times: user 36.2 ms, sys: 5.12 ms, total: 41.3 ms
Wall time: 1min
print(blast_qresult[0:5])Program: blastp (2.10.1+)
  Query: unnamed (2701)
         protein product
 Target: pdb
   Hits: ----  -----  ----------------------------------------------------------
            #  # HSP  ID + description
         ----  -----  ----------------------------------------------------------
            0      1  pdb|6YYT|A  Chain A, nsp12 [Severe acute respiratory sy...
            1      1  pdb|6XEZ|A  Chain A, nsp12 [Severe acute respiratory sy...
            2      1  pdb|7BW4|A  Chain A, nsp12 [Severe acute respiratory sy...
            3      1  pdb|6X2G|A  Chain A, RNA-directed RNA polymerase [Sever...
            4      1  pdb|7BV1|A  Chain A, nsp12 [Severe acute respiratory sy...
#fetch the id, description, evalue, bitscore & alignment of first hit

seqid = blast_qresult[0]

details = seqid[0]

print(f"\
Sequence ID:{seqid.id}\n\
description:{seqid.description}\n\
E value:    {details.evalue} \n\
Bit Score:  {details.bitscore}\n\
")Sequence ID:pdb|6YYT|A
description:Chain A, nsp12 [Severe acute respiratory syndrome coronavirus 2]
E value:    0.0
Bit Score:  1938.31

print(f"alignment:\n{details.aln}")alignment:
ProteinAlphabet() alignment with 2 rows and 925 columns
FKRVCGVSAARLTPCGTGTSTDVVYRAFDIYNDKVAGFAKFLKT...VLQ unnamed
LNRVCGVSAARLTPCGTGTSTDVVYRAFDIYNDKVAGFAKFLKT...VLQ pdb|6YYT|A

## 6. Reading PDB file_____no_output_____### Retreiving PDB Structure From RCSB PDB_____no_output_____

seqid.id_____no_output_____# split seqid

seqid.id.split('|')[1]_____no_output_____# link format https://files.rcsb.org/download/6YYT.pdb

urllib.request.urlretrieve('https://files.rcsb.org/download/6YYT.pdb',
                           'Sequence_data/6YYT.pdb')_____no_output_____

### 6.1 Reading PDB file_____no_output_____

parser = PDBParser()

structure = parser.get_structure("6YYT","Sequence_data/6YYT.pdb")
structure/home/rhyme/.local/lib/python3.6/site-packages/Bio/PDB/StructureBuilder.py:92: PDBConstructionWarning: WARNING: Chain A is discontinuous at line 12059.
  PDBConstructionWarning,

### 6.2 Identifying the number of chains_____no_output_____

for chain in structure[0]:
    print(f"chainid: {chain.id}")chainid: A
chainid: B
chainid: C
chainid: D
chainid: P
chainid: Q
chainid: T
chainid: U

## 7. Visualizing SARS-CoV-19 Protein structure_____no_output_____### 7.1. nglview_____no_output_____

nv.demo()_____no_output_____view = nv.show_biopython(structure)
view_____no_output_____view.render_image()_____no_output_____

### 7.2. nglview GUI_____no_output_____

#GUI
view = nv.show_biopython(structure, gui=True)
view_____no_output_____view.render_image()_____no_output_____

## Observation:

A. Length 29903 base pairs

B. GC content 37.97

C. Protein content has high L & the largest protein is of length 2701 Amino acid

D. Largest protein BLAST results corresponds to SARS-CoV-19 6YYT

E. Protein 6YYT has 8 chains & a DNA binding domain

_____no_output_____## Further Reading
1. [**Transcription & Translation**](https://www.nature.com/scitable/topicpage/translation-dna-to-mrna-to-protein-393/)
2. [**Biopython Tutorial and Cookbook**](http://biopython.org/DIST/docs/tutorial/Tutorial.html)_____no_output_____


# Notebook from UWInSpace/InSpace
Path: notebooks/Unit_Testing_JK.ipynb

# Unit testing
Using nosetests_____no_output_____### `get_seq`_____no_output_____

def get_seq(email, prot_accession_num):
    from Bio import Entrez
    from Bio.SeqUtils.ProtParam import ProteinAnalysis

    Entrez.email = email

    gis = [prot_accession_num]
    request = Entrez.epost("protein",id=",".join(map(str,gis)))
    result = Entrez.read(request)
    webEnv = result["WebEnv"]
    queryKey = result["QueryKey"]
    handle = Entrez.efetch(db="protein",retmode="xml", webenv=webEnv, query_key=queryKey)

    for r in Entrez.parse(handle):
        try:
            gi=int([x for x in r['GBSeq_other-seqids'] if "gi" in x][0].split("|")[1])
        except ValueError:
            gi=None
        #print(r['GBSeq_sequence'])
        seq = r['GBSeq_sequence']
    return seq_____no_output_____def test_get_seq():
    seq = get_seq("karanjia@uw.edu", 728886557)
    expect = 'mlrsmltasttlnqlqqqidtissnlsnsnttgykakdtnfselvrqqfdqvdekneevakarktppglrlgvgammssrlvsdqgsiqktdrdldiaftspyqylqvnvngnrqytrdgalyvtpsaananqlqlvtgngypvldengntvnidssmknitinkngtltasdgnavqrfnlgvvqvnnpqelksegnnlfsidnaaafeelnganrqnigmqqgslemsnvdiseqmtdlitsqrsyqlnsrtitmgdqmlglinsvr'
    assert seq == expect, 'the get_seq function is not working'
    return_____no_output_____test_get_seq()_____no_output_____

### `usr_seq`_____no_output_____

def usr_seq(user_input, email):
    """If user input is an integer (EID and not a sequence that would be a string), get the sequence
    """
    t = type(user_input)
    if t is int:
        user_sequence = get_seq(email, user_input)
    else:
        user_sequence = user_input

    return user_sequence_____no_output_____def test_usr_seq():
    # Case 1: input is EID
    email = 'jaking11@uw.edu'
    usr_in = 15599626
    result = usr_seq(usr_in, email)
    assert result == 'mnkfmawvdarfpatkmwedhlskyyapknfnfwyffgslallvlvnqiltgiwltmsftpsaeeafasveyimrdvdygwiirymhstgasaffivvylhmfrgllygsyqkprelvwifgmliylalmaeafmgyllpwgqmsywgaqviislfgaipvvgedlaqwirgdflisgitlnrffalhvialpivllglvvlhilalhevgsnnpdgvdikkkkdengvpldgiafhpyytvkdivgvvvflfifctvifffpemggyflekpnfemanqfktpehiapvwyftpfyailravpdklmgvvamgaaiavlfvlpwldrspvrsirykgwlsklwlvifavsfvilgyygaqapsplgttlsrvctvlyfaffilmpfytrmektkpvpervtg', 'the usr_seq function does not work'
    return_____no_output_____test_usr_seq()_____no_output_____

### `get_prot_mass`_____no_output_____

def get_prot_mass(AASeq):

    '''Tabulate approximate total mass of input amino acid string based on the sum of
    the average masses for every amino acid in the string.'''

    # Create dict with amino acid sybols as keys and associated average masses as values
    # Average masses taken from http://proteomicsresource.washington.edu/protocols06/masses.php
    molecular_mass_dict = {
    'A':71.0779,
    'R':156.18568,
    'G':57.05132,
    'S':87.0773,
    'P':97.11518,
    'V':99.13106,
    'T':101.10388,
    'C':103.1429,
    'L':113.15764,
    'I':113.15764,
    'N':114.10264,
    'D':115.0874,
    'Q':128.12922,
    'K':128.17228,
    'E':129.11398,
    'M':131.19606,
    'H':137.13928,
    'F':147.17386,
    'U':150.3079,
    'Y':163.17326,
    'W':186.2099,
    'O':237.29816
    }

    # Calculate approx mass for amino acid sequence
    mass_list = []

    # Capitalize all letters in amino acid string prior to taking mass
    AASeq = AASeq.upper()

    # Raise error if amino acid sequence contains characters not in the dict
    acceptable_amino_acids_list = list(molecular_mass_dict.keys())

    for char in AASeq:
        if char not in acceptable_amino_acids_list:
            if char == ' ':
                continue
            else:
                raise ValueError('AASeq contains unacceptable characters')

    for amino_acid, mw in molecular_mass_dict.items():
        aa_weight = AASeq.count(amino_acid)*mw
        mass_list.append(aa_weight)
    total_mass = sum(mass_list)
    total_mass = round(total_mass, 2)

    return total_mass_____no_output_____def test_get_prot_mass():
    import math
    seq = 'TACO'
    result = get_prot_mass(seq)
    expect = 512.62
    assert math.isclose(result, expect), 'the get_prot_mass function does not work'
    return_____no_output_____test_get_prot_mass()_____no_output_____

### `get_biopy_feat`_____no_output_____

def get_biopy_feat(sequence):
    """
    Taken-in dataframe with a column specified as 'SEQUENCE' and uses Biopython to
    generate additional features from each protein sequence to help better train a machine
    learning model to predict log2FC
    """
    from Bio.SeqUtils.ProtParam import ProteinAnalysis
    ProtA = ProteinAnalysis(sequence)
    molwt_biopy = ProtA.molecular_weight()
    aromaticity = ProtA.aromaticity()
    isoelectric_pt = ProtA.isoelectric_point()

    return molwt_biopy, aromaticity, isoelectric_pt_____no_output_____def test_get_biopy_feat():
    import math
    seq = 'TACO'
    molwt_biopy, aromaticity, isoelectric_pt = get_biopy_feat(seq)
    expect = 530.6381
    assert math.isclose(molwt_biopy, expect), 'the get_biopy_feat function does not work'
    return_____no_output_____test_get_biopy_feat()_____no_output_____

### `count_aa_types`_____no_output_____

def count_aa_types(sequence):
    '''here, sequence is an element in a list, not a list itself
    Function takes the sequence, counts how many times amino acids occur per each of 4
    groups and returns values as percentages of the total amino acides in the sequence'''
    l = len(sequence)

    ninja = {
        'nonpolar': ['G', 'g', 'A', 'a', 'V', 'v', 'C', 'c', 'P', 'p', 'L', 'l', 'I', 'i', 'M', 'm', 'W', 'w', 'F', 'f'],
        'positive': ['K', 'k', 'R', 'r', 'H', 'h'],
        'polar': ['S', 's', 'T', 't', 'Y', 'y', 'N', 'n', 'Q', 'q'],
        'negative': ['D', 'd', 'E', 'e']
    }

    # Initiate lists for counts
    nonpolar_l = []
    positive_l = []
    polar_l = []
    negative_l = []

    for i in range(l):
        aa = sequence[i]
        if aa in ninja['nonpolar']:
            nonpolar_l.append(1)
        elif aa in ninja['positive']:
            positive_l.append(1)
        elif aa in ninja['polar']:
            polar_l.append(1)
        else:
            negative_l.append(1)

    # Sum the lists to return
    nonpolar_c = sum(nonpolar_l)
    positive_c = sum(positive_l)
    polar_c = sum(polar_l)
    negative_c = sum(negative_l)

    # Percentage calculation to return
    nonpolar = nonpolar_c / l *100
    nonpolar = round(nonpolar, 2)
    positive = positive_c / l *100
    positive = round(positive, 2)
    polar = polar_c / l *100
    polar = round(polar, 2)
    negative = negative_c / l *100
    negative = round(negative, 2)

    return nonpolar, positive, polar, negative_____no_output_____def test_count_aa_types():
    import math
    seq = 'TACO'
    nonpolar, positive, polar, negative = count_aa_types(seq)
    expect = 25.0
    assert math.isclose(polar, expect), 'the count_aa_types function does not work'
    return_____no_output_____test_count_aa_types()_____no_output_____

### `get_feat`_____no_output_____

def get_feat(user_sequence):
    """
    This function takes the sequence that the user is querying and returns a dataframe appended
    with all of the features used in the predictive model
    """
    import pandas as pd
    mass = get_prot_mass(user_sequence)

    molwt_biopy, aromaticity, isoelectric_pt = get_biopy_feat(user_sequence)

    nonpolar, positive, polar, negative = count_aa_types(user_sequence)

    # Make the features into a Pandas DataFrame
    column_names = ['AA_NP', 'AA_POS', 'AA_POL', 'AA_NEG', 'MW', 'AROM', 'ISO_E']
    feat_list = [nonpolar, positive, polar, negative, mass, aromaticity, isoelectric_pt]
    feat_df = pd.DataFrame([feat_list], columns=column_names)

    return feat_df_____no_output_____def test_get_feat():
    import math
    seq = 'TACO'
    df = get_feat(seq)
    result = df['MW']
    expect = 512.62
    assert math.isclose(result, expect), 'the get_feat function is not working'
    return_____no_output_____test_get_feat()_____no_output_____

### `scale_input_feat`_____no_output_____

def scale_input_feat(X):
    '''
    The function takes in X (our input features), and rescale based on min-max normalization
    it returns the normalized X
    '''
    import pandas as pd
    from sklearn import preprocessing
    #returns a numpy array for X (needed to use the min_max_scaler)
    X_arr = X.values

    X_col_names = list(X.columns.values.tolist()) #get column names to then put back into X_norm

    #min-max normalization (rescaling) of input features
    min_max_scaler = preprocessing.MinMaxScaler()
    X_scaled = min_max_scaler.fit_transform(X_arr)
    X_norm= pd.DataFrame(X_scaled)

    #put back the original column names
    X_norm.columns = X_col_names

    return X_norm_____no_output_____def test_scale_input_feat():
    import math
    import numpy as np
    import pandas as pd

    arr = np.array([[1, 2], [2, 3], [3, 1]])
    df = pd.DataFrame(arr)
    df_norm = scale_input_feat(df)
    result = df_norm[0].max()
    expect = 1.0
    assert math.isclose(result, expect), 'the scale_input_feat function is not working'
    return_____no_output_____test_scale_input_feat()_____no_output_____

### `bagging_regr`_____no_output_____

def bagging_regr(X_user):
    '''
    the function takes in the master csv and user input
    csv_file should be inputted as a string = 'compiled_features_complete.csv'
    test ratio, random state and n_estimator are set (from previous ML optimization)
    returning the predicted output based on user input
    '''
    import pandas as pd
    from sklearn import preprocessing

    from sklearn.model_selection import train_test_split
    from sklearn.metrics import mean_squared_error, r2_score
    from sklearn.ensemble import BaggingRegressor
    from sklearn.tree import DecisionTreeRegressor
    # Open and load dataset
    bacterial_csv = pd.read_csv('UWInSpace_ModelData.csv')
    df = pd.DataFrame(data=bacterial_csv)

    #assign input (X) /output (y) features
    X= df[['AA_NP','AA_POS', 'AA_POL','AA_NEG', 'MW', 'AROM', 'ISO_E']]
    y= df['LOG2FC']

    #Scale input features
    X_arr = X.values #returns a numpy array for X (needed to use the min_max_scaler)

    X_col_names = list(X.columns.values.tolist()) #get column names to then put back into X_norm

    #min-max normalization (rescaling) of input features
    min_max_scaler = preprocessing.MinMaxScaler()
    X_scaled = min_max_scaler.fit_transform(X_arr)
    X_norm= pd.DataFrame(X_scaled)

    #put back the original column names
    X_norm.columns = X_col_names

    #set Bagging regressor parameters, from ML training:
    test_ratio = 0.30
    seed_random = 42
    n_estim= 20

    X_train, X_test, y_train, y_test = train_test_split(X_norm, y, test_size=test_ratio, random_state=seed_random, shuffle=True)
    #Model is Bagging Regressor, base estimator is Decision Tree regressor
    model = BaggingRegressor(base_estimator=DecisionTreeRegressor(),n_estimators=n_estim, random_state=seed_random)
    model.fit(X_train, y_train)
    #y_testpredict = model.predict(X_test)

    user_predict = model.predict(X_user)

    return user_predict_____no_output_____def test_bagging_regr():
    import math
    import numpy as np
    import pandas as pd
    from sklearn import preprocessing
    from sklearn.model_selection import train_test_split
    from sklearn.metrics import mean_squared_error, r2_score
    from sklearn.ensemble import BaggingRegressor
    from sklearn.tree import DecisionTreeRegressor

    arr = np.array([[1, 0], [0.5, 0.5], [0.5, 1]])
    df = pd.DataFrame(arr)
    predict = scale_input_feat(df)
    result = df_norm[0].max()
    expect = 1.0
    assert math.isclose(result, expect), 'the scale_input_feat function is not working'
    return_____no_output_____

### `predict_log2fc`_____no_output_____

def predict_log2fc(user_input, email):
    """
    This function takes the user input of either a protein accesion number or
    an amino acid sequence and predicts how much the sequence will change after
    being in space (near-zero gravity and increased radiation exposure)
    """
    import Bio
    from Bio import Entrez
    from Bio.SeqUtils.ProtParam import ProteinAnalysis
    import math
    import pandas as pd
    import numpy as np
    import matplotlib.pyplot as plt

    # Import Scikit-Learn library for the regression model
    import sklearn
    from sklearn import preprocessing #sklearn for normalization function
    from sklearn.model_selection import train_test_split
    from sklearn.metrics import mean_squared_error, r2_score
    #for Bagging regressor
    from sklearn.ensemble import BaggingRegressor
    from sklearn.tree import DecisionTreeRegressor

    # Get user sequence
    user_sequence = usr_seq(user_input, email)

    # Get features
    user_features_df = get_feat(user_sequence)

    # Predict log2fc
    prediction = bagging_regr(user_features_df)
    prediction = prediction[0]
    prediction = round(prediction, 4)

    user_features_df['LOG2FC'] = [prediction]

    print('The predicted log2fc is ', prediction)

    return prediction, user_features_df_____no_output_____def test_predict_log2fc():
    import math
    user_input = 15600267
    email = 'jaking11@uw.edu'
    prediction, user_features_df = predict_log2fc(user_input, email)
    expect = 0.168
    assert math.isclose(prediction, expect), 'the predict_log2fc function does not work'
    return_____no_output_____test_predict_log2fc()The predicted log2fc is  0.168

### `cluster_visuals`_____no_output_____

def cluster_visuals(user_df, user_genecluster):
    import pandas as pd
    import seaborn as sns
    from matplotlib import pyplot as plt

    # set seaborn as default plotting language
    sns.set()

    # function definition
    # NASA_data is the "compiled features complete CSV", maybe need to change to final version of this

    UD = user_df
    NASA_data = pd.read_csv('UWInSpace_ModelData.csv')

    ND_ABC = NASA_data[NASA_data['GENENAME'] == 'ABC_transporter']
    ND_CYT = NASA_data[NASA_data['GENENAME'] == 'cytochrome']
    ND_DNA = NASA_data[NASA_data['GENENAME'] == 'DNA_polymerase']
    ND_EFF = NASA_data[NASA_data['GENENAME'] == 'efflux_transporter']
    ND_ELE = NASA_data[NASA_data['GENENAME'] == 'electron_transfer']
    ND_FLA = NASA_data[NASA_data['GENENAME'] == 'flagellar_motility']
    ND_NAD = NASA_data[NASA_data['GENENAME'] == 'NADH_NADPH']
    ND_RNA = NASA_data[NASA_data['GENENAME'] == 'RNA_polymerase']

    fig, axes = plt.subplots(1, 7, figsize= (15, 5), sharey=True)
    fig.suptitle('Comparison of features per user-specified gene cluster')

    if user_genecluster == 'ABC_transporter':
        ND = ND_ABC
    elif user_genecluster == 'cytochrome':
        ND = ND_CYT
    elif user_genecluster == 'DNA_polymerase':
        ND = ND_DNA
    elif user_genecluster == 'efflux_transporter':
        ND = ND_EFF
    elif user_genecluster == 'electron_transfer':
        ND = ND_ELE
    elif user_genecluster == 'flagellar_motility':
        ND = ND_FLA
    elif user_genecluster == 'NADH_NADPH':
        ND = ND_NAD
    elif user_genecluster == 'RNA_polymerase':
        ND = ND_RNA
    else:
        print('Please check your user-defined gene cluster and ensure that it matches the possible 8 categories')

    # user protein df
    p0a = sns.scatterplot(ax=axes[0], data=UD, x='AA_NP', y='LOG2FC', hue='LOG2FC', palette=['red'], legend=False)
    p1a = sns.scatterplot(ax=axes[1], data=UD, x='AA_POL', y='LOG2FC', hue='LOG2FC', palette=['red'], legend=False)
    p2a = sns.scatterplot(ax=axes[2], data=UD, x='AA_POS', y='LOG2FC', hue='LOG2FC', palette=['red'], legend=False)
    p3a = sns.scatterplot(ax=axes[3], data=UD, x='AA_NEG', y='LOG2FC', hue='LOG2FC', palette=['red'], legend=False)
    p4a = sns.scatterplot(ax=axes[4], data=UD, x='MW', y='LOG2FC', hue='LOG2FC', palette=['red'], legend=False)
    p5a = sns.scatterplot(ax=axes[5], data=UD, x='AROM', y='LOG2FC', hue='LOG2FC', palette=['red'], legend=False)
    p6a = sns.scatterplot(ax=axes[6], data=UD, x='ISO_E', y='LOG2FC', hue='LOG2FC', palette=['red'])

    p0 = sns.scatterplot(ax=axes[0], data=ND, x='AA_NP', y='LOG2FC', hue='ORG', legend=False)
    p1 = sns.scatterplot(ax=axes[1], data=ND, x='AA_POL', y='LOG2FC', hue='ORG', legend=False)
    p2 = sns.scatterplot(ax=axes[2], data=ND, x='AA_POS', y='LOG2FC', hue='ORG', legend=False)
    p3 = sns.scatterplot(ax=axes[3], data=ND, x='AA_NEG', y='LOG2FC', hue='ORG', legend=False)
    p4 = sns.scatterplot(ax=axes[4], data=ND, x='MW', y='LOG2FC', hue='ORG', legend=False)
    p5 = sns.scatterplot(ax=axes[5], data=ND, x='AROM', y='LOG2FC', hue='ORG', legend=False)
    p6 = sns.scatterplot(ax=axes[6], data=ND, x='ISO_E', y='LOG2FC', hue='ORG')

    return_____no_output_____


# Notebook from QMrpy/deepchem
Path: examples/tutorials/Training_a_Normalizing_Flow_on_QM9_PyTorch.ipynb

# Training a Normalizing Flow on QM9 in PyTorch
By [Rupayan Sarkar](https://github.com/QMrpy)

In this tutorial, we will train a Normalizing Flow (NF) on the [QM9 dataset](https://www.nature.com/articles/sdata201422). The dataset comprises 133,885 stable small organic molecules made up of CHNOF atoms. We will try to train a network that is an invertible transformation between a simple base distribution and the distribution of molecules in QM9.  One of the key advantages of normalizing flows is that they can be constructed to efficiently sample from a distribution (generative modeling) and do probability density calculations (exactly compute log-likelihoods), whereas other models make tradeoffs between the two or can only approximate probability densities.

NFs are useful whenever we need a probabilistic model with one or both of these capabilities. Note that because NFs are completely invertible, there is no "latent space" in the sense used when referring to generative adversarial networks or variational autoencoders. For more on NFs, we refer to this [review paper](https://arxiv.org/pdf/1912.02762.pdf).

To encode the QM9 dataset, we'll make use of the SELFIES (SELF-referencIng Embedded Strings) representation, which is a 100% robust molecular string representation. SMILES strings produced by generative models are often syntactically invalid (they do not correspond to a molecular graph), or they violate chemical rules like the maximum number of bonds between atoms. SELFIES are designed so that even totally random SELFIES strings correspond to valid molecular graphs, so they are a great framework for generative modeling. For more details about SELFIES, see the [GitHub repo](https://github.com/aspuru-guzik-group/selfies) and the associated [paper](https://arxiv.org/abs/1905.13741).

## Colab

This tutorial and the rest in this sequence are designed to be done in Google colab. If you'd like to open this notebook in colab, you can use the following link.

[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/deepchem/deepchem/blob/master/examples/tutorials/23_Training_a_Normalizing_Flow_on_QM9.ipynb)

## Setup

To run DeepChem within Colab, you'll need to run the following cell of installation commands. This will take about 5 minutes to run to completion and install your environment._____no_output_____

!curl -Lo conda_installer.py https://raw.githubusercontent.com/deepchem/deepchem/master/scripts/colab_install.py
import conda_installer
conda_installer.install()
!/root/miniconda/bin/conda info -e  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  3490  100  3490    0     0  15863      0 --:--:-- --:--:-- --:--:-- 15863
!pip install --pre deepchem
import deepchem
deepchem.__version__Collecting deepchem
  Downloading https://files.pythonhosted.org/packages/20/13/03547ffeca81a4d65fef79d0d13bd2eaf541408c606bbdbd67c0e2fec0b2/deepchem-2.4.0rc1.dev20200923221715.tar.gz (393kB)

     |▉                               | 10kB 16.1MB/s eta 0:00:01
     |█▋                              | 20kB 1.8MB/s eta 0:00:01
     |██▌                             | 30kB 2.1MB/s eta 0:00:01
     |███▎                            | 40kB 2.4MB/s eta 0:00:01
     |████▏                           | 51kB 1.8MB/s eta 0:00:01
     |█████                           | 61kB 2.1MB/s eta 0:00:01
     |█████▉                          | 71kB 2.3MB/s eta 0:00:01
     |██████▋                         | 81kB 2.6MB/s eta 0:00:01
     |███████▌                        | 92kB 2.7MB/s eta 0:00:01
     |████████▎                       | 102kB 2.6MB/s eta 0:00:01
     |█████████▏                      | 112kB 2.6MB/s eta 0:00:01
     |██████████                      | 122kB 2.6MB/s eta 0:00:01
     |██████████▉                     | 133kB 2.6MB/s eta 0:00:01
     |███████████▋                    | 143kB 2.6MB/s eta 0:00:01
     |████████████▌                   | 153kB 2.6MB/s eta 0:00:01
     |█████████████▎                  | 163kB 2.6MB/s eta 0:00:01
     |██████████████▏                 | 174kB 2.6MB/s eta 0:00:01
     |███████████████                 | 184kB 2.6MB/s eta 0:00:01
     |███████████████▉                | 194kB 2.6MB/s eta 0:00:01
     |████████████████▋               | 204kB 2.6MB/s eta 0:00:01
     |█████████████████▌              | 215kB 2.6MB/s eta 0:00:01
     |██████████████████▎             | 225kB 2.6MB/s eta 0:00:01
     |███████████████████▏            | 235kB 2.6MB/s eta 0:00:01
     |████████████████████            | 245kB 2.6MB/s eta 0:00:01
     |████████████████████▉           | 256kB 2.6MB/s eta 0:00:01
     |█████████████████████▋          | 266kB 2.6MB/s eta 0:00:01
     |██████████████████████▌         | 276kB 2.6MB/s eta 0:00:01
     |███████████████████████▎        | 286kB 2.6MB/s eta 0:00:01
     |████████████████████████▏       | 296kB 2.6MB/s eta 0:00:01
     |█████████████████████████       | 307kB 2.6MB/s eta 0:00:01
     |█████████████████████████▉      | 317kB 2.6MB/s eta 0:00:01
     |██████████████████████████▋     | 327kB 2.6MB/s eta 0:00:01
     |███████████████████████████▌    | 337kB 2.6MB/s eta 0:00:01
     |████████████████████████████▎   | 348kB 2.6MB/s eta 0:00:01
     |█████████████████████████████▏  | 358kB 2.6MB/s eta 0:00:01
     |██████████████████████████████  | 368kB 2.6MB/s eta 0:00:01
     |██████████████████████████████▉ | 378kB 2.6MB/s eta 0:00:01
     |███████████████████████████████▋| 389kB 2.6MB/s eta 0:00:01
     |████████████████████████████████| 399kB 2.6MB/s
Requirement already satisfied: joblib in /usr/local/lib/python3.6/dist-packages (from deepchem) (0.16.0)
Requirement already satisfied: numpy in /usr/local/lib/python3.6/dist-packages (from deepchem) (1.18.5)
Requirement already satisfied: pandas in /usr/local/lib/python3.6/dist-packages (from deepchem) (1.0.5)
Requirement already satisfied: scikit-learn in /usr/local/lib/python3.6/dist-packages (from deepchem) (0.22.2.post1)
Requirement already satisfied: scipy in /usr/local/lib/python3.6/dist-packages (from deepchem) (1.4.1)
Requirement already satisfied: python-dateutil>=2.6.1 in /usr/local/lib/python3.6/dist-packages (from pandas->deepchem) (2.8.1)
Requirement already satisfied: pytz>=2017.2 in /usr/local/lib/python3.6/dist-packages (from pandas->deepchem) (2018.9)
Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.6/dist-packages (from python-dateutil>=2.6.1->pandas->deepchem) (1.15.0)
Building wheels for collected packages: deepchem
  Building wheel for deepchem (setup.py) ... done
  Created wheel for deepchem: filename=deepchem-2.4.0rc1.dev20200924184214-cp36-none-any.whl size=499031 sha256=bb06a3dd7f6e432a05d18f54403bc00e292ddc9c52b8d5008c640c3153b917ee
  Stored in directory: /root/.cache/pip/wheels/c7/5c/0b/1f5cfa9461cf4af4190b45b7ae87ecc22ee5bdfb55748cfbe3
Successfully built deepchem
Installing collected packages: deepchem
Successfully installed deepchem-2.4.0rc1.dev20200924184214

Install the SELFIES library to translate SMILES strings._____no_output_____

!git clone https://github.com/aspuru-guzik-group/selfies.git
%cd selfies
!pip install .
%cd ..Cloning into 'selfies'...
remote: Enumerating objects: 157, done.
remote: Counting objects: 100% (157/157), done.
remote: Compressing objects: 100% (114/114), done.
remote: Total 2026 (delta 90), reused 85 (delta 43), pack-reused 1869
Receiving objects: 100% (2026/2026), 12.38 MiB | 17.27 MiB/s, done.
Resolving deltas: 100% (1276/1276), done.
/content/selfies
Processing /content/selfies
Building wheels for collected packages: selfies
  Building wheel for selfies (setup.py) ... done
  Created wheel for selfies: filename=selfies-1.0.1-cp36-none-any.whl size=27081 sha256=7c0b9aa7277c7a1103b657efc0354829b65851f2b2fa8e2082ae31544350be83
  Stored in directory: /tmp/pip-ephem-wheel-cache-lkv5aj3a/wheels/d0/8b/6e/8a44d44da67fdb190acc4f94129ff1428fc623ff9ad9a7abed
Successfully built selfies
Installing collected packages: selfies
Successfully installed selfies-1.0.1
/content
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import os

import deepchem as dc
from deepchem.models.torch_models.normalizing_flows import NormalizingFlow, NormalizingFlowModel
from deepchem.models.optimizers import Adam
from deepchem.data import NumpyDataset
from deepchem.splits import RandomSplitter
from deepchem.molnet import load_tox21

import rdkit
from rdkit.Chem import Draw

from IPython.display import Image, display

import selfies as sf

import torch
import torch.distributions as distribution/usr/local/lib/python3.6/dist-packages/statsmodels/tools/_testing.py:19: FutureWarning: pandas.util.testing is deprecated. Use the functions in the public API at pandas.testing instead.
  import pandas.util.testing as tm

First, let's get a dataset of 2500 small organic molecules from the QM9 dataset. We'll then convert the molecules to SELFIES, one-hot encode them, and dequantize the inputs so they can be processed by a normalizing flow. 2000 molecules will be used for training, while the remaining 500 will be split into validation and test sets. We'll use the validation set to see how our architecture is doing at learning the underlying the distribution, and leave the test set alone. You should feel free to experiment with this notebook to get the best model you can and evaluate it on the test set when you're done!_____no_output_____

# Download from MolNet
tasks, datasets, transformers = dc.molnet.load_qm9(featurizer='ECFP')
df = pd.DataFrame(data={'smiles': datasets[0].ids})_____no_output_____data = df[['smiles']].sample(2500, random_state=42)_____no_output_____

SELFIES defines a dictionary called `bond_constraints` that enforces how many bonds every atom or ion can make. E.g., 'C': 4, 'H': 1, etc. The `?` symbol is used for any atom or ion that isn't defined in the dictionary, and it defaults to 8 bonds. Because QM9 contains ions and we don't want to allow those ions to form up to 8 bonds, we'll constrain them to 3. This will really improve the percentage of valid molecules we generate. You can read more about setting constraints in the [SELFIES documentation](https://selfies-mirror.readthedocs.io/en/latest/selfies_examples.html#Advanced-Usage)._____no_output_____

sf.set_semantic_constraints()  # reset constraints
constraints = sf.get_semantic_constraints()
constraints['?'] = 3

sf.set_semantic_constraints(constraints)
constraints_____no_output_____def preprocess_smiles(smiles):
  return sf.encoder(smiles)

data['selfies'] = data['smiles'].apply(preprocess_smiles)_____no_output_____

Let's take a look at some short SMILES strings and their corresponding SELFIES representations. We can see right away that there is a key difference in how the two representations deal with Rings and Branches. SELFIES is designed so that branch length and ring size are stored locally with the `Branch` and `Ring` identifiers, and the SELFIES grammar prevents invalid strings._____no_output_____

data['len'] = data['smiles'].apply(lambda x: len(x))
data.sort_values(by='len').head()_____no_output_____

To convert SELFIES to a one-hot encoded representation, we need to construct an `alphabet` of all the characters that occur in the list of SELFIES strings. We also have to know what the longest SELFIES string is, so that all the shorter SELFIES can be padded with `'[nop]'` to be equal length._____no_output_____

selfies_list = np.asanyarray(data.selfies)
selfies_alphabet = sf.get_alphabet_from_selfies(selfies_list)
selfies_alphabet.add('[nop]')  # Add the "no operation" symbol as a padding character
selfies_alphabet = list(sorted(selfies_alphabet))
largest_selfie_len = max(sf.len_selfies(s) for s in selfies_list)_____no_output_____

`selfies` has a handy utility function to translate SELFIES strings into one-hot encoded vectors._____no_output_____

onehots = sf.multiple_selfies_to_hot(selfies_list, largest_selfie_len, selfies_alphabet)_____no_output_____

Next, we "dequantize" the inputs by adding random noise from the interval `[0, 1)` to every input in the encodings. This allows the normalizing flow to operate on continuous inputs (rather than discrete), and the original inputs can easily be recovered by applying a floor function._____no_output_____

input_tensor = torch.Tensor(onehots, dtype=torch.float64)
noise_tensor = torch.rand(input_tensor.shape, dtype=torch.float64)
dequantized_data = torch.add(input_tensor, noise_tensor)_____no_output_____

The dequantized data is ready to be processed as a DeepChem dataset and split into training, validation, and test sets. We'll also keep track of the SMILES strings for the training set so we can compare the training data to our generated molecules later on._____no_output_____

ds = NumpyDataset(dequantized_data)  # Create a DeepChem dataset
splitter = RandomSplitter()
train, val, test = splitter.train_valid_test_split(dataset=ds, seed=42)
train_idx, val_idx, test_idx = splitter.split(dataset=ds, seed=42)

dim = len(train.X[0])  # length of one-hot encoded vectors
train.X.shape  # 2000 samples, N-dimensional one-hot vectors that represent molecules_____no_output_____# SMILES strings of training data
train_smiles = data['smiles'].iloc[train_idx].values_____no_output_____

Next we'll set up the normalizing flow model. The base distribution is a multivariate Normal distribution._____no_output_____

base_dist = distribution.MultivariateNormal(torch.zeros(dim), torch.eye(dim))_____no_output_____from deepchem.models.torch_models.flow_models import PlanarFlow

num_layers = 8
flow_layers = []

nflow = PlanarFlow(dim)

for _ in range(num_layers):
    flow_layers.append(nflow)_____no_output_____

We can draw samples from the untrained distribution, but for now they don't have any relation to the QM9 dataset distribution._____no_output_____

%%time
nf = NormalizingFlow(base_distribution=base_dist,
                    flow_layers=flow_layers)
samples = nf.flow.sample(5)CPU times: user 45.7 s, sys: 1.77 s, total: 47.5 s
Wall time: 35.5 s

A `NormalizingFlowModel` takes a `NormalizingFlow` and any parameters used by `deepchem.models.KerasModel`._____no_output_____

nfm = NormalizingFlowModel(nf)_____no_output_____

Now to train the model! We'll try to minimize the negative log likelihood loss, which measures the likelihood that generated samples are drawn from the target distribution, i.e. as we train the model, it should get better at modeling the target distribution and it will generate samples that look like molecules from the QM9 dataset. _____no_output_____

losses = []
val_losses = []_____no_output_____%%time
max_epochs = 20 # maximum number of epochs of the training

for epoch in range(max_epochs):
  loss = nfm.fit(train)
  val_loss = nfm.loss(nfm.flow, val.X)
  val_losses.append(val_loss.numpy())WARNING:tensorflow:Model was constructed with shape (None, 588) for input Tensor("input_1:0", shape=(None, 588), dtype=float64), but it was called on an input with incompatible shape (1, 128, 588).
WARNING:tensorflow:Model was constructed with shape (None, 588) for input Tensor("input_1:0", shape=(None, 588), dtype=float64), but it was called on an input with incompatible shape (1, 128, 588).
WARNING:tensorflow:Model was constructed with shape (None, 588) for input Tensor("input_1:0", shape=(None, 588), dtype=float64), but it was called on an input with incompatible shape (1, 128, 588).
WARNING:tensorflow:Model was constructed with shape (None, 588) for input Tensor("input_1:0", shape=(None, 588), dtype=float64), but it was called on an input with incompatible shape (1, 128, 588).
WARNING:tensorflow:Model was constructed with shape (None, 588) for input Tensor("input_1:0", shape=(None, 588), dtype=float64), but it was called on an input with incompatible shape (1, 128, 588).
WARNING:tensorflow:Model was constructed with shape (None, 588) for input Tensor("input_1:0", shape=(None, 588), dtype=float64), but it was called on an input with incompatible shape (1, 128, 588).
WARNING:tensorflow:Model was constructed with shape (None, 588) for input Tensor("input_1:0", shape=(None, 588), dtype=float64), but it was called on an input with incompatible shape (1, 128, 588).
WARNING:tensorflow:Model was constructed with shape (None, 588) for input Tensor("input_1:0", shape=(None, 588), dtype=float64), but it was called on an input with incompatible shape (1, 128, 588).
WARNING:tensorflow:Model was constructed with shape (None, 588) for input Tensor("input_1:0", shape=(None, 588), dtype=float64), but it was called on an input with incompatible shape (1, 128, 588).
WARNING:tensorflow:Model was constructed with shape (None, 588) for input Tensor("input_1:0", shape=(None, 588), dtype=float64), but it was called on an input with incompatible shape (1, 128, 588).
WARNING:tensorflow:Model was constructed with shape (None, 588) for input Tensor("input_1:0", shape=(None, 588), dtype=float64), but it was called on an input with incompatible shape (1, 128, 588).
WARNING:tensorflow:Model was constructed with shape (None, 588) for input Tensor("input_1:0", shape=(None, 588), dtype=float64), but it was called on an input with incompatible shape (1, 128, 588).
WARNING:tensorflow:Model was constructed with shape (None, 588) for input Tensor("input_1:0", shape=(None, 588), dtype=float64), but it was called on an input with incompatible shape (1, 128, 588).
WARNING:tensorflow:Model was constructed with shape (None, 588) for input Tensor("input_1:0", shape=(None, 588), dtype=float64), but it was called on an input with incompatible shape (1, 128, 588).
WARNING:tensorflow:Model was constructed with shape (None, 588) for input Tensor("input_1:0", shape=(None, 588), dtype=float64), but it was called on an input with incompatible shape (1, 128, 588).
WARNING:tensorflow:Model was constructed with shape (None, 588) for input Tensor("input_1:0", shape=(None, 588), dtype=float64), but it was called on an input with incompatible shape (1, 128, 588).
WARNING:tensorflow:Model was constructed with shape (None, 588) for input Tensor("input_1:0", shape=(None, 588), dtype=float64), but it was called on an input with incompatible shape (1, 128, 588).
WARNING:tensorflow:Model was constructed with shape (None, 588) for input Tensor("input_1:0", shape=(None, 588), dtype=float64), but it was called on an input with incompatible shape (1, 128, 588).
WARNING:tensorflow:Model was constructed with shape (None, 588) for input Tensor("input_1:0", shape=(None, 588), dtype=float64), but it was called on an input with incompatible shape (1, 128, 588).
WARNING:tensorflow:Model was constructed with shape (None, 588) for input Tensor("input_1:0", shape=(None, 588), dtype=float64), but it was called on an input with incompatible shape (1, 128, 588).
WARNING:tensorflow:Model was constructed with shape (None, 588) for input Tensor("input_1:0", shape=(None, 588), dtype=float64), but it was called on an input with incompatible shape (1, 128, 588).
WARNING:tensorflow:Model was constructed with shape (None, 588) for input Tensor("input_1:0", shape=(None, 588), dtype=float64), but it was called on an input with incompatible shape (1, 128, 588).
WARNING:tensorflow:Model was constructed with shape (None, 588) for input Tensor("input_1:0", shape=(None, 588), dtype=float64), but it was called on an input with incompatible shape (1, 128, 588).
WARNING:tensorflow:Model was constructed with shape (None, 588) for input Tensor("input_1:0", shape=(None, 588), dtype=float64), but it was called on an input with incompatible shape (1, 128, 588).
WARNING:tensorflow:Model was constructed with shape (None, 588) for input Tensor("input_1:0", shape=(None, 588), dtype=float64), but it was called on an input with incompatible shape (1, 128, 588).
WARNING:tensorflow:Model was constructed with shape (None, 588) for input Tensor("input_1:0", shape=(None, 588), dtype=float64), but it was called on an input with incompatible shape (1, 128, 588).
WARNING:tensorflow:Model was constructed with shape (None, 588) for input Tensor("input_1:0", shape=(None, 588), dtype=float64), but it was called on an input with incompatible shape (1, 128, 588).
WARNING:tensorflow:Model was constructed with shape (None, 588) for input Tensor("input_1:0", shape=(None, 588), dtype=float64), but it was called on an input with incompatible shape (1, 128, 588).
WARNING:tensorflow:Model was constructed with shape (None, 588) for input Tensor("input_1:0", shape=(None, 588), dtype=float64), but it was called on an input with incompatible shape (1, 128, 588).
WARNING:tensorflow:Model was constructed with shape (None, 588) for input Tensor("input_1:0", shape=(None, 588), dtype=float64), but it was called on an input with incompatible shape (1, 128, 588).
WARNING:tensorflow:Model was constructed with shape (None, 588) for input Tensor("input_1:0", shape=(None, 588), dtype=float64), but it was called on an input with incompatible shape (1, 128, 588).
WARNING:tensorflow:Model was constructed with shape (None, 588) for input Tensor("input_1:0", shape=(None, 588), dtype=float64), but it was called on an input with incompatible shape (1, 128, 588).
CPU times: user 7min 9s, sys: 9.26 s, total: 7min 18s
Wall time: 3min 48s
f, ax = plt.subplots()
ax.scatter(range(len(losses)), losses, label='train loss')
ax.scatter(range(len(val_losses)), val_losses, label='val loss')
plt.legend(loc='upper right');_____no_output_____

The normalizing flow is learning a mapping between the multivariate Gaussian and the target distribution! We can see this by visualizing the loss on the validation set. We can now use `nfm.flow.sample()` to generate new QM9-like molecules and `nfm.flow.log_prob()` to evaluate the likelihood that a molecule was drawn from the underlying distribution._____no_output_____

generated_samples = nfm.flow.sample(50)  # generative modeling
log_probs = nfm.flow.log_prob(generated_samples)  # probability density estimation_____no_output_____

Now we transform the generated samples back into SELFIES. We have to quantize the outputs and add padding characters to any one-hot encoding vector that has all zeros._____no_output_____

mols = torch.floor(generated_samples)  # quantize data
mols = torch.clamp(mols, 0, 1)  # Set negative values to 0 and values > 1 to 1
mols_list = mols.numpy().tolist()

# Add padding characters if needed
for mol in mols_list:
  for i in range(largest_selfie_len):
    row = mol[len(selfies_alphabet) * i: len(selfies_alphabet) * (i + 1)]
    if all(elem == 0 for elem in row):
      mol[len(selfies_alphabet) * (i+1) - 1] = 1_____no_output_____

`selfies` has another utility function to translate one-hot encoded representations back to SELFIES strings._____no_output_____

mols = sf.multiple_hot_to_selfies(mols_list, largest_selfie_len, selfies_alphabet)_____no_output_____

We can use RDKit to find valid generated molecules. Some have unphysical valencies and should be discarded. If you've ever tried to generate valid SMILES strings, you'll notice right away that this model is doing much better than we would expect! Using SELFIES, 90\% of the generated molecules are valid, even though our normalizing flow architecture doesn't know any rules that govern chemical validity._____no_output_____

from rdkit import RDLogger
from rdkit import Chem
RDLogger.DisableLog('rdApp.*')  # suppress error messages

valid_count = 0
valid_selfies, invalid_selfies = [], []
for idx, selfies in enumerate(mols):
  try:
    if Chem.MolFromSmiles(sf.decoder(mols[idx]), sanitize=True) is not None:
        valid_count += 1
        valid_selfies.append(selfies)
    else:
      invalid_selfies.append(selfies)
  except Exception:
    pass
print('%.2f' % (valid_count / len(mols)),  '% of generated samples are valid molecules.')0.90 % of generated samples are valid molecules.

Let's take a look at some of the generated molecules! We'll borrow some helper functions from the [Modeling Solubility](https://github.com/deepchem/deepchem/blob/master/examples/tutorials/03_Modeling_Solubility.ipynb) tutorial to display molecules with RDKit._____no_output_____

gen_mols = [Chem.MolFromSmiles(sf.decoder(vs)) for vs in valid_selfies]_____no_output_____def display_images(filenames):
    """Helper to pretty-print images."""
    for file in filenames:
      display(Image(file))

def mols_to_pngs(mols, basename="generated_mol"):
    """Helper to write RDKit mols to png files."""
    filenames = []
    for i, mol in enumerate(mols):
        filename = "%s%d.png" % (basename, i)
        Draw.MolToFile(mol, filename)
        filenames.append(filename)
    return filenames_____no_output_____display_mols = []
for i in range(10):
  display_mols.append(gen_mols[i])

display_images(mols_to_pngs(display_mols))_____no_output_____

Finally, we can compare generated molecules with our training data via a [similarity search](https://medium.com/gsi-technology/rdkit-for-newbies-3697e617521f) with Tanimoto similarity. This gives an indication of how "original" the generated samples are, versus simply producing samples that are extremely similar to molecules the model has already seen. We have to keep in mind that QM9 contains *all* stable small molecules with up to 9 heavy atoms (CONF). So anything new we generate either exists in the full QM9 dataset, or else will not obey the charge neutrality and stability criteria used to generated QM9._____no_output_____

from rdkit.Chem.Fingerprints.FingerprintMols import FingerprintMol
from rdkit.DataStructs import FingerprintSimilarity
from IPython.display import display

def tanimoto_similarity(database_mols, query_mol):
    """Compare generated molecules to database by Tanimoto similarity."""
    # convert Mol to datastructure type
    fps = [FingerprintMol(m) for m in database_mols]

    # set a query molecule to compare against database
    query = FingerprintMol(query_mol)

    similarities = []

    # loop through to find Tanimoto similarity
    for idx, f in enumerate(fps):
        # tuple: (idx, similarity)
        similarities.append((idx, FingerprintSimilarity(query, f)))

    # sort sim using the similarities
    similarities.sort(key=lambda x:x[1], reverse=True)

    return similarities_____no_output_____

We'll consider our generated molecules and look at the top 3 most similar molecules from the training data by Tanimoto similarity. Here's an example where the Tanimoto similarity scores are low! There are no molecules in our training set that are very similar to our generated sample. This might be interesting, or it might mean that the generated molecule is unrealistic._____no_output_____

train_mols = [Chem.MolFromSmiles(smiles) for smiles in train_smiles]_____no_output_____# change the second argument to compare different generated molecules to QM9
tanimoto_scores = tanimoto_similarity(train_mols, gen_mols[3])
similar_mols = []_____no_output_____for idx, ts in tanimoto_scores[:3]:
    print(round(ts, 3))
    similar_mols.append(train_mols[idx])

display_images(mols_to_pngs(similar_mols, 'qm9_mol'))0.243
0.243
0.241

### Further reading

So far we have looked at a measure of validity and done a bit of investigation into the novelty of the generated compounds. There are more dimensions along which we can and should evaluate the performance of a generative model. For an example of some standard benchmarks, see the [GuacaMol evaluation framework](https://arxiv.org/pdf/1811.09621.pdf).

For examples of normalizing flow-based molecular graph generation frameworks, check out the [MoFlow](https://arxiv.org/abs/2006.10137), [GraphAF](https://arxiv.org/pdf/2001.09382.pdf), and [GraphNVP](https://arxiv.org/pdf/1905.11600.pdf) papers._____no_output_____# Congratulations! Time to join the Community!

Congratulations on completing this tutorial notebook! If you enjoyed working through the tutorial, and want to continue working with DeepChem, we encourage you to finish the rest of the tutorials in this series. You can also help the DeepChem community in the following ways:

## Star DeepChem on [GitHub](https://github.com/deepchem/deepchem)
This helps build awareness of the DeepChem project and the tools for open source drug discovery that we're trying to build.

## Join the DeepChem Gitter
The DeepChem [Gitter](https://gitter.im/deepchem/Lobby) hosts a number of scientists, developers, and enthusiasts interested in deep learning for the life sciences. Join the conversation!_____no_output_____


# Notebook from ynpreet/Technocolabs-data-science-internship
Path: Learn From the Basic to Advanced/Python for Data Science/exercise7-working-with-external-libraries-preet.ipynb

**This notebook is an exercise in the [Python](https://www.kaggle.com/learn/python) course.  You can reference the tutorial at [this link](https://www.kaggle.com/colinmorris/working-with-external-libraries).**

---
_____no_output_____# Try It Yourself

There are only three problems in this last set of exercises, but they're all pretty tricky, so be on guard!

Run the setup code below before working on the questions._____no_output_____

from learntools.core import binder; binder.bind(globals())
from learntools.python.ex7 import *
print('Setup complete.')Setup complete.

# Exercises_____no_output_____## 1.

After completing the exercises on lists and tuples, Jimmy noticed that, according to his `estimate_average_slot_payout` function, the slot machines at the Learn Python Casino are actually rigged *against* the house, and are profitable to play in the long run.

Starting with $200 in his pocket, Jimmy has played the slots 500 times, recording his new balance in a list after each spin. He used Python's `matplotlib` library to make a graph of his balance over time:_____no_output_____

# Import the jimmy_slots submodule
from learntools.python import jimmy_slots
# Call the get_graph() function to get Jimmy's graph
graph = jimmy_slots.get_graph()
graph_____no_output_____

As you can see, he's hit a bit of bad luck recently. He wants to tweet this along with some choice emojis, but, as it looks right now, his followers will probably find it confusing. He's asked if you can help him make the following changes:

1. Add the title "Results of 500 slot machine pulls"
2. Make the y-axis start at 0.
3. Add the label "Balance" to the y-axis

After calling `type(graph)` you see that Jimmy's graph is of type `matplotlib.axes._subplots.AxesSubplot`. Hm, that's a new one. By calling `dir(graph)`, you find three methods that seem like they'll be useful: `.set_title()`, `.set_ylim()`, and `.set_ylabel()`.

Use these methods to complete the function `prettify_graph` according to Jimmy's requests. We've already checked off the first request for you (setting a title).

(Remember: if you don't know what these methods do, use the `help()` function!)_____no_output_____

def prettify_graph(graph):
    """Modify the given graph according to Jimmy's requests: add a title, make the y-axis
    start at 0, label the y-axis. (And, if you're feeling ambitious, format the tick marks
    as dollar amounts using the "$" symbol.)
    """
    graph.set_title("Results of 500 slot machine pulls")
    # Complete steps 2 and 3 here

graph = jimmy_slots.get_graph()
prettify_graph(graph)
graph_____no_output_____

**Bonus:** Can you format the numbers on the y-axis so they look like dollar amounts? e.g. $200 instead of just 200.

(We're not going to tell you what method(s) to use here. You'll need to go digging yourself with `dir(graph)` and/or `help(graph)`.)_____no_output_____

# Check your answer (Run this code cell to receive credit!)
q1.solution()_____no_output_____

## 2. 🌶🌶

This is a very hard problem. Feel free to skip it if you are short on time:

Luigi is trying to perform an analysis to determine the best items for winning races on the Mario Kart circuit. He has some data in the form of lists of dictionaries that look like...

    [
        {'name': 'Peach', 'items': ['green shell', 'banana', 'green shell',], 'finish': 3},
        {'name': 'Bowser', 'items': ['green shell',], 'finish': 1},
        # Sometimes the racer's name wasn't recorded
        {'name': None, 'items': ['mushroom',], 'finish': 2},
        {'name': 'Toad', 'items': ['green shell', 'mushroom'], 'finish': 1},
    ]

`'items'` is a list of all the power-up items the racer picked up in that race, and `'finish'` was their placement in the race (1 for first place, 3 for third, etc.).

He wrote the function below to take a list like this and return a dictionary mapping each item to how many times it was picked up by first-place finishers._____no_output_____

def best_items(racers):
    """Given a list of racer dictionaries, return a dictionary mapping items to the number
    of times those items were picked up by racers who finished in first place.
    """
    winner_item_counts = {}
    for i in range(len(racers)):
        # The i'th racer dictionary
        racer = racers[i]
        # We're only interested in racers who finished in first
        if racer['finish'] == 1:
            for i in racer['items']:
                # Add one to the count for this item (adding it to the dict if necessary)
                if i not in winner_item_counts:
                    winner_item_counts[i] = 0
                winner_item_counts[i] += 1

        # Data quality issues :/ Print a warning about racers with no name set. We'll take care of it later.
        if racer['name'] is None:
            print("WARNING: Encountered racer with unknown name on iteration {}/{} (racer = {})".format(
                i+1, len(racers), racer['name'])
                 )
    return winner_item_counts_____no_output_____

He tried it on a small example list above and it seemed to work correctly:_____no_output_____

sample = [
    {'name': 'Peach', 'items': ['green shell', 'banana', 'green shell',], 'finish': 3},
    {'name': 'Bowser', 'items': ['green shell',], 'finish': 1},
    {'name': None, 'items': ['mushroom',], 'finish': 2},
    {'name': 'Toad', 'items': ['green shell', 'mushroom'], 'finish': 1},
]
best_items(sample)_____no_output_____

However, when he tried running it on his full dataset, the program crashed with a `TypeError`.

Can you guess why? Try running the code cell below to see the error message Luigi is getting. Once you've identified the bug, fix it in the cell below (so that it runs without any errors).

Hint: Luigi's bug is similar to one we encountered in the [tutorial](https://www.kaggle.com/colinmorris/working-with-external-libraries) when we talked about star imports._____no_output_____

# Import luigi's full dataset of race data
from learntools.python.luigi_analysis import full_dataset

# Fix me!
def best_items(racers):
    winner_item_counts = {}
    for i in range(len(racers)):
        # The i'th racer dictionary
        racer = racers[i]
        # We're only interested in racers who finished in first
        if racer['finish'] == 1:
            for item in racer['items']:
                # Add one to the count for this item (adding it to the dict if necessary)
                if i not in winner_item_counts:
                    winner_item_counts[i] = 0
                winner_item_counts[i] += 1

        # Data quality issues :/ Print a warning about racers with no name set. We'll take care of it later.
        if racer['name'] is None:
            print("WARNING: Encountered racer with unknown name on iteration {}/{} (racer = {})".format(
                i+1, len(racers), racer['name'])
                 )
    return winner_item_counts

# Try analyzing the imported full dataset
best_items(full_dataset)WARNING: Encountered racer with unknown name on iteration 4/8 (racer = None)
#q2.hint()_____no_output_____# Check your answer (Run this code cell to receive credit!)
q2.solution()_____no_output_____

## 3. 🌶

Suppose we wanted to create a new type to represent hands in blackjack. One thing we might want to do with this type is overload the comparison operators like `>` and `<=` so that we could use them to check whether one hand beats another. e.g. it'd be cool if we could do this:

```python
>>> hand1 = BlackjackHand(['K', 'A'])
>>> hand2 = BlackjackHand(['7', '10', 'A'])
>>> hand1 > hand2
True
```

Well, we're not going to do all that in this question (defining custom classes is a bit beyond the scope of these lessons), but the code we're asking you to write in the function below is very similar to what we'd have to write if we were defining our own `BlackjackHand` class. (We'd put it in the `__gt__` magic method to define our custom behaviour for `>`.)

Fill in the body of the `blackjack_hand_greater_than` function according to the docstring._____no_output_____

def hand_total(hand):
    """Helper function to calculate the total points of a blackjack hand.
    """
    total = 0
    # Count the number of aces and deal with how to apply them at the end.
    aces = 0
    for card in hand:
        if card in ['J', 'Q', 'K']:
            total += 10
        elif card == 'A':
            aces += 1
        else:
            # Convert number cards (e.g. '7') to ints
            total += int(card)
    # At this point, total is the sum of this hand's cards *not counting aces*.

    # Add aces, counting them as 1 for now. This is the smallest total we can make from this hand
    total += aces
    # "Upgrade" aces from 1 to 11 as long as it helps us get closer to 21
    # without busting
    while total + 10 <= 21 and aces > 0:
        # Upgrade an ace from 1 to 11
        total += 10
        aces -= 1
    return total

def blackjack_hand_greater_than(hand_1, hand_2):
    total_1 = hand_total(hand_1)
    total_2 = hand_total(hand_2)
    return total_1 <= 21 and (total_1 > total_2 or total_2 > 21)

# Check your answer
q3.check()_____no_output_____#q3.hint()
q3.solution()_____no_output_____

## The end

You've finished the Python course. Congrats!

As always, if you have any questions about these exercises, or anything else you encountered in the course, come to the [Learn Forum](https://kaggle.com/learn-forum).

You probably didn't put in all these hours of learning Python just to play silly games of chance, right? If you're interested in applying your newfound Python skills to some data science tasks, check out some of our other **[Kaggle Courses](https://www.kaggle.com/learn/overview)**. Some good next steps are:

1. [Machine learning with scikit-learn](https://www.kaggle.com/learn/intro-to-machine-learning)
2. [Pandas for data manipulation](https://www.kaggle.com/learn/pandas)
3. [Deep learning with TensorFlow](https://www.kaggle.com/learn/deep-learning)

Happy Pythoning!
_____no_output_____---

*Have questions or comments? Visit the [Learn Discussion forum](https://www.kaggle.com/learn-forum/161283) to chat with other Learners.*_____no_output_____


# Notebook from martinjzhang/scDRS
Path: experiments/job.ca1_pyramidal/00_prepare_dataset/ayhan_2021.ipynb

<code>
import numpy as np
import scanpy as sc
import pandas as pd
import matplotlib.pyplot as plt
from os.path import join_____no_output_____raw_dir = "raw/ayhan_2021/"_____no_output_____adata = sc.read_text(join(raw_dir, "exprMatrix.tsv.gz"))
meta = pd.read_csv(join(raw_dir, "meta.tsv"), sep="\t")
adata.var = meta
adata = adata.T
adata.obs = adata.obs.set_index("Cell")

umap = pd.read_csv(join(raw_dir, "Seurat_umap.coords.tsv.gz"), sep='\t', header=None, index_col=0, names=["Cell", "Seurat_umap1", "Seurat_umap2"])
assert (adata.obs.index == umap.index).all()
adata.obs[["Seurat_umap1", "Seurat_umap2"]] = umap[["Seurat_umap1", "Seurat_umap2"]]
sc.pp.filter_cells(adata, min_genes=0)
adata.write_h5ad("processed/ayhan_2021.raw.h5ad")/n/holystore01/LABS/price_lab/Users/khou/miniconda3/lib/python3.8/site-packages/anndata/_core/anndata.py:119: ImplicitModificationWarning: Transforming to str index.
  warnings.warn("Transforming to str index.", ImplicitModificationWarning)
... storing 'orig.ident' as categorical
... storing 'group' as categorical
... storing 'sex' as categorical
... storing 'batch' as categorical
... storing 'version' as categorical
... storing 'donor' as categorical
... storing 'Cluster' as categorical
adata = sc.read_h5ad("processed/ayhan_2021.raw.h5ad")_____no_output_____adata.obsm["X_umap"] = adata.obs[["Seurat_umap1", "Seurat_umap2"]]_____no_output_____adata_____no_output_____sc.set_figure_params(dpi=200)_____no_output_____?sc.pl.umap_____no_output_____sc.pl.umap(adata, color=["Cluster", "SATB2", "TYRO3", "PFKP", "FN1"], ncols=1, use_raw=False)_____no_output_____df_cov = pd.get_dummies(adata.obs[["n_genes", "nCount_RNA", "percent.mt", "age", "batch", "sex", "version", "epilepsy_duration", "epilepsy_frequency"]], drop_first=True)
print(np.linalg.matrix_rank(df_cov.values))

# make covariates (remove dependent columns)
df_cov = pd.get_dummies(adata.obs[["n_genes", "nCount_RNA", "percent.mt", "batch", "sex", "epilepsy_duration"]], drop_first=True)
print(np.linalg.matrix_rank(df_cov.values))
df_cov["const"] = 1.
df_cov.to_csv("processed/ayhan_2021.cov.tsv", sep='\t')8
8
# processed = raw.copy()
# sc.pp.highly_variable_genes(processed)
# processed = processed[:, processed.var.highly_variable]
# sc.pp.scale(processed, max_value=10)
# sc.tl.pca(processed, svd_solver='arpack')
# sc.pp.neighbors(processed, n_neighbors=10, n_pcs=40)
# sc.tl.umap(processed)
# raw.obsm["X_umap"] = raw.obs[['Seurat_umap1', 'Seurat_umap2']].values
# # visualize raw dataset
# sc.pl.umap(raw, color=["Cluster", "age", "sex", "batch"])
# for g in np.unique(raw.obs["orig.ident"]):
#     sub_adata = raw[raw.obs["orig.ident"] == g]
#     sc.pl.umap(sub_adata, color="Cluster")

# # visualize processed dataset
# for g in np.unique(processed.obs["orig.ident"]):
#     sub_adata = processed[processed.obs["orig.ident"] == g]
#     sc.pl.umap(sub_adata, color="Cluster")_____no_output_____
</code>


# Notebook from wulongyuan/tracktor
Path: examples/3d Termite_collective_behaviour.ipynb

import numpy as np
import pandas as pd
import tracktor as tr
import cv2
import sys
from sklearn.cluster import KMeans
from scipy.optimize import linear_sum_assignment
from scipy.spatial.distance import cdist_____no_output_____

## Global parameters
This cell (below) enlists user-defined parameters_____no_output_____

# colours is a vector of BGR values which are used to identify individuals in the video
# t_id is termite id and is also used for individual identification
# number of elements in colours should be greater than n_inds (THIS IS NECESSARY FOR VISUALISATION ONLY)
# number of elements in t_id should be greater than n_inds (THIS IS NECESSARY TO GET INDIVIDUAL-SPECIFIC DATA)
n_inds = 8
t_id = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
colours = [(0,0,255),(0,255,255),(255,0,255),(255,255,255),(255,255,0),(255,0,0),(0,255,0),(0,0,0)]

# this is the block_size and offset used for adaptive thresholding (block_size should always be odd)
# these values are critical for tracking performance
block_size = 51
offset = 20

# the scaling parameter can be used to speed up tracking if video resolution is too high (use value 0-1)
scaling = 1.0

# minimum area and maximum area occupied by the animal in number of pixels
# this parameter is used to get rid of other objects in view that might be hard to threshold out but are differently sized
min_area = 500
max_area = 10000

# mot determines whether the tracker is being used in noisy conditions to track a single object or for multi-object
# using this will enable k-means clustering to force n_inds number of animals
mot = True

# in this example, we use a circular mask to ignore area outside the petri-dish
# mask_offset represents offset of circle from centre of the frame
mask_offset_x = -18
mask_offset_y = -5

# name of source video and paths
video = 'termite_video'
input_vidpath = '/mnt/ssd1/Documents/Vivek/tracktor/videos/' + video + '.mp4'
output_vidpath = '/mnt/ssd1/Documents/Vivek/tracktor/output/' + video + '_tracked.mp4'
output_filepath = '/mnt/ssd1/Documents/Vivek/tracktor/output/' + video + '_tracked.csv'
codec = 'DIVX' # try other codecs if the default doesn't work ('DIVX', 'avc1', 'XVID') note: this list is non-exhaustive_____no_output_____

The cell below runs the tracking code_____no_output_____

## Open video
cap = cv2.VideoCapture(input_vidpath)
if cap.isOpened() == False:
    sys.exit('Video file cannot be read! Please check input_vidpath to ensure it is correctly pointing to the video file')

## Video writer class to output video with contour and centroid of tracked object(s)
# make sure the frame size matches size of array 'final'
fourcc = cv2.VideoWriter_fourcc(*codec)
output_framesize = (int(cap.read()[1].shape[1]*scaling),int(cap.read()[1].shape[0]*scaling))
out = cv2.VideoWriter(filename = output_vidpath, fourcc = fourcc, fps = 60.0, frameSize = output_framesize, isColor = True)

## Individual location(s) measured in the last and current step
meas_last = list(np.zeros((n_inds,2)))
meas_now = list(np.zeros((n_inds,2)))

df = []
last = 0

while(True):
    # Capture frame-by-frame
    ret, frame = cap.read()

    this = cap.get(1)
    if ret == True:
        # Preprocess the image for background subtraction
        frame = cv2.resize(frame, None, fx = scaling, fy = scaling, interpolation = cv2.INTER_LINEAR)

        # Apply mask to ignore area outside the petri dish
        mask = np.zeros((frame.shape[0], frame.shape[1]))
        cv2.circle(mask, (mask.shape[1]//2 + mask_offset_x, mask.shape[0]//2 + mask_offset_y), 520, 255, -1)
        frame[mask == 0] = 0

        thresh = tr.colour_to_thresh(frame, block_size, offset)
        # Custom background subtraction
        bg = thresh.copy()
        cv2.circle(bg, (bg.shape[1]//2 + mask_offset_x, bg.shape[0]//2 + mask_offset_y), 520, 0, -1)
        bgsub = thresh - bg

        final, contours, meas_last, meas_now = tr.detect_and_draw_contours(frame, thresh, meas_last, meas_now, min_area, max_area)
        if len(meas_now) != n_inds:
            contours, meas_now = tr.apply_k_means(contours, n_inds, meas_now)

        row_ind, col_ind = tr.hungarian_algorithm(meas_last, meas_now)
        final, meas_now, df = tr.reorder_and_draw(final, colours, n_inds, col_ind, meas_now, df, mot, this)

        # Create output dataframe
        for i in range(n_inds):
            df.append([this, meas_now[i][0], meas_now[i][1], t_id[i]])

        # Display the resulting frame
        out.write(final)
        cv2.imshow('frame', final)
        if cv2.waitKey(1) == 27:
            break

    if last >= this:
        break

    last = this

## Write positions to file
df = pd.DataFrame(np.matrix(df), columns = ['frame','pos_x','pos_y', 'id'])
df.to_csv(output_filepath, sep=',')

## When everything done, release the capture
cap.release()
out.release()
cv2.destroyAllWindows()
cv2.waitKey(1)_____no_output_____

## Summary statistics
The cells below provide functions to perform basic summary statistics - in this case, group polarisation and rotation around group centroid and rotation around centre of the arena. Polarisation measures how aligned individuals in a group are whereas rotation is a measure of the group being in a milling state aka. rotating. Checkout Tunstrom et al. 2013 PLoS Computational Biology for a more detailed description.

#### Group showing high polarisation                                                                       Group transitioning from high rotation to high polarisation

_____no_output_____

df = pd.read_csv(output_filepath)
df.head()_____no_output_____df = df.drop(columns=['Unnamed: 0'])
df['dir_x'] = df['pos_x'] - df['pos_x'].shift(n_inds)
df['dir_y'] = df['pos_y'] - df['pos_y'].shift(n_inds)
df['speed'] = np.sqrt(df['dir_x']**2 + df['dir_y']**2)
df['dir_x'] /= df['speed']
df['dir_y'] /= df['speed']

# drop any inf in data
df = df.replace([np.inf, -np.inf], np.nan).dropna(axis=0, how="any")

df.head()_____no_output_____for idx, ID in enumerate(np.unique(df['id'])):
    df['id'][df['id'] == ID] = idx/home/user/.local/lib/python3.6/site-packages/ipykernel_launcher.py:2: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy

import matplotlib.pyplot as plt

plt.figure(figsize=(8,8))
plt.scatter(df['pos_x'], df['pos_y'], c=df['id'], cmap='jet', alpha=0.5)
plt.xlabel('X', fontsize=16)
plt.ylabel('Y', fontsize=16)
plt.tight_layout()
plt.savefig('imgs/ex4_fig1.eps', format='eps', dpi=300)
plt.show()_____no_output_____df_ord = df.groupby(['frame']).mean()
df_ord = df_ord.reset_index()

df_ord = df_ord.rename(index=str, columns={'pos_x':'centroid_x', 'pos_y':'centroid_y', 'dir_x':'gdir_x', 'dir_y':'gdir_y', 'speed':'gspeed'})_____no_output_____df = pd.merge(df, df_ord, how='left')_____no_output_____tmpx = (df['pos_x'] - df['centroid_x'])
tmpy = (df['pos_y'] - df['centroid_y'])
df['centroid_disp_x'] = tmpx / np.linalg.norm((tmpx, tmpy), axis=0)
df['centroid_disp_y'] = tmpy / np.linalg.norm((tmpx, tmpy), axis=0)

tmpx = (df['pos_x'] - mask.shape[1]//2 + mask_offset_x)
tmpy = (df['pos_x'] - mask.shape[0]//2 + mask_offset_y)
df['arena_centre_disp_x'] = tmpx / np.linalg.norm((tmpx, tmpy), axis=0)
df['arena_centre_disp_y'] = tmpy / np.linalg.norm((tmpx, tmpy), axis=0)_____no_output_____centroid_disp = [df['centroid_disp_x'], df['centroid_disp_y']]
direction = [df['dir_x'], df['dir_y']]

arena_disp = [df['arena_centre_disp_x'], df['arena_centre_disp_y']]_____no_output_____df['rotation'] = np.cross(np.array(centroid_disp).T, np.array(direction).T)
df['arena_rotation'] = np.cross(np.array(arena_disp).T, np.array(direction).T)_____no_output_____df_ord = df.groupby(['frame']).agg(['sum', 'count'])
df_ord = df_ord.reset_index()_____no_output_____df_ord['polarisation'] = np.sqrt(df_ord['dir_x']['sum']**2 + df_ord['dir_y']['sum']**2) / df_ord['dir_x']['count']
df_ord['rotation'] = df_ord['rotation']['sum'].divide(df_ord['rotation']['count'])
df_ord['arena_rotation'] = df_ord['arena_rotation']['sum'].divide(df_ord['arena_rotation']['count'])_____no_output_____plt.figure(figsize=(30,3))
plt.plot(df_ord['frame']/30, df_ord['rotation']['sum'], color='r', label='Rotatioin (about group centroid)')
plt.plot(df_ord['frame']/30, df_ord['arena_rotation']['sum'], color='g', label='Rotation (about arena centre)')
plt.plot(df_ord['frame']/30, df_ord['polarisation'], color='b', label='Polarisation')
plt.xlabel('Time (s)', fontsize=16)
plt.legend(loc=1)
plt.tight_layout()
plt.savefig('imgs/ex4_fig2.eps', format='eps', dpi=300)
plt.show()_____no_output_____import seaborn as sns

plot = sns.jointplot(df_ord['polarisation'], df_ord['rotation']['sum'], xlim=[0,1], ylim=[-1,1], kind="hex", space=0, size = 7.5, stat_func=None, ratio=3)
plot.set_axis_labels('Polarisation', 'Rotation (about group centroid)', fontsize=16)
plt.tight_layout()
plt.savefig('imgs/ex4_fig3a.eps', format='eps', dpi=300)
plt.show()/home/user/.local/lib/python3.6/site-packages/matplotlib/axes/_axes.py:6462: UserWarning: The 'normed' kwarg is deprecated, and has been replaced by the 'density' kwarg.
  warnings.warn("The 'normed' kwarg is deprecated, and has been "
plot = sns.jointplot(df_ord['polarisation'], df_ord['arena_rotation']['sum'], xlim=[0,1], ylim=[-1,1], kind="hex", space=0, size = 7.5, stat_func=None, ratio=3)
plot.set_axis_labels('Polarisation', 'Rotation (about arena centre)', fontsize=16)
plt.tight_layout()
plt.savefig('imgs/ex4_fig3b.eps', format='eps', dpi=300)
plt.show()/home/user/.local/lib/python3.6/site-packages/matplotlib/axes/_axes.py:6462: UserWarning: The 'normed' kwarg is deprecated, and has been replaced by the 'density' kwarg.
  warnings.warn("The 'normed' kwarg is deprecated, and has been "
print(np.median(df_ord['polarisation']), np.median(np.abs(df_ord['rotation']['sum'])), np.median(np.abs(df_ord['arena_rotation']['sum'])))0.32835415043948535 0.21825415958494676 0.18926017785324067


# Notebook from singfie/Data-Driven-Optimization
Path: Reinforcement Learning - Monte Carlo Policy Evaluation for MDP with first visit policy.ipynb

Reinforcement Learning: Monte Carlo Policy Evaluation_____no_output_____

<code>
import numpy as np_____no_output_____class State: # a class to generate states in an MDP

    # initialize the state
    def __init__(self, state_name, actions, probabilities, rewards):

        self.state_name = state_name
        self.actions = actions
        self.probabilities = probabilities
        self.rewards = rewards
        self.counter = 0
        self.visits = 0
        self.active = False
        self.running_return = 0
    _____no_output_____class MDP: # a class to generate an MDP from given input data

    # initialize the MDP
    def __init__(self, statespace, probabilities, rewards, actions, discount):

        # check dimensionality

        if (probabilities.shape[0] != actions.shape[0]) or (probabilities.shape[1] != statespace.shape[0]):
            print("ERROR: Incorrect dimensionality: probability matrix does not match actions and state space!")

        if (rewards.shape[0] != actions.shape[0]) or (rewards.shape[1] != statespace.shape[0]):
            print("ERROR: Incorrect dimensionality: reward matrix does not match actions and state space!")

        else:

            # parameter initialization
            self.statespace = statespace
            self.discount = discount

            self.states = [] # a list to hold objects
            for i in range(len(self.statespace)):
                self.states.append(State(i, actions, probabilities[i], rewards[i]))

            # performance indicators
            self.iterations = 0

            #print("Initialized MDP")
            #print("-------------------------------------")

    # define a function to generate a random state at the beginning of the process
    def init_random_state(self):
        self.currentstate = np.random.choice(self.states, size=1, replace=False)[0]
        self.currentstate.active = True # activate new state
        #print("Initial state:", self.currentstate.state_name)
        #print("-------------------------------------")

    # define a function to perform an action on the MDP, which causes the state evolution
    def perform_action(self, action): # record data based on first visit policy

        self.iterations += 1
        #print("Iteration: ", self.iterations)

        if action in self.currentstate.actions: # perform action if it does exist in the set of actions of a state
            nextstate = np.random.choice(self.states,
                                         p = self.currentstate.probabilities[action],
                                         size=1, replace=False)[0]

        else: # if action does not exist, raise an error and choose one randomly
            print("Action not available in current state")
            print("Choosing randoms action instead!")
            action = np.random.choice(self.currentstate.actions, size=1, replace=False)[0]
            nextstate = np.random.choice(self.states,
                                         p = self.currentstate.probabilities[action],
                                         size=1, replace=False)[0]

        # update rewards and counter
        if nextstate.active == False:
            nextstate.running_return += (self.discount ** self.iterations) * self.currentstate.rewards[action, nextstate.state_name]

        # update visits and check whether state has been visited before
        #print("Next state: ", nextstate.state_name)
        nextstate.visits += 1 # update number of visits of state
        if nextstate.active == False: # if state not visited before, activate
            nextstate.active = True

        # print statistics to keep track of evolution
        #for i in self.states:
        #    print("Visits of state", i.state_name, ":", i.visits)
        #for i in self.states:
        #    print("Running reward of state", i.state_name, ":", i.running_return)

        # update the current state
        self.currentstate = nextstate
        #print("-------------------------------------")
    _____no_output_____# Example data
probabilities = np.array([[[0.1, 0.9],
                          [0.7, 0.3]],

                          [[0.2, 0.8],
                          [0.5, 0.5]]])

rewards = np.array([[[1, 4],
                    [-2, 5]],

                    [[3, -2],
                    [7, 5]]])

statespace = np.array([0,1])

actions = np.array([0,1])

discount = 0.9_____no_output_____# a function to generate all possible policies
def generate_policies(statespace, actions): #only works for statespace of 2

    options = np.array(np.meshgrid(statespace, actions)).T.reshape(-1,2)
    #print(options)
    policies = []
    for j in options:
        if j[0] == 0:
            for k in options:
                if k[0] != 0:
                    policies.append(np.array([j,k]))

    return(policies)_____no_output_____policies = generate_policies(statespace, actions)_____no_output_____# initialize value functions and returns
J = [[[] for _ in range(len(statespace))] for _ in range(len(policies))]
Returns = [[[] for _ in range(len(statespace))] for _ in range(len(policies))]

for k in range(len(policies)):
    # initialize policy
    policy = policies[k]

    np.random.seed(k * 2) # set random seed

    # initialize number of episodes
    episodes = 1000 # tested empirically to show convergence
    # initialize number of steps per episode
    steps = 100 # tested emprically to be a reasonable number

    for j in range(episodes):

        #print("Episode", j)

        #initialize MDP with random state
        mdp = MDP(statespace, probabilities, rewards, actions, discount)
        mdp.init_random_state()

        # iterate through all steps on each episode
        for i in range(steps):
            active_state = mdp.currentstate.state_name # obtain active state
            mdp.perform_action(policy[active_state][1]) # execute action as per policy

        # append returns list after the episode (consider that discountin was done in the MDP)
        for i in mdp.states:
            Returns[k][i.state_name].append(i.running_return)
            J[k][i.state_name].append(np.mean(Returns[k][i.state_name]))
_____no_output_____from matplotlib import pyplot as plt

plt.style.use('seaborn-whitegrid')

plt.figure(figsize=[10,10])

t = range(episodes)

pol0_J0 = J[0][0]
pol0_J1 = J[0][1]
pol1_J0 = J[1][0]
pol1_J1 = J[1][1]
pol2_J0 = J[2][0]
pol2_J1 = J[2][1]
pol3_J0 = J[3][0]
pol3_J1 = J[3][1]

#plot2 = plt.subplot(122)
plt.plot(t, pol0_J0, label = 'Policy 0: J state 0')
plt.plot(t, pol0_J1, label = 'Policy 0: J state 1')
plt.plot(t, pol1_J0, label = 'Policy 1: J state 0')
plt.plot(t, pol1_J1, label = 'Policy 1: J state 1')
plt.plot(t, pol2_J0, label = 'Policy 2: J state 0')
plt.plot(t, pol2_J1, label = 'Policy 2: J state 1')
plt.plot(t, pol3_J0, label = 'Policy 3: J state 0')
plt.plot(t, pol3_J1, label = 'Policy 3: J state 1')

plt.xlabel("Episodes")
plt.ylabel("Value of policy use per state")
plt.legend(loc="upper right")
plt.title("Evolution of value function for each state under different policies")

#plt.savefig('Results.png', dpi = 800)

plt.show()_____no_output_____
</code>