# Notebook from shakeelzafar3/reconstruction
Path: MNIST_CNN.ipynb

_____no_output_____

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

"""PSO module
Copyright (c) 2017 Future Processing sp. z.o.o.
@author: Pablo Ribalta Lorenzo
@email: pribalta@future-processing.com)
@date: 10.04.2017
This module encapsulates all the functionality related to Particle
Swarm Optimization, including the algorithm itself and the Particles
"""

import copy
import numpy as np

class Particle(object):
    """Particle class for PSO
    This class encapsulates the behavior of each particle in PSO and provides
    an efficient way to do bookkeeping about the state of the swarm in any given
    iteration.
    Args:
        lower_bound (np.array): Vector of lower boundaries for particle dimensions.
        upper_bound (np.array): Vector of upper boundaries for particle dimensions.
        dimensions (int): Number of dimensions of the search space.
        objective function (function): Black-box function to evaluate.
    """
    def __init__(self,
                 lower_bound,
                 upper_bound,
                 dimensions,
                 objective_function):
        self.reset(dimensions, lower_bound, upper_bound, objective_function)

    def reset(self,
              dimensions,
              lower_bound,
              upper_bound,
              objective_function):
        """Particle reset
        Allows for reset of a particle without reallocation.
		Args:
			lower_bound (np.array): Vector of lower boundaries for particle dimensions.
			upper_bound (np.array): Vector of upper boundaries for particle dimensions.
			dimensions (int): Number of dimensions of the search space.
        """
        position = []
        for i in range(dimensions):
            if lower_bound[i] < upper_bound[i]:
                position.extend(np.random.randint(lower_bound[i], upper_bound[i] + 1, 1, dtype=int))
            elif lower_bound[i] == upper_bound[i]:
                position.extend(np.array([lower_bound[i]], dtype=int))
            else:
                assert False

        self.position = [position]

        self.velocity = [np.multiply(np.random.rand(dimensions),
                                     (upper_bound - lower_bound)).astype(int)]

        self.best_position = self.position[:]

        self.function_value = [objective_function(self.best_position[-1])]
        self.best_function_value = self.function_value[:]

    def update_velocity(self, omega, phip, phig, best_swarm_position):
        """Particle velocity update
		Args:
			omega (float): Velocity equation constant.
			phip (float): Velocity equation constant.
			phig (float): Velocity equation constant.
			best_swarm_position (np.array): Best particle position.
        """
        random_coefficient_p = np.random.uniform(size=np.asarray(self.position[-1]).shape)
        random_coefficient_g = np.random.uniform(size=np.asarray(self.position[-1]).shape)

        self.velocity.append(omega
                             * np.asarray(self.velocity[-1])
                             + phip
                             * random_coefficient_p
                             * (np.asarray(self.best_position[-1])
                                - np.asarray(self.position[-1]))
                             + phig
                             * random_coefficient_g
                             * (np.asarray(best_swarm_position)
                                - np.asarray(self.position[-1])))

        self.velocity[-1] = self.velocity[-1].astype(int)

    def update_position(self, lower_bound, upper_bound, objective_function):
        """Particle position update
		Args:
			lower_bound (np.array): Vector of lower boundaries for particle dimensions.
			upper_bound (np.array): Vector of upper boundaries for particle dimensions.
			objective function (function): Black-box function to evaluate.
        """
        new_position = self.position[-1] + self.velocity[-1]

        if np.array_equal(self.position[-1], new_position):
            self.function_value.append(self.function_value[-1])
        else:
            mark1 = new_position < lower_bound
            mark2 = new_position > upper_bound

            new_position[mark1] = lower_bound[mark1]
            new_position[mark2] = upper_bound[mark2]

            self.function_value.append(objective_function(self.position[-1]))

        self.position.append(new_position.tolist())

        if self.function_value[-1] < self.best_function_value[-1]:
            self.best_position.append(self.position[-1][:])
            self.best_function_value.append(self.function_value[-1])

class Pso(object):
    """PSO wrapper
    This class contains the particles and provides an abstraction to hold all the context
    of the PSO algorithm
    Args:
        swarmsize (int): Number of particles in the swarm
        maxiter (int): Maximum number of generations the swarm will run
    """
    def __init__(self, swarmsize=100, maxiter=100):
        self.max_generations = maxiter
        self.swarmsize = swarmsize

        self.omega = 0.5
        self.phip = 0.5
        self.phig = 0.5

        self.minstep = 1e-4
        self.minfunc = 1e-4

        self.best_position = [None]
        self.best_function_value = [1]

        self.particles = []

        self.retired_particles = []

    def run(self, function, lower_bound, upper_bound, kwargs=None):
        """Perform a particle swarm optimization (PSO)
		Args:
			objective_function (function): The function to be minimized.
			lower_bound (np.array): Vector of lower boundaries for particle dimensions.
			upper_bound (np.array): Vector of upper boundaries for particle dimensions.
		Returns:
			best_position (np.array): Best known position
			accuracy (float): Objective value at best_position
			:param kwargs:
        """
        if kwargs is None:
            kwargs = {}

        objective_function = lambda x: function(x, **kwargs)
        assert hasattr(function, '__call__'), 'Invalid function handle'

        assert len(lower_bound) == len(upper_bound), 'Invalid bounds length'

        lower_bound = np.array(lower_bound)
        upper_bound = np.array(upper_bound)

        assert np.all(upper_bound > lower_bound), 'Invalid boundary values'

        dimensions = len(lower_bound)

        self.particles = self.initialize_particles(lower_bound,
                                                   upper_bound,
                                                   dimensions,
                                                   objective_function)

        # Start evolution
        generation = 1
        while generation <= self.max_generations:
            for particle in self.particles:
                particle.update_velocity(self.omega, self.phip, self.phig, self.best_position[-1])
                particle.update_position(lower_bound, upper_bound, objective_function)

                if particle.best_function_value[-1] == 0:
                    self.retired_particles.append(copy.deepcopy(particle))
                    particle.reset(dimensions, lower_bound, upper_bound, objective_function)
                elif particle.best_function_value[-1] < self.best_function_value[-1]:
                    stepsize = np.sqrt(np.sum((np.asarray(self.best_position[-1])
                                               - np.asarray(particle.position[-1])) ** 2))

                    if np.abs(np.asarray(self.best_function_value[-1])
                              - np.asarray(particle.best_function_value[-1])) \
                            <= self.minfunc:
                        return particle.best_position[-1], particle.best_function_value[-1]
                    elif stepsize <= self.minstep:
                        return particle.best_position[-1], particle.best_function_value[-1]
                    else:
                        self.best_function_value.append(particle.best_function_value[-1])
                        self.best_position.append(particle.best_position[-1][:])

            generation += 1

        return self.best_position[-1], self.best_function_value[-1]

    def initialize_particles(self,
                             lower_bound,
                             upper_bound,
                             dimensions,
                             objective_function):
        """Initializes the particles for the swarm
		Args:
			objective_function (function): The function to be minimized.
			lower_bound (np.array): Vector of lower boundaries for particle dimensions.
			upper_bound (np.array): Vector of upper boundaries for particle dimensions.
			dimensions (int): Number of dimensions of the search space.
		Returns:
			particles (list): Collection or particles in the swarm
        """
        particles = []
        for _ in range(self.swarmsize):
            particles.append(Particle(lower_bound,
                                      upper_bound,
                                      dimensions,
                                      objective_function))
            if particles[-1].best_function_value[-1] < self.best_function_value[-1]:
                self.best_function_value.append(particles[-1].best_function_value[-1])
                self.best_position.append(particles[-1].best_position[-1])

        self.best_position = [self.best_position[-1]]
        self.best_function_value = [self.best_function_value[-1]]

        return particles

'''Trains a simple convnet on the MNIST dataset.
Gets to 99.25% test accuracy after 12 epochs
(there is still a lot of margin for parameter tuning).
16 seconds per epoch on a GRID K520 GPU.
'''

from __future__ import print_function
import keras
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras import backend as K

batch_size = 128
num_classes = 10
epochs = 100

# input image dimensions
img_rows, img_cols = 28, 28

# the data, shuffled and split between train and test sets
(x_train, y_train), (x_test, y_test) = mnist.load_data()

if K.image_data_format() == 'channels_first':
    x_train = x_train.reshape(x_train.shape[0], 1, img_rows, img_cols)
    x_test = x_test.reshape(x_test.shape[0], 1, img_rows, img_cols)
    input_shape = (1, img_rows, img_cols)
else:
    x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1)
    x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1)
    input_shape = (img_rows, img_cols, 1)

x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255
print('x_train shape:', x_train.shape)
print(x_train.shape[0], 'train samples')
print(x_test.shape[0], 'test samples')

# convert class vectors to binary class matrices
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)

def func(x):
  n,sf,sp,l = x[0],x[1],x[2],x[3]

  model = Sequential()
  model.add(Conv2D(32,kernel_size=(3, 3),
                 activation='relu',
                 input_shape=input_shape))
  model.add(Conv2D(64, (3, 3), activation='relu'))
  model.add(Conv2D(n, (sf, sf), activation='relu'))
  model.add(MaxPooling2D(pool_size=(sp, sp),strides=(l,l)))
  model.add(Flatten())
  model.add(Dense(num_classes, activation='softmax'))
  model.compile(loss=keras.losses.categorical_crossentropy,
              optimizer=keras.optimizers.Adam(),
              metrics=['accuracy'])

  cp = [keras.callbacks.EarlyStopping(monitor='val_loss', patience=5, verbose=0, mode='auto')];

  model.fit(x_train, y_train,
            batch_size=batch_size,
            epochs=epochs,
            verbose=0,
            validation_data=(x_test, y_test),callbacks=cp)

  score = model.evaluate(x_test, y_test, verbose=0)

  # loss, val
  print('current config:',x,'val:',score[1])
  return score[1]

##################################################################
pso = Pso(swarmsize=4,maxiter=14)
# n,sf,sp,l
bp,value = pso.run(func,[1,2,2,2],[16,8,4,4])

v = func(bp);

##################################################################

print('Test loss:', bp)
print('Test accuracy:', value,v)Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz
11493376/11490434 [==============================] - 0s 0us/step
x_train shape: (60000, 28, 28, 1)
60000 train samples
10000 test samples
current config: [10, 8, 4, 4] val: 0.9886000156402588
current config: [3, 7, 2, 2] val: 0.9846000075340271
current config: [14, 6, 3, 2] val: 0.989300012588501
current config: [12, 6, 4, 2] val: 0.9879000186920166
current config: [10, 8, 4, 4] val: 0.9884999990463257
current config: [3, 7, 2, 2] val: 0.9861000180244446
current config: [14, 6, 3, 2] val: 0.9909999966621399
current config: [12, 6, 4, 2] val: 0.9918000102043152
current config: [11, 8, 4, 4] val: 0.9873999953269958
current config: [11, 8, 3, 2] val: 0.9907000064849854
current config: [16, 7, 4, 2] val: 0.9919999837875366
current config: [10, 8, 4, 4] val: 0.9898999929428101
current config: [5, 8, 2, 2] val: 0.9894000291824341
current config: [7, 8, 3, 2] val: 0.9894999861717224
current config: [15, 7, 4, 2] val: 0.9901000261306763
current config: [7, 8, 4, 4] val: 0.9886000156402588
current config: [6, 8, 3, 2] val: 0.989799976348877
current config: [10, 7, 4, 2] val: 0.9907000064849854
current config: [5, 8, 4, 4] val: 0.9896000027656555
current config: [5, 8, 3, 2] val: 0.9894000291824341
current config: [7, 7, 4, 2] val: 0.9896000027656555
current config: [7, 8, 3, 2] val: 0.9896000027656555
current config: [4, 8, 4, 4] val: 0.9891999959945679
current config: [8, 8, 3, 2] val: 0.9891999959945679
current config: [5, 8, 4, 4] val: 0.9883000254631042
current config: [7, 8, 4, 4] val: 0.9890999794006348
current config: [10, 8, 3, 2] val: 0.9908000230789185
current config: [8, 8, 4, 4] val: 0.988099992275238
current config: [8, 7, 4, 2] val: 0.9919999837875366
current config: [3, 7, 2, 2] val: 0.9890999794006348
Test loss: [3, 7, 2, 2]
Test accuracy: 0.9846000075340271 0.9890999794006348
_____no_output_____


# Notebook from ofou/course-content
Path: tutorials/W3D3_OptimalControl/W3D3_Intro.ipynb

[![Kaggle](https://kaggle.com/static/images/open-in-kaggle.svg)](https://kaggle.com/kernels/welcome?src=https://raw.githubusercontent.com/NeuromatchAcademy/course-content/master/tutorials/W3D3_OptimalControl/W3D3_Intro.ipynb)_____no_output_____# Intro_____no_output_____**Our 2021 Sponsors, including Presenting Sponsor Facebook Reality Labs**

_____no_output_____## Overview

Today you will learn about Optimal Control. Previously you used observations to draw inferences about a hidden state. Now you get to act. The Intro video teaches you about the formalism: you have a dynamic process that you get to act upon, and you choose your actions to maximize a utility function. The tutorials will continue to explore our two running examples, fishing and astrocat, for binary and gaussian variables. In the fishing example, you’ll use your Hidden Markov Models to figure out where the fish are, and then update your fishing location to catch the most fish. In the Astrocat example, you will learn to use the cat’s jetpack to keep the cat on target. Your core learning objective is to understand and implement algorithms to use your knowledge to select good actions. The Outro video talks about applications of these ideas to how you plan.

Optimal Control combines ideas from the Hidden Dynamics lessons (which used Hidden Markov Models) with maximizing utility described in the Bayes day (which combined a posterior with a utility function). It also connects directly to later lessons in Reinforcement Learning, which learns how to control before you understand the world. In contrast, Optimal Control assumes that you already know how the world works.

Optimal Control is a crucial model in motor neuroscience, because it provides a principled benchmark for how we expect an animal should move. It also is an important engineering method, used for brain-computer interfaces and clamping neurons to desired activity patterns._____no_output_____## Video_____no_output_____

# @markdown
from ipywidgets import widgets

out2 = widgets.Output()
with out2:
  from IPython.display import IFrame
  class BiliVideo(IFrame):
      def __init__(self, id, page=1, width=400, height=300, **kwargs):
          self.id=id
          src = "https://player.bilibili.com/player.html?bvid={0}&page={1}".format(id, page)
          super(BiliVideo, self).__init__(src, width, height, **kwargs)

  video = BiliVideo(id=f"BV1T54y1B7GJ", width=854, height=480, fs=1)
  print("Video available at https://www.bilibili.com/video/{0}".format(video.id))
  display(video)

out1 = widgets.Output()
with out1:
  from IPython.display import YouTubeVideo
  video = YouTubeVideo(id=f"bIMf8pWu0xU", width=854, height=480, fs=1, rel=0)
  print("Video available at https://youtube.com/watch?v=" + video.id)
  display(video)

out = widgets.Tab([out1, out2])
out.set_title(0, 'Youtube')
out.set_title(1, 'Bilibili')

display(out)_____no_output_____

## Slides_____no_output_____

# @markdown
from IPython.display import IFrame
IFrame(src=f"https://mfr.ca-1.osf.io/render?url=https://osf.io/2uc6v/?direct%26mode=render%26action=download%26mode=render", width=854, height=480)_____no_output_____


# Notebook from saroudant/sobolev_alignment_manuscript
Path: figure_3/model_I/results_analysis_model_I.ipynb

# Model I: generate data, perform Sobolev Alignment and analyse results._____no_output_____

import os, sys, pylab, gc, umap, re, scanpy, torch, scipy
import numpy as np
import seaborn as sns
from anndata import AnnData
import matplotlib.pyplot as plt
from functools import reduce
from pickle import dump, load
from copy import deepcopy
import pandas as pd
from joblib import Parallel, delayed
import umap, scvi
from statannot import add_stat_annotation
from shutil import copyfile
import rpy2
import rpy2.robjects as robjects
from rpy2.robjects import pandas2ri
from sklearn.decomposition import PCA
from time import process_time
%config IPCompleter.use_jedi = False

from sobolev_alignment import SobolevAlignment, KRRApprox

source_palette = {'common': '#7F91D0', 'specific': '#71AB5A', 'half': 'tab:grey'}
target_palette = {'common': '#7F91D0', 'specific': '#C89E34', 'half': 'tab:grey'}_____no_output_____

## Generate data
Call outside script to generate the data using Dyngen.

WARNING: Launching this script may work better in the console, reducing the overhead of Jupyter Notebook._____no_output_____

!sh generate_data.sh_____no_output_____

## Pre-processing
Pre-process the data previously generated to format it for Sobolev Alignment.
### Import data_____no_output_____

n_targets = 5
X_source = scanpy.read_h5ad('./data/source_dataset_large_targets_%s.h5ad'%(n_targets))
X_target = scanpy.read_h5ad('./data/target_dataset_large_targets_%s.h5ad'%(n_targets))

# Densify data
X_source.X = np.array(X_source.X.todense())
X_target.X = np.array(X_target.X.todense())

# Change simulation as string
X_target.obs['simulation_i'] = X_target.obs['simulation_i'].astype(str)
X_source.obs['simulation_i'] = X_source.obs['simulation_i'].astype(str)_____no_output_____

### Potential filtering_____no_output_____

def remove_target_kousekeeping_genes(X):
    is_target = np.array(X.var.index.str.contains('Target'))
    is_housekeeping = np.array(X.var.index.str.contains('HK'))
    to_remove = (~is_target) & (~is_housekeeping)

    return X[:,to_remove]

X_source = remove_target_kousekeeping_genes(X_source)
X_target = remove_target_kousekeeping_genes(X_target)_____no_output_____

### Save data_____no_output_____

X_combined = pd.concat({
    'CELL_LINE': X_source.to_df(),
    'TUMOR' : X_target.to_df()
})

# Save files
X_combined.to_csv('./data/combined_counts.csv', sep=',')_____no_output_____

## Sobolev Alignment
Performs and save Sobolev Alignment between source and target.

WARNING: Launching this script may work better in the console, reducing the overhead of Jupyter Notebook._____no_output_____

!sh launch_model_I.sh_____no_output_____

## Post-processing
Performs the analysis presented in the manuscript._____no_output_____

output_folder = './output/'
figure_folder = './figures/'_____no_output_____

### Computation of factor weights_____no_output_____

%run ./model_I_scripts/compute_feature_weights.py -o ${output_folder} -j 4 -m 6_____no_output_____

### Load Sobolev Alignment_____no_output_____

# Input data
X_combined = pd.read_csv(
    './data/combined_counts.csv'%(output_folder),
    sep=',',
    index_col=[0,1]
)
X_source = X_combined.loc['CELL_LINE']
X_target = X_combined.loc['TUMOR']
X_input = {'source': X_source, 'target': X_target}_____no_output_____iter_idx = 0
sobolev_alignment_clf = {}

# Load Sobolev Alignment
for kernel_type in ['laplacian', 'gaussian']:
    if 'iter_%s_nu_%s'%(iter_idx, kernel_type) not in os.listdir(output_folder):
        continue
    sobolev_alignment_clf[kernel_type] = SobolevAlignment.load(
        '%s/iter_%s_nu_%s/sobolev_alignment_model'%(output_folder, iter_idx, kernel_type),
        with_krr=True,
        with_model=False
    )

    sobolev_alignment_clf[kernel_type].training_data = {
        'source': X_source,
        'target': X_target
    }

    sobolev_alignment_clf[kernel_type].krr_log_input_ = True_____no_output_____X_log_input = {
    'source': sobolev_alignment_clf['laplacian'].approximate_krr_regressions_['source'].anchors(),
    'target': sobolev_alignment_clf['laplacian'].approximate_krr_regressions_['target'].anchors()
}

X_log_input = {
    x: pd.DataFrame(X_log_input[x].detach().numpy(), columns=X_source.columns)
    for x in X_log_input
}_____no_output_____

## Goodness of fit
Compares the KRR predictions with the actual scVI embeddings._____no_output_____

latent_embedding = {
    x: pd.read_csv('%s/scvi_embedding_%s.csv'%(output_folder, x), header=None, sep=' ')
    for x in ['source', 'target']
}_____no_output_____plt.figure(figsize=(8,3))
prediction_latent_corr = {}
for data_source in ['source', 'target']:
    print('START %s'%(data_source))

    prediction_latent_corr[data_source] = []
    krr_pred = sobolev_alignment_clf['laplacian'].approximate_krr_regressions_[data_source].transform(
        torch.Tensor(
            sobolev_alignment_clf['laplacian']._frobenius_normalisation(
                data_source,
                np.log10(X_input[data_source] + 1),
                frob_norm_source=True
    ).values))
    target_spearman_corr = []
    for x in range(krr_pred.shape[1]):
        prediction_latent_corr[data_source].append(
            scipy.stats.spearmanr(krr_pred[:,x], latent_embedding[data_source][x])[0]
        )

    sns.distplot(
        prediction_latent_corr[data_source],
        label='CELL LINE' if data_source == 'source' else 'TUMOR',
        kde_kws={"lw": 3}
    )

plt.xlabel('Spearman correlation between\n KRR and scVI', fontsize=20, color='black')
plt.xticks(fontsize=15)
plt.ylabel('Proportion', fontsize=20, color='black')
plt.yticks([], [])
plt.legend(fontsize=15)
plt.tight_layout()
plt.savefig('%s/hist_spearman_corr_reconstruction_latent.png'%(figure_folder))
plt.show()_____no_output_____

## Recompute all PVs (if need be)_____no_output_____

for kernel_type in sobolev_alignment_clf:
    sobolev_alignment_clf[kernel_type]._compute_principal_vectors(all_PVs=True)
    sobolev_alignment_clf[kernel_type].save(
        folder='%s/iter_%s_nu_%s/sobolev_alignment_model'%(output_folder, iter_idx, kernel_type),
        with_krr=True,
        with_model=False
    )_____no_output_____

## Import corrected terms_____no_output_____### Linear_____no_output_____

from supporting_scripts.linear_terms_treatment import read_latent_factors
from supporting_scripts.linear_terms_treatment import process_df
from supporting_scripts.linear_terms_treatment import aggregate_norm_comparison
from supporting_scripts.linear_terms_treatment import process_PV_linear_norm_comparison
from supporting_scripts.linear_terms_treatment import correct_linear_features
from supporting_scripts.linear_terms_treatment import assess_equality_contribution
from supporting_scripts.linear_terms_treatment import process_linear_weights
from supporting_scripts.linear_terms_treatment import compute_gene_std
from supporting_scripts.linear_terms_treatment import _compute_kernel_param_____no_output_____# Read data
n_iter = 0
kernel_name = 'laplacian'

source_PV_linear_features = read_latent_factors(
    output_folder,
    'PV_linear_weights_source_order_1',
    n_iter,
    kernel_name
)
target_PV_linear_features = read_latent_factors(
    output_folder,
    'PV_linear_weights_target_order_1',
    n_iter,
    kernel_name
)

# Process files
source_PV_linear_features = process_df(source_PV_linear_features, square_value=True)
target_PV_linear_features = process_df(target_PV_linear_features, square_value=True)_____no_output_____# Format DataFrame
source_linear_PV_norm_comparison = process_PV_linear_norm_comparison(
    source_PV_linear_features.groupby(['kernel', 'factor', 'iter']).agg('sum'),
    kernel_name=kernel_name
)
target_linear_PV_norm_comparison = process_PV_linear_norm_comparison(
    target_PV_linear_features.groupby(['kernel', 'factor', 'iter']).agg('sum'),
    kernel_name=kernel_name
)

# Correct scaling coefficient between Gaussian and Laplacian
source_PV_linear_features = correct_linear_features(source_PV_linear_features, source_linear_PV_norm_comparison)
target_PV_linear_features = correct_linear_features(target_PV_linear_features, target_linear_PV_norm_comparison)

# Assert that the norm correction is correct
assess_equality_contribution(source_PV_linear_features)
assess_equality_contribution(target_PV_linear_features)

# Put the matrix in form genes x P
source_linear_weights = process_linear_weights(source_PV_linear_features, kernel_name=kernel_name)
target_linear_weights = process_linear_weights(target_PV_linear_features, kernel_name=kernel_name)

# Process the gene names
source_PV_linear_features['variable'] = source_PV_linear_features['variable'].str.extract(r'([A-Za-z0-9-_]*)\^1')
target_PV_linear_features['variable'] = target_PV_linear_features['variable'].str.extract(r'([A-Za-z0-9-_]*)\^1')_____no_output_____# Correct for standard deviation
gamma = {s: _compute_kernel_param(s, sobolev_alignment_clf) for s in ['source', 'target']}
assert gamma['source'] == gamma['target']
gamma = gamma['source']

# Compute feature-level (gene * exp offset) standard deviation
all_genes_std = {
    data_source: compute_gene_std(
        X_log_input[data_source],
        np.exp(- gamma * np.square(np.linalg.norm(X_log_input[data_source], axis=1)))
    )
    for data_source in ['source', 'target']
}
all_genes_std = {
    data_source: pd.DataFrame(all_genes_std[data_source], index=['feature_std']).T
    for data_source in ['source', 'target']
}

# Merge dataset and correct
source_PV_linear_features = source_PV_linear_features.merge(
    all_genes_std['source'],
    left_on='variable',
    right_index=True
)
target_PV_linear_features = target_PV_linear_features.merge(
    all_genes_std['target'],
    left_on='variable',
    right_index=True
)

# Correct naming
source_PV_linear_features['variable'] = source_PV_linear_features['variable'].str.replace('_TF1', '')
target_PV_linear_features['variable'] = target_PV_linear_features['variable'].str.replace('_TF1', '')

# WARNING: HAS TO BE MULTIPLIED BY STANDARD DEVIATION
for df in [source_PV_linear_features, target_PV_linear_features]:
    df['standardized_value'] = df['corrected_value'] * df['feature_std']_____no_output_____source_PV_linear_features = source_PV_linear_features.set_index('kernel').loc[kernel_name]
source_PV_linear_features = source_PV_linear_features.pivot(
    index='variable',
    columns='factor',
    values='standardized_value'
)

target_PV_linear_features = target_PV_linear_features.set_index('kernel').loc[kernel_name]
target_PV_linear_features = target_PV_linear_features.pivot(
    index='variable',
    columns='factor',
    values='standardized_value'
)_____no_output_____

### Interactions_____no_output_____

from supporting_scripts.interaction_terms_treatment import read_interaction_weights
from supporting_scripts.interaction_terms_treatment import compute_all_interactions_std, _compute_kernel_param_____no_output_____iter_idx = 0

source_file_radical = 'PV_linear_weights_source_order_2'
source_interaction_scaling_coef, source_PV_interaction_features = read_interaction_weights(
    file_radical=source_file_radical,
    output_folder=output_folder,
    iter_idx=iter_idx,
    kernel_name=kernel_name
)

target_file_radical = 'PV_linear_weights_target_order_2'
target_interaction_scaling_coef, target_PV_interaction_features = read_interaction_weights(
    file_radical=target_file_radical,
    output_folder=output_folder,
    iter_idx=iter_idx,
    kernel_name=kernel_name
)
gc.collect()_____no_output_____

#### Correct for standard deviation_____no_output_____

interactions_std = {
    data_source: compute_all_interactions_std(
        X_log_input[data_source],
        np.exp(- gamma * np.square(np.linalg.norm(X_log_input[data_source], axis=1)))
    ) for data_source in X_log_input
}
interactions_std = {
    data_source: pd.DataFrame(
        reduce(lambda x,y: x + y, interactions_std[data_source]),
        columns=['gene_A', 'gene_B', 'interaction_std']
    ).set_index(['gene_A', 'gene_B'])
    for data_source in interactions_std
}_____no_output_____source_PV_interaction_features = pd.concat(
    [source_PV_interaction_features, interactions_std['source']],
    axis=1
)
for col in source_PV_interaction_features.columns:
    if col == 'interactions_std':
        continue
    source_PV_interaction_features[col] *= source_PV_interaction_features['interaction_std']
del source_PV_interaction_features['interaction_std']

target_PV_interaction_features = pd.concat(
    [target_PV_interaction_features, interactions_std['target']],
    axis=1
)
for col in target_PV_interaction_features.columns:
    if col == 'interactions_std':
        continue
    target_PV_interaction_features[col] *= target_PV_interaction_features['interaction_std']
del target_PV_interaction_features['interaction_std']_____no_output_____

### Compute square loadings_____no_output_____

for col in source_PV_linear_features.columns:
    source_PV_linear_features['%s_squared'%(col)] = np.square(source_PV_linear_features[col])
    source_PV_interaction_features['%s_squared'%(col)] = np.square(source_PV_interaction_features[col])
for col in target_PV_linear_features.columns:
    target_PV_linear_features['%s_squared'%(col)] = np.square(target_PV_linear_features[col])
    target_PV_interaction_features['%s_squared'%(col)] = np.square(target_PV_interaction_features[col])_____no_output_____

### Comparison all weights_____no_output_____

def plot_contribution_prop(data_source):
    weights = {}
    weights_sum = {}

    # Read coefficients
    for i in range(1,5):
        weights[i] = pd.read_pickle(
            '%s/iter_0_nu_gaussian/PV_linear_weights_%s_order_%s.gz'%(output_folder, data_source, i),
            compression='gzip'
        )
        weights_sum[i] = np.sum(np.square(weights[i]), axis=1)

    # Format weights and plot
    weights_sum_df = pd.concat(weights_sum, axis=1)
    weights_sum_df.index = ['SPV %s'%(i+1) for i in range(weights_sum_df.shape[0])]
    weights_sum_df.plot.bar(stacked=True, width=0.95)
    plt.axhline(1, linestyle='--', color='black')

    plt.legend(loc='center left', bbox_to_anchor=(1, 0.5), fontsize=15).set_title('Order', prop={'size':20})
    plt.xticks(fontsize=20, color='black')
    plt.yticks(fontsize=15, color='black')
    plt.ylabel('Contribution', fontsize=20, color='black')
    plt.tight_layout()

for data_source in ['source', 'target']:
    plot_contribution_prop(data_source)
    plt.savefig('%s/proportion_PVs_per_order_%s.png'%(figure_folder, data_source), dpi=300)
    plt.show()_____no_output_____

## Similarity visualisation_____no_output_____

n_source_PVs = source_PV_linear_features.shape[1]//2
n_target_PVs = target_PV_linear_features.shape[1]//2_____no_output_____def plot_feature_correlation_matrix(source_PV_feat, target_PV_feat, n_source_PVs, n_target_PVs):
    # Compute correlation
    feat_corr_matrix = pd.concat([
        source_PV_feat[['PV %s'%(e) for e in range(n_source_PVs)]],
        target_PV_feat[['PV %s'%(e) for e in range(n_target_PVs)]]
    ], axis=1).corr().values[n_source_PVs:,:n_source_PVs]

    # Plot the heatmap
    ax = sns.heatmap(feat_corr_matrix, cmap='seismic_r', center=0)

    # Visualisation routines
    cax = plt.gcf().axes[-1]
    cax.tick_params(labelsize=15)
    plt.xticks(
        np.arange(n_source_PVs)+.5, ['SPV %s'%(i+1) for i in range(n_source_PVs)],
        fontsize=15, color='black', rotation=90
    )
    plt.yticks(
        np.arange(n_target_PVs)+.5, ['SPV %s'%(i+1) for i in range(n_target_PVs)],
        fontsize=15, color='black', rotation=0
    )
    plt.xlabel('Source', fontsize=20, color='black')
    plt.ylabel('Target', fontsize=20, color='black')
    plt.tight_layout()

# Linear terms
plot_feature_correlation_matrix(
    source_PV_linear_features, target_PV_linear_features, n_source_PVs, n_target_PVs
)
plt.savefig('%s/cosine_sim_linear_terms.png'%(figure_folder), dpi=300)
plt.show()

# Interaction terms
plot_feature_correlation_matrix(
    source_PV_interaction_features, target_PV_interaction_features, n_source_PVs, n_target_PVs
)
plt.savefig('%s/cosine_sim_interaction_terms.png'%(figure_folder), dpi=300)_____no_output_____def plot_one_self_corr_matrix(PV_feat, n_PV, ax, label):
    self_corr_matrix = pd.concat([
        PV_feat[['PV %s'%(e) for e in range(n_PV)]],
        PV_feat[['PV %s'%(e) for e in range(n_PV)]]
    ], axis=1).corr().values[n_PV:,:n_PV]
    sns.heatmap(self_corr_matrix, cmap='seismic_r', center=0, vmin=-1, vmax=1, ax=ax)
    ax.set_xlabel(label, fontsize=20, color='black')
    ax.set_ylabel(label, fontsize=20, color='black')
    ax.set_xticks(np.arange(n_PV)+.5)
    ax.set_xticklabels(['SPV %s'%(i+1) for i in range(n_PV)], fontsize=15, color='black', rotation=90)
    ax.set_yticks(np.arange(n_PV)+.5)
    ax.set_yticklabels(['SPV %s'%(i+1) for i in range(n_PV)], fontsize=15, color='black', rotation=0)

# Linear to linear
fig, axes = plt.subplots(1,2, figsize=(10,4))
plot_one_self_corr_matrix(source_PV_linear_features, n_source_PVs, axes[0], 'Source')
plot_one_self_corr_matrix(target_PV_linear_features, n_target_PVs, axes[1], 'Target')
plt.tight_layout()
plt.savefig('%s/self_cosine_sim_linear_terms.png'%(figure_folder), dpi=300)
plt.show()

# Interactions to interactions
fig, axes = plt.subplots(1,2, figsize=(10,4))
plot_one_self_corr_matrix(source_PV_interaction_features, n_source_PVs, axes[0], 'Source')
plot_one_self_corr_matrix(target_PV_interaction_features, n_target_PVs, axes[1], 'Target')
plt.tight_layout()
plt.savefig('%s/self_cosine_sim_interaction_terms.png'%(figure_folder), dpi=300)
plt.show()_____no_output_____

## Gene classification
### Routine_____no_output_____

common_genes = ['A1', 'A2', 'A3', 'A4', 'Burn1', 'Burn2']
individual_genes = ['X1', 'X2', 'X3', 'X4', 'Y1', 'Y2', 'Y3', 'Y4', 'Burn3', 'Burn4', 'Burn5', 'Burn6']
feature_renaming = {'Burn': 'Ext'}
colors = {'common': 'tab:green', 'specific': 'tab:red', 'half': 'tab:grey'}

def compute_ordered_contributions(linear_df, interactions_df, PV_number, exclusion_pattern):
    """
    Takes as input interactions and linear features, stack them and order them
    exclusion_pattern: string to remove certain genes or interactions, e.g. Y for source and
    X for target.
    """
    # Format linear features
    combined_features_df = linear_df[['PV %s_squared'%(PV_number)]]
    combined_features_df['gene_A'] = combined_features_df.index
    combined_features_df['gene_B'] = 'NA'

    # Concatenate linear and interaction terms and format the names
    combined_features_df = pd.concat(
        [combined_features_df, interactions_df[['PV %s_squared'%(PV_number)]].reset_index()],
        axis=0
    )
    combined_features_df['gene_A'] = combined_features_df['gene_A'].str.extract(r'([A-Za-z0-9]*)')
    combined_features_df['gene_B'] = combined_features_df['gene_B'].str.extract(r'([A-Za-z0-9]*)')

    # Compute feature status
    combined_features_df['feature_status'] = combined_features_df['gene_A'].isin(common_genes).astype(int)
    combined_features_df['feature_status'] *= (1 + (combined_features_df['gene_B'] == 'NA')).astype(int) # For genes to be in common
    combined_features_df['feature_status'] += combined_features_df['gene_B'].isin(common_genes).astype(int)
    combined_features_df['feature_status'] -= 1

    # Remove target-specific genes for comparison
    combined_features_df = combined_features_df.loc[
        ~combined_features_df['gene_A'].str.contains(exclusion_pattern)
    ]
    combined_features_df = combined_features_df.loc[
        ~combined_features_df['gene_B'].str.contains(exclusion_pattern)
    ]

    feature_status_dict = {0: 'half', 1: 'common', -1: 'specific'}
    combined_features_df['feature_status'] = combined_features_df['feature_status'].apply(
        lambda x: feature_status_dict[x]
    )

    return combined_features_df

def barplot_top_contributors(df, PV_number, palette, file_save=None, top_genes=30, ax=None):
    plot_df = deepcopy(df)
    plot_df = plot_df.sort_values('PV %s_squared'%(PV_number), ascending=False).reset_index(drop=True).reset_index()
    plot_df['color'] = plot_df['feature_status'].apply(lambda x: palette[x])
    plot_df['feat_name'] = (plot_df['gene_A'] + '-' + plot_df['gene_B']).str.replace('-NA', '')
    for x in feature_renaming:
        plot_df['feat_name'] = plot_df['feat_name'].str.replace(x, feature_renaming[x])

    sns.barplot(
        data=plot_df.head(top_genes),
        x='feat_name', y='PV %s_squared'%(PV_number), palette=plot_df['color'], ax=ax
    )
    if ax is None:
        plt.xticks(fontsize=15, color='black', rotation=90)
        plt.yticks(fontsize=15, color='black', rotation=0)
        plt.ylabel('Loadings', fontsize=20, color='black')
        plt.xlabel('')
        plt.tight_layout()
    else:
        ax.tick_params(axis='x', labelsize=15, labelcolor='black', rotation=90)
        ax.tick_params(axis='y', labelsize=15, labelcolor='black', rotation=0)
        ax.set_xlabel('')
        ax.set_ylabel('Loadings', size=20, color='black')

    if file_save is not None:
        plt.savefig(file_save, dpi=300)
    if ax is None:
        plt.show()
    del plot_df_____no_output_____

### Source_____no_output_____

source_combined_features_df = []
for PV_number in range(source_PV_linear_features.shape[1] // 2):
    combined_features_df = compute_ordered_contributions(
        source_PV_linear_features, source_PV_interaction_features, PV_number, r'(Y|Burn5|Burn6)'
    )
    barplot_top_contributors(
        combined_features_df, PV_number, top_genes=20, palette=source_palette,
        file_save='%s/barplot_features_source_PV_%s.png'%(figure_folder, PV_number+1)
    )
    source_combined_features_df.append(combined_features_df.set_index(['gene_A', 'gene_B', 'feature_status']))_____no_output_____# Stacked plot of contributions
stacked_plot_df = pd.concat(source_combined_features_df, axis=1).groupby('feature_status').agg('sum').T
stacked_plot_df = stacked_plot_df.T / np.sum(stacked_plot_df, axis=1)
stacked_plot_df.T.plot.bar(stacked=True, color=source_palette, width=0.9, figsize=(8,4))

plt.xticks(np.arange(n_source_PVs), ['SPV %s'%(i+1) for i in np.arange(n_source_PVs)], fontsize=20, rotation=90)
plt.yticks(fontsize=15, rotation=0)
plt.ylabel('PV contribution', fontsize=20, color='black')
plt.legend(loc='center left', bbox_to_anchor=(1, 0.5), fontsize=20)
plt.tight_layout()
plt.savefig('%s/contributions_source.png'%(figure_folder), dpi=300)

del stacked_plot_df_____no_output_____if type(source_combined_features_df) != pd.DataFrame:
    source_combined_features_df = pd.concat(source_combined_features_df, axis=1)
source_combined_features_df['is_linear'] = source_combined_features_df.index.get_level_values('gene_B') == 'NA'

# Linear features
linear_proportion = source_combined_features_df.loc[source_combined_features_df['is_linear']]
linear_proportion = linear_proportion / np.sum(linear_proportion)
del linear_proportion['is_linear']
linear_proportion = linear_proportion.groupby('feature_status').agg('sum')
linear_proportion.T.plot.bar(stacked=True, width=0.9, figsize=(8,4), color=source_palette)

plt.xticks(np.arange(n_source_PVs), ['SPV %s'%(i+1) for i in np.arange(n_source_PVs)], fontsize=20, rotation=90)
plt.yticks(fontsize=15, rotation=0)
plt.ylabel('PV contribution', fontsize=20, color='black')
plt.legend(loc='center left', bbox_to_anchor=(1, 0.5), fontsize=20)
plt.tight_layout()
plt.savefig('%s/contributions_source_linear.png'%(figure_folder), dpi=300)
plt.show()

# Interaction features
interaction_proportion = source_combined_features_df.loc[~source_combined_features_df['is_linear']]
interaction_proportion = interaction_proportion / np.sum(interaction_proportion)
del interaction_proportion['is_linear']

interaction_proportion = interaction_proportion.groupby('feature_status').agg('sum')
interaction_proportion.T.plot.bar(stacked=True, width=0.9, figsize=(8,4), color=source_palette)

plt.xticks(np.arange(n_source_PVs), ['SPV %s'%(i+1) for i in np.arange(n_source_PVs)], fontsize=20, rotation=90)
plt.yticks(fontsize=15, rotation=0)
plt.ylabel('PV contribution', fontsize=20, color='black')
plt.legend(loc='center left', bbox_to_anchor=(1, 0.5), fontsize=20)
plt.tight_layout()
plt.savefig('%s/contributions_source_interactions.png'%(figure_folder), dpi=300)
plt.show()_____no_output_____

### Target_____no_output_____

target_combined_features_df = []
for PV_number in range(target_PV_interaction_features.shape[1] // 2):
    combined_features_df = compute_ordered_contributions(
        target_PV_linear_features, target_PV_interaction_features, PV_number, r'(X|Burn3|Burn4)'
    )
    barplot_top_contributors(
        combined_features_df, PV_number, top_genes=20, palette=target_palette,
        file_save='%s/barplot_features_target_PV_%s.png'%(figure_folder, PV_number+1)
    )
    target_combined_features_df.append(combined_features_df.set_index(['gene_A', 'gene_B', 'feature_status']))_____no_output_____# Stacked plot of contributions
stacked_plot_df = pd.concat(target_combined_features_df, axis=1).groupby('feature_status').agg('sum').T
stacked_plot_df = stacked_plot_df.T / np.sum(stacked_plot_df, axis=1)
stacked_plot_df.T.plot.bar(stacked=True, color=target_palette, width=0.9, figsize=(8,4))

plt.xticks(np.arange(n_target_PVs), ['SPV %s'%(i+1) for i in np.arange(n_target_PVs)], fontsize=20, rotation=90)
plt.yticks(fontsize=15, rotation=0)
plt.ylabel('PV contribution', fontsize=20, color='black')
plt.legend(loc='center left', bbox_to_anchor=(1, 0.5), fontsize=20)
plt.tight_layout()
plt.savefig('%s/contributions_target.png'%(figure_folder), dpi=300)

del stacked_plot_df_____no_output_____if type(target_combined_features_df) != pd.DataFrame:
    target_combined_features_df = pd.concat(target_combined_features_df, axis=1)
target_combined_features_df['is_linear'] = target_combined_features_df.index.get_level_values('gene_B') == 'NA'

# Linear features
linear_proportion = target_combined_features_df.loc[target_combined_features_df['is_linear']]
linear_proportion = linear_proportion / np.sum(linear_proportion)
del linear_proportion['is_linear']
linear_proportion = linear_proportion.groupby('feature_status').agg('sum')
linear_proportion.T.plot.bar(stacked=True, width=0.9, figsize=(8,4), color=target_palette)

plt.xticks(np.arange(n_target_PVs), ['SPV %s'%(i+1) for i in np.arange(n_target_PVs)], fontsize=20, rotation=90)
plt.yticks(fontsize=15, rotation=0)
plt.ylabel('PV contribution', fontsize=20, color='black')
plt.legend(loc='center left', bbox_to_anchor=(1, 0.5), fontsize=20)
plt.tight_layout()
plt.savefig('%s/contributions_target_linear.png'%(figure_folder), dpi=300)
plt.show()

# Interaction featurs
interaction_proportion = target_combined_features_df.loc[~target_combined_features_df['is_linear']]
interaction_proportion = interaction_proportion / np.sum(interaction_proportion)
del interaction_proportion['is_linear']

interaction_proportion = interaction_proportion.groupby('feature_status').agg('sum')
interaction_proportion.T.plot.bar(stacked=True, width=0.9, figsize=(8,4), color=target_palette)

plt.xticks(np.arange(n_target_PVs), ['SPV %s'%(i+1) for i in np.arange(n_target_PVs)], fontsize=20, rotation=90)
plt.yticks(fontsize=15, rotation=0)
plt.ylabel('PV contribution', fontsize=20, color='black')
plt.legend(loc='center left', bbox_to_anchor=(1, 0.5), fontsize=20)
plt.tight_layout()
plt.savefig('%s/contributions_target_interactions.png'%(figure_folder), dpi=300)
plt.show()_____no_output_____

## Common plot_____no_output_____

n_number_top_genes = 10
n_max_PV = max(source_PV_linear_features.shape[1] // 2, target_PV_linear_features.shape[1] // 2)
fig, axes = plt.subplots(n_max_PV, 2, figsize=(10,3*n_max_PV))

# Fill source barplots
for PV_number in range(n_source_PVs):
    combined_features_df = compute_ordered_contributions(
        source_PV_linear_features, source_PV_interaction_features, PV_number, r'(Y|Burn3|Burn4)'
    )
    barplot_top_contributors(
        combined_features_df, PV_number, top_genes=n_number_top_genes, palette=source_palette, ax=axes[PV_number, 0]
    )

# Fill target barplots
for PV_number in range(n_target_PVs):
    combined_features_df = compute_ordered_contributions(
        target_PV_linear_features, target_PV_interaction_features, PV_number, r'(X|Burn5|Burn6)'
    )
    barplot_top_contributors(
        combined_features_df, PV_number, top_genes=n_number_top_genes, palette=source_palette, ax=axes[PV_number, 1]
    )

# Remove empty ones
for PV_number in range(min(n_source_PVs, n_target_PVs), n_max_PV):
    empty_ax_idx = int(n_target_PVs < n_max_PV)
    axes[PV_number, empty_ax_idx].spines['top'].set_visible(False)
    axes[PV_number, empty_ax_idx].spines['right'].set_visible(False)
    axes[PV_number, empty_ax_idx].spines['bottom'].set_visible(False)
    axes[PV_number, empty_ax_idx].spines['left'].set_visible(False)
    axes[PV_number, empty_ax_idx].get_xaxis().set_ticks([])
    axes[PV_number, empty_ax_idx].get_yaxis().set_ticks([])

plt.tight_layout()
plt.savefig('%s/complete_feature_barplot.png'%(figure_folder), dpi=300)

del n_max_PV, n_number_top_genes, empty_ax_idx, PV_number_____no_output_____


# Notebook from nanotheorygroup/kaldo
Path: docs/docsource/introduction.ipynb

### Introduction

κALDo is a versatile and scalable open-source software to compute phonon transport in crystalline and amorphous solids. It features real space QHGK calculations and three different solvers of the linearized BTE: direct inversion, self-consistent cycle, and RTA.

The algorithms are implemented using linear algebra operations on tensors, to take advantage of multithreading on GPU and CPU using Numpy, Tensorflow and optimized tensor libraries.

Using the Atomic Simulation Environment, κALDo can calculate the IFCs using several ab initio and molecular dynamics codes, thus enabling the use of first-principles DFT, empirical forcefields and semi-empirical tight- binding. A native LAMMPS interface is also available in the USER-PHONON package. Finally, through seamless integration with the hiPhive package, the IFC calculation can take advantage of compressing-sensing machine learning algorithms

The code is released open-source for the community to use and contribute with edits and suggestions. It is designed on modern software best practices, and we hope to provide a development platform to implement new theory and methods.

### Quick Install

We recommend creating a new environment with Python 3.6, 3.7, or 3.8.
```bash
conda create -n kaldo python=3.7
```
and enable the environment
```bash
conda activate kaldo
conda install pip
```

kALDo installation can be done using `pip`
```bash
pip install git+https://github.com/nanotheorygroup/kaldo
```

#### Using `pip` and `virtualenv`

You can also install kALDO without using `conda`
```bash
pip3 install virtualenv
virtualenv --system-site-packages -p python3 ~/kaldo
source ~/kaldo/bin/activate
pip3 install git+https://github.com/nanotheorygroup/kaldo
```
#### Development mode

The best way to run examples, tests and to develop kaldo is to follow the quick install procedure, and add the following extra steps.
```bash
pip uninstall kaldo
make ~/develoment
cd ~/development
git clone git+https://github.com/nanotheorygroup/kaldo
export PYTHONPATH=~/development/kaldo:$PYTHONPATH
```
If you followed the steps in the quickstart and then uninstall kaldo, you will have all the dependencies correctly installed.
The next lines are pulling the repo from Github and adding it to the `PYTHONPATH`.

If you want to make the last change in the `PYTHONPATH` permanent, you can also run
```bash
echo "export PYTHONPATH=~/development/kaldo:$PYTHONPATH" >> ~/.bashrc
```

### Interfacing with Other Codes

#### LAMMPS library setup

In order to use LAMMPS with ASE, it needs to be compiled a lib
```bash
cd path/to/lammps/src
make yes-manybody
make yes-molecule
...
make mpi mode=shlib
```
Next, activate your environment
```
conda activate kaldo
```
or if you used `virtualenv`
```
source ~/kaldo/bin/activate
```
and finally install `lammpslib` using
```
make install-python
```
Update 07/2020: It you are having any issue with the July 2020 version of `lammpslib`, try using the October 2019 version.

#### LAMMPS executable setup

You can use LAMMPS executable directly, as illustrated in the example folder.
For that purpose, you will need the  [LAMMPS user-phonon package by Charles Sievers](https://lammps.sandia.gov/doc/Packages_details.html#pkg-user-phonon) to calculate the dynamical matrix and the third order interatomic force constants.

#### Quantum Espresso setup

In order to use QE with ASE, Set the environment variable:
```bash
export ASE_ESPRESSO_COMMAND="mpirun -np 4 /path/to/pw.x -in PREFIX.pwi > PREFIX.pwo"
```
Update 01/2021: It you are having any issue with ASE version 3.20+, try using ASE version 3.19.1.

See the [ASE documentation](https://wiki.fysik.dtu.dk/ase/ase/calculators/calculators.html) for more info.

### Output Storage

#### Default Storage

When using the storage `formatted`, kALDo stores the following dense tensor as formatted, human readable, files:

- `frequency` $(n_{kpoints}, n_{modes})$. mode changes first k changes after
- `velocity_alpha` $(n_{kpoints}, n_{modes})$
- `physical_mode_<min_freq>_<max_freq>_<is_nw>` $(n_{kpoints}, n_{modes})$

- `<temperature>/<statistics>/heat_capacity` $(n_{kpoints}, n_{modes})$
- `<temperature>/<statistics>/population` $(n_{kpoints}, n_{modes})$

- `<temperature>/<statistics>/<method>/<third_bandwidth>/<diffusivity_bandwidth>/conductivity_<alpha>_<beta>` $(n_{kpoints}, n_{modes})$ where the `<third_bandwidth>/<diffusivity_bandwidth>` folder is created only if those values are defined
- `<temperature>/<statistics>/<diffusivity_bandwidth>/diffusivity` $(n_{kpoints}, n_{modes})$
- `<temperature>/<statistics>/<third_bandwidth>/<method>/mean_free_path` $(n_{kpoints}, n_{modes})$
- `<temperature>/<statistics>/<third_bandwidth>/lifetime` $(n_{kpoints}, n_{modes})$
- `<temperature>/<statistics>/<third_bandwidth>/bandwidth` $(n_{kpoints}, n_{modes})$
- `<temperature>/<statistics>/<third_bandwidth>/phase_space` $(n_{kpoints}, n_{modes})$
- `<diffusivity_bandwidth>flux_dense` $(n_{kpoints}, n_{modes}, n_{kpoints}, n_{modes})$, when `diffusivity_threshold` is not specified.
- `<diffusivity_bandwidth>/<diffusivity_threshold>/flux_sparse` $(n_{kpoints}, n_{modes}, n_{kpoints}, n_{modes})$. Sparse only when  `diffusivity_threshold` is specified.

The folder structure depends on the input parameters to the Phonon Object
and in parenthesis is the shape of the tensor. All of the above observables are stored in a dense format,
except for `flux_alpha` which is stored as formatted file in a `index value` format.

The following tensors are stored in raw binary format and help saving time when performing different simulations on the same sample.

- `_eigensystem (eigenvalues and eigenvectors)`
- `_dynmat_derivatives`
- `<temperature>/<statistics>/<diffusivity_bandwidth>/_generalized_diffusivity`
- `<temperature>/<statistics>/<third_bandwidth>/_ps_and_gamma_tensor`
- `<temperature>/<statistics>/<third_bandwidth>/_ps_and_gamma`, when only RTA conductivity is required

#### Alternative Storage

Other storage options available are `numpy` and `hdf5` where all the files are saved as one of those formats.
Finally the `memory` option doesn't store any permanent files.

| Measurement             | Units                    |
|-------------------------|--------------------------|
| Distances               | $A$                      |
| Masses                  | $g/N_A$                  |
| Frequencies             | $THz$                    |
| Potential Derivatives   | $eV/(A^2)$ or $eV/(A^3)$ |
| Conductivity [$\kappa$]| $\frac{W}{m\ K}$       |

### Code Architecture

### Main Features

Below we illustrate the main features of the code

### Examples

Examples and the explanation on how to use them are located in the [examples folder of the repo](https://github.com/nanotheorygroup/kaldo/tree/master/examples).

### How to cite

If you have used kALDo, please cite the following article:

Barbalinardo, G.; Chen, Z.; Lundgren, N. W.; Donadio, D. Efficient Anharmonic Lattice Dynamics Calculations of Thermal Transport in Crystalline and Disordered Solids. J Appl Phys 2020, 128 (13), 135104–135112. https://doi.org/10.1063/5.0020443
also available open access on ArXiv: https://arxiv.org/abs/2009.01967

```
@article{kaldo,
author = {Barbalinardo, Giuseppe and Chen, Zekun and Lundgren, Nicholas W and Donadio, Davide},
title = {{Efficient anharmonic lattice dynamics calculations of thermal transport in crystalline and disordered solids}},
journal = {Journal of Applied Physics},
year = {2020},
volume = {128},
number = {13},
pages = {135104--12},
month = oct
}
```

### Copyright

Copyright (c) 2020, Giuseppe Barbalinardo, Zekun Chen, Nicholas W. Lundgren, Davide Donadio

### Acknowledgements

We gratefully acknowledge support by the Investment Software Fellowships (grant No. ACI-1547580-479590) of the NSF Molecular Sciences Software Institute (grant No. ACI-1547580) at Virginia Tech.

MolSSI builds open source software and data which serves the computational molecular science community. [Explore MolSSI’s software infrastructure projects.](https://molssi.org/software-projects/)

### Other codes

We are thankful to the whole open-source community, and in particular we want to acknowledge some other great anharmonic lattice dynamics related projects. If using kALDo example, you
If, while you are running kALDo examples, you use any of these codes, please don't forget to cite them.

- ASE: A. H. Larsen, J. J. Mortensen, J. Blomqvist, I. E. Castelli, R. Christensen, M. Dułak, J. Friis, M. N. Groves, B. Hammer, C. Hargus, E. D. Hermes, P. C. Jennings, P. B. Jensen, J. Kermode, J. R. Kitchin, E. L. Kolsbjerg, J. Kubal, K. Kaasbjerg, S. Lysgaard, J. B. Maronsson, T. Maxson, T. Olsen, L. Pastewka, A. Peterson, C. Rostgaard, J. Schiøtz, O. Schütt, M. Strange, K. S. Thygesen, T. Vegge, L. Vilhelmsen, M. Walter, Z. Zeng, and K. W. Jacobsen, “The atomic simulation environment—a python library for work- ing with atoms,” Journal of Physics: Condensed Matter 29, 273002 (2017).
- LAMMPS: S. Plimpton, Fast Parallel Algorithms for Short-Range Molecular Dynamics, J Comp Phys, 117, 1-19 (1995).
- Quantum Espresso: P Giannozzi, O Andreussi, T Brumme, O Bunau, M Buongiorno Nardelli, M Calandra, R Car, C Cavazzoni, D Ceresoli, M Cococcioni, N Colonna, I Carnimeo, A Dal Corso, S de Gironcoli, P Delugas, R A DiStasio Jr, A Ferretti, A Floris, G Fratesi, G Fugallo, R Gebauer, U Gerstmann, F Giustino, T Gorni, J Jia, M Kawamura, H-Y Ko, A Kokalj, E Küçükbenli, M Lazzeri, M Marsili, N Marzari, F Mauri, N L Nguyen, H-V Nguyen, A Otero-de-la-Roza, L Paulatto, S Poncé, D Rocca, R Sabatini, B Santra, M Schlipf, A P Seitsonen, A Smogunov, I Timrov, T Thonhauser, P Umari, N Vast, X Wu and S Baroni, J.Phys.:Condens.Matter 29, 465901 (2017)
- HiPhive: The Hiphive Package for the Extraction of High‐Order Force Constants by Machine Learning, Fredrik Eriksson, Erik Fransson, and Paul Erhart, Advanced Theory and Simulations,  (2019)

### Project template

Project template from the [Computational Molecular Science Python Cookiecutter](https://github.com/molssi/cookiecutter-cms).

### How to contribute changes
- Clone the repository if you have write access to the main repo, fork the repository if you are a collaborator.
- Make a new branch with `git checkout -b {your branch name}`
- Make changes and test your code
- Ensure that the test environment dependencies (`conda-envs`) line up with the build and deploy dependencies (`conda-recipe/meta.yaml`)
- Push the branch to the repo (either the main or your fork) with `git push -u origin {your branch name}`
  * Note that `origin` is the default name assigned to the remote, yours may be different
- Make a PR on GitHub with your changes
- We'll review the changes and get your code into the repo after lively discussion!

#### Checklist for updates
- [ ] Make sure there is an/are issue(s) opened for your specific update
- [ ] Create the PR, referencing the issue
- [ ] Debug the PR as needed until tests pass
- [ ] Tag the final, debugged version
   *  `git tag -a X.Y.Z [latest pushed commit] && git push --follow-tags`
- [ ] Get the PR merged in

#### Versioneer Auto-version
[Versioneer](https://github.com/warner/python-versioneer) will automatically infer what version
is installed by looking at the `git` tags and how many commits ahead this version is. The format follows
[PEP 440](https://www.python.org/dev/peps/pep-0440/) and has the regular expression of:
```regexp
\d+.\d+.\d+(?\+\d+-[a-z0-9]+)
```
If the version of this commit is the same as a `git` tag, the installed version is the same as the tag,
e.g. `kaldo-0.1.2`, otherwise it will be appended with `+X` where `X` is the number of commits
ahead from the last tag, and then `-YYYYYY` where the `Y`'s are replaced with the `git` commit hash._____no_output_____


# Notebook from hms-dbmi/Access-to-Data-using-PIC-SURE-API
Path: NHLBI_BioData_Catalyst/python/3_PheWAS.ipynb

# PIC-SURE python API use-case: Phenome-Wide analysis on BioData Catalyst studies_____no_output_____This notebook is an illustration example about how to query data using the python **PIC-SURE API**. It takes as use-case a simple PheWAS analysis. This notebook is intentionally straightforward, and explanation provided are only aimed at guiding through the PheWAS analysis processus. For a more step-by-step introduction to the python PIC-SURE API, see the `PICSURE-API_101.ipynb` notebook._____no_output_____**Before running this notebook, please be sure to get a user-specific security token. For more information on how to proceed, see the `get_your_token.ipynb` notebook**_____no_output_____# Environment set-up_____no_output_____### System requirements
- Python 3.6 or later
- pip package manager
- bash interpreter_____no_output_____### Installation of external dependencies_____no_output_____

import sys
!{sys.executable} -m pip install -r requirements.txt_____no_output_____

#### Installing latest python PIC-SURE API libraries from github_____no_output_____

!{sys.executable} -m pip install --upgrade --force-reinstall git+https://github.com/hms-dbmi/pic-sure-python-adapter-hpds.git
!{sys.executable} -m pip install --upgrade --force-reinstall git+https://github.com/hms-dbmi/pic-sure-python-client.git
!{sys.executable} -m pip install --upgrade --force-reinstall git+https://github.com/hms-dbmi/pic-sure-biodatacatalyst-python-adapter-hpds.git_____no_output_____import json
from pprint import pprint

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats

import PicSureClient
import PicSureBdcAdapter

from python_lib.utils import get_multiIndex_variablesDict, joining_variablesDict_onCol_____no_output_____print("NB: This Jupyter Notebook has been written using PIC-SURE API following versions:\n- PicSureBdcAdapter: 1.0.0\n- PicSureClient: 1.1.0")
print("The installed PIC-SURE API libraries versions:\n- PicSureBdcAdapter: {0}\n- PicSureClient: {1}".format(PicSureBdcAdapter.__version__, PicSureClient.__version__))_____no_output_____# Pandas DataFrame display options
pd.set_option("max.rows", 100)

# Matplotlib display parameters
plt.rcParams["figure.figsize"] = (14,8)
font = {'weight' : 'bold',
        'size'   : 12}
plt.rc('font', **font)_____no_output_____

## Connecting to a PIC-SURE network_____no_output_____

PICSURE_network_URL = "https://picsure.biodatacatalyst.nhlbi.nih.gov/picsure"
resource_id = "02e23f52-f354-4e8b-992c-d37c8b9ba140"
token_file = "token.txt"_____no_output_____with open(token_file, "r") as f:
    my_token = f.read()_____no_output_____client = PicSureClient.Client()
connection = client.connect(PICSURE_network_URL, my_token)
adapter = PicSureBdcAdapter.Adapter(connection)
resource = adapter.useResource(resource_id)_____no_output_____

## PheWAS analysis_____no_output_____In a nutshell, this PheWAS analysis follows the subsequent steps:
- Retrieving the variables dictionary, using the PIC-SURE API dedicated methods
- From the info provided by the dictionary, retrieving the data in an exploitable format through PIC-SURE API calls
- Data management
- Running univariate tests against every phenotype variables
- Accounting for multiple hypotheses testing issue
- Plotting results

This analysis is conducted using individuals enrolled in the COPDGene Study. Overall goal of this cohort is to detect underlying genetic factors to develop Chronic Obstructive Pulmonary Disease (COPD), and currently includes more than 10,000 individuals ([more information on COPDGene Study](http://www.copdgene.org))._____no_output_____### 1. Retrieving variables dictionary from the Database_____no_output_____Retrieving variables dictionary for COPDGene related variables._____no_output_____

copdgene_dic = resource.dictionary().find("Genetic Epidemiology of COPD (COPDGene)").DataFrame()
consent_dic = resource.list_consents()['consent']
# line needed bc dictionaries doesn't return the same column type for categorical and numerical variables
plain_variablesDict = copdgene_dic.transpose().join(consent_dic.transpose(), how="outer").transpose()_____no_output_____

Here we retrieved information about all the available variables of the COPDGene study, as well as information about the individual consents. The Consent variable will be eventually used to filter the patients pertaining to the COPDGene study. We are then combining both dictionaries into a single one. _____no_output_____

plain_variablesDict.head()_____no_output_____resource.dictionary().help()_____no_output_____# Display the variables tree hierarchy from the variables name
variablesDict = get_multiIndex_variablesDict(plain_variablesDict)
variablesDict.iloc[10:20,:]_____no_output_____dic = resource.dictionary().find().DataFrame()_____no_output_____

### 2. Selecting variables and retrieving data from the database_____no_output_____Subseting to keep only the phenotype variables + the variable "affection status" that will be used as the dependent variable for this illustration use-case._____no_output_____

mask_pheno = variablesDict.index.get_level_values(1) == 'Subject Phenotype'
mask_status = variablesDict.index.get_level_values(2) == 'Affection status'
mask_drop = variablesDict["simplified_name"].isin(["Dbgap_id", "De-identified site code", "A1AD: phenotype/genotype"])
mask_vars = mask_pheno | mask_status
variablesDict = variablesDict.loc[mask_vars & ~ mask_drop,:]_____no_output_____selected_vars = variablesDict.loc[:, "name"].tolist()_____no_output_____pprint(selected_vars[0:5])_____no_output_____

### Subsetting only COPDGene records_____no_output_____To subset only the subjects from the COPDGene study, we are using the different COPDGene study accession codes, which all begins with 'phs000179...'._____no_output_____

phs = pd.Series(consent_dic)
mask_phs_copdgene = phs.str.startswith("phs000179").tolist()
phs_copdgene = phs[mask_phs_copdgene]_____no_output_____

Retrieving the data:_____no_output_____

%%capture
query = resource.query()
query.filter().add(consent_dic.index[0], phs_copdgene)
query.select().add(selected_vars)
facts = query.getResultsDataFrame(low_memory=False)_____no_output_____facts.head()_____no_output_____status_var = variablesDict.loc[variablesDict.index.get_level_values(2) == 'Affection status', "name"]
facts = facts.dropna(subset=status_var)\
.set_index("Patient ID")
mask_to_drop = variablesDict["simplified_name"]\
.isin(["Dbgap_id", "De-identified site code", "A1AD: phenotype/genotype"])
variablesDict = variablesDict.loc[~mask_to_drop, :]
var_to_keep = variablesDict.loc[:, "name"]
facts = facts.loc[:, var_to_keep]_____no_output_____print("{0} rows, {1} columns".format(*facts.shape))_____no_output_____

Here is a sample of our dataset, one row per patient and one column par variable:_____no_output_____

facts.tail(5)_____no_output_____

### 3. Data-management_____no_output_____#### Selecting variables regarding their types_____no_output_____One important step in a PheWAS is to get the distinction between categorical and numerical variables. This distinction is straightforward using the variable dictionary._____no_output_____

mask_categories = variablesDict.loc[:, "categorical"] == True
categorical_names = variablesDict.loc[mask_categories, "name"].tolist()
continuous_names = variablesDict.loc[~mask_categories, "name"].tolist()_____no_output_____

### Selecting the dependent variable to study
Most of PheWAS studies use a genetic variant as the dependent variable to separate the population between cases and controls. However the population doesn't have to be dichotomized using a genetic variant, and any phenotypic variable could be used to run a PheWAS analysis (see for example [*Neuraz et al.*, 2013](https://journals.plos.org/ploscompbiol/article?id=10.1371/journal.pcbi.1003405)).

Here we will use the **COPD status** as the case-control variable to dichotomize the population in our analysis, and keep only the population subset containing relevant values for the COPD status (i.e. keeping "Case" and "Control" individuals, thus discarding "Other", "Control, Exclusionary Disease", and null values)._____no_output_____

dependent_var_name = variablesDict.loc[variablesDict["simplified_name"] == "Affection status", "name"].values[0]
categorical_names.remove(dependent_var_name)_____no_output_____mask_dependent_var_name = facts[dependent_var_name].isin(["Case", "Control"])
facts = facts.loc[mask_dependent_var_name,:]\
             .astype({dependent_var_name: "category"})
print("Control: {0} individuals\nCase: {1} individuals".format(*facts[dependent_var_name].value_counts().tolist()))_____no_output_____

### 4. Univariate statistical tests_____no_output_____From this point, each variable present in the `facts_dummies` dataset will be tested again the selected dependent variable, (ie presence or absence of COPD).

Two different association tests will be carried out according to variables data types:
- Mann-Whitney U test for continuous ones
- Fisher exact test for categorical ones_____no_output_____### LLR result_____no_output_____

from statsmodels.discrete.discrete_model import Logit_____no_output_____independent_names = variablesDict["name"].tolist()
independent_names.remove(dependent_var_name)
dependent_var = facts[dependent_var_name].astype("category").cat.codes
dic_pvalues = {}
simple_index_variablesDict = variablesDict.set_index("name", drop=True)_____no_output_____from scipy.linalg import LinAlgError
from statsmodels.tools.sm_exceptions import PerfectSeparationError
from tqdm import tqdm_____no_output_____for independent_name in tqdm(independent_names, position=0, leave=True):
    matrix = facts.loc[:, [dependent_var_name, independent_name]]\
                  .dropna(how="any")
    if matrix.shape[0] == 0:
        dic_pvalues[independent_name] = np.NaN
        continue
    if simple_index_variablesDict.loc[independent_name, "categorical"]:
        matrix = pd.get_dummies(matrix,
                                columns=[independent_name],
                                drop_first=False)\
                    .iloc[:, 0:-1]
    dependent_var = matrix[dependent_var_name].cat.codes
    independent_var = matrix.drop(dependent_var_name, axis=1)\
                            .assign(intercept = 1)
    model = Logit(dependent_var, independent_var)
    try:
        results = model.fit(disp=0)
        dic_pvalues[independent_name] = results.llr_pvalue
    except (LinAlgError, PerfectSeparationError) as e:
        dic_pvalues[independent_name] = np.NaN_____no_output_____

#### p-values distribution (univariate tests)_____no_output_____

pd.Series([v for v in dic_pvalues.values()]).plot.hist(bins=30)
plt.suptitle("Distribution of individual p-values",
             weight="bold",
            fontsize=15)_____no_output_____

### 5. Multiple hypotheses testing correction: Bonferroni Method_____no_output_____In order to handle the multiple testing problem (increase in the probability of getting statistically significant associations), we will use the Bonferroni correction method. Although many other multiple-comparison corrections exist, Bonferroni is the most straightforward to use, because it doesn't require assumptions about variables correlation. Other PheWAS analysis also use False Discovery Rate controlling procedures ([see](https://en.wikipedia.org/wiki/False_discovery_rate))._____no_output_____In a nutshell, Bonferonni allows to calculate a corrected "statistical significant threshold" according to the number of test performed. Every p-value below this threshold will be deemed statistically significant._____no_output_____

%%capture
# Merging pvalues from different tests
df_pvalues = pd.DataFrame.from_dict(dic_pvalues, orient="index", columns=["pvalues"])\
.rename_axis("name")\
.reset_index(drop=False)

# Adding pvalues results as a new column to variablesDict
variablesDict = joining_variablesDict_onCol(variablesDict,
                                              df_pvalues,
                                              left_col="name",
                                              right_col="name")

adjusted_alpha = 0.05/len(variablesDict["pvalues"])
variablesDict["p_adj"] = variablesDict["pvalues"] / len(variablesDict["pvalues"])
variablesDict['log_p'] = -np.log10(variablesDict['pvalues'])
variablesDict = variablesDict.sort_index()
variablesDict["group"] = variablesDict.reset_index(level=2)["level_2"].values_____no_output_____print("Bonferonni adjusted significance threshold: {0:.2E}".format(adjusted_alpha))_____no_output_____

## 6. Result visualisations: Manhattan plot_____no_output_____Manhattan plot is the classical way to plot the results of a PheWAS analysis. It plots every tested phenotypical variables on the X-axis, against their *-log(pvalue)* on the Y-axis. The horizontal line represents the adjusted significance level threshold._____no_output_____

mask = variablesDict["pvalues"].isna()
df_results = variablesDict.loc[~mask,:].copy().replace([np.inf, -np.inf], np.nan)
df_results = df_results.loc[~df_results["log_p"].isna().values,:]

#### Specific adjustment to make this specific plot looks nicer
####### to adapt when changing data or dependent variable
df_results = df_results.replace({"TLC": "Spirometry",
                                 "New Gold Classification": "Quantitative Analysis",
                  "Other": "Demographics",
                                "Eligibility Form": "Sociodemography and Administration"})
group_order={'6MinWalk': 0,
 'CT Acquisition Parameters': 1,
 'CT Assessment Scoresheet': 2,
 'Demographics and Physical Characteristics': 3,
 'Longitudinal Analysis': 5,
 'Medical History': 4,
 'Medication History': 13,
 'Quantitative Analysis': 9,
 'Respiratory Disease': 6,
 'SF-36 Health Survey': 11,
 'Sociodemography and Administration': 12,
 'Spirometry': 7,
 'VIDA': 15}
df_results["group_order"] = df_results["group"].replace(group_order)
df_results = df_results.sort_values("group_order", ascending=True)
df_results["simplified_name"] = df_results["simplified_name"].str.replace("[0-9]+[A-z]*", "").to_frame()
###

fig = plt.figure()
ax = fig.add_subplot(111)
colors = plt.get_cmap('Set1')
x_labels = []
x_labels_pos = []

y_lims = (0, df_results["log_p"].max(skipna=True) + 50)
threshold_top_values = df_results["log_p"].sort_values(ascending=False)[0:6][-1]

df_results["ind"] = np.arange(1, len(df_results)+1)
df_grouped = df_results.groupby(('group'))
for num, (name, group) in enumerate(df_grouped):
    group.plot(kind='scatter', x='ind', y='log_p',color=colors.colors[num % len(colors.colors)], ax=ax, s=20)
    x_labels.append(name)
    x_labels_pos.append((group['ind'].iloc[-1] - (group['ind'].iloc[-1] - group['ind'].iloc[0])/2)) # Set label in the middle
    for n, row in group.iterrows():
        if row["log_p"] > threshold_top_values:
            ax.text(row['ind'] + 3, row["log_p"] + 0.05, row["simplified_name"], rotation=0, alpha=1, size=8, color="black")

ax.set_xticks(x_labels_pos)
ax.set_xticklabels(x_labels)
ax.set_xlim([0, len(df_results) +1])
ax.set_ylim(y_lims)
ax.set_ylabel('-log(p-values)', style="italic")
ax.set_xlabel('Phenotypes', fontsize=15)
ax.axhline(y=-np.log10(adjusted_alpha), linestyle=":", color="black", label="Adjusted Threshold")
plt.xticks(fontsize = 9,rotation=90)
plt.yticks(fontsize = 8)
plt.title("Statistical Association Between COPD Status and Phenotypes",
          loc="center",
          style="oblique",
          fontsize = 20,
         y=1)
xticks = ax.xaxis.get_major_ticks()
xticks[0].set_visible(False)
handles, labels = ax.get_legend_handles_labels()
plt.legend(handles = handles, labels = labels, loc = "upper left")
plt.show()_____no_output_____

Overall, it appears that most of the tested phenotypes covariates are above the adjusted threshold of significant association. However, it is not that surprising given the nature of our dependent variable: a lot of the collected phenotypic variables are correlated to the COPD status._____no_output_____This code can be used directly with any other variable present in the variable Dictionary. Only the `dependent_var_name` variable need to be changed._____no_output_____


# Notebook from mlovci/tmpnb_PAG2014
Path: examples/illumina_bodymap.ipynb

# Create a `flotilla` study from the Illumina Bodymap 2.0 data

By: Olga Botvinnik_____no_output_____In this example, we will create a [`flotilla`](https://github.com/YeoLab/flotilla) study from the [Illumina](http://www.illumina.com) Bodymap 2.0 data. This is a nice dataset because it is simple yet complex. It has several nice features:

* Already processed to publically available gene expression values
* 16 human tissue types, so its relatable to people across biological disciplines, and to non-scientists (everyone knows what a brain is)
* Can group the tissue types as meta-types

These data are available from the European Bioinformatics Institute (EBI) website [here](http://www.ebi.ac.uk/gxa/experiments/E-MTAB-513?ref=aebrowse) (you can browse their other datasets on their [Data library](http://science.illumina.com/science/data_library.html) website). There's a link on the "[Expression Atlas](http://www.ebi.ac.uk/gxa/experiments/E-MTAB-513?ref=aebrowse)" view of the data to download the processed data, which is the link I use below. So let's get this data!_____no_output_____## Download the data and supplement_____no_output_____

! curl http://www.ebi.ac.uk/gxa/experiments/E-MTAB-513.tsv > E-MTAB-513.tsv
! curl http://www.ebi.ac.uk/arrayexpress/files/E-MTAB-513/E-MTAB-513.sdrf.txt>  E-MTAB-513.sdrf.txt  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 39860  100 39860    0     0  32219      0  0:00:01  0:00:01 --:--:-- 32249

What does this look like? Let's look at the top of the file with `head`._____no_output_____

! head E-MTAB-513.tsv# Expression Atlas version: 0.1.4-SNAPSHOT
# Query: Genes matching: 'protein_coding' exactly, specifically expressed in any Organism part above the expression level cutoff: 0.5 in experiment E-MTAB-513
# Timestamp: Sun, 11-Jan-2015 23:58:59
Gene ID	Gene Name	adipose tissue	adrenal gland	animal ovary	brain	breast	colon	heart	kidney	leukocyte	liver	lung	lymph node	prostate	skeletal muscle	testis	thyroid
ENSG00000000003	TSPAN6	21	5	21	5	16	12	2	13		31	11	5	13		18	15
ENSG00000000005	TNMD	16	5			44	1									0.6
ENSG00000000419	DPM1	20	31	33	25	26	25	23	35	29	17	25	27	32	18	42	44
ENSG00000000457	SCYL3	1	3	4	2	3	1	1	3	4	2	1	3	3	0.9	3	3
ENSG00000000460	C1orf112	0.7	0.8	0.8		0.6			0.6	0.6	0.7		0.9	0.9		5	0.7
ENSG00000000938	FGR	9	7	1	1	2	1	2	3	147	2	26	11	2	0.7	0.8	2
! head E-MTAB-513.sdrf.txtSource Name	Material Type	Description	Characteristics[organism]	Characteristics[age]	Unit[TimeUnit]	Characteristics[organism part]	Characteristics[sex]	Characteristics[ethnic group]	Comment[biosource provider]	Protocol REF	Extract Name	Material Type	Comment[LIBRARY_LAYOUT]	Comment[ORIENTATION]	Comment[NOMINAL_LENGTH]	Comment[NOMINAL_SDEV]	Comment[LIBRARY_SOURCE]	Comment[LIBRARY_STRATEGY]	Comment[LIBRARY_SELECTION]	Comment[spiked_in]	Comment[insertSize]	Comment[LIBRARYPREP]	Protocol REF	Performer	Assay Name	Technology Type	Comment[ENA_EXPERIMENT]	Comment[CYCLE_COUNT]	Comment[SPOT_LENGTH]	Comment[SEQUENCE_LENGTH]	Comment[READ_INDEX_0_READ_TYPE]	Comment[READ_INDEX_0_READ_CLASS]	Comment[READ_INDEX_0_BASE_COORD]	Comment[READ_INDEX_1_READ_TYPE]	Comment[READ_INDEX_1_READ_CLASS]	Comment[READ_INDEX_1_BASE_COORD]	Protocol REF	Scan Name	Comment[FASTQ_URI]	Comment[ENA_RUN]	Comment[SUBMITTED_FILE_NAME]	Comment[quality_scoring_system]	Comment[quality_encoding]	Comment[ascii_offset]	Factor Value[organism part]
HCT20142	organism part	1x75 single mRNA-Seq	Homo sapiens	60	year	kidney	female	Caucasian	"Human kidney total RNA, lot 0908002"	P-MTAB-19502	HCT20142_SINGLE	total_RNA	SINGLE	  	  	  	TRANSCRIPTOMIC	RNA-Seq	cDNA	~ 0.5% phiX DNA	~210 bps	mRNA-Seq	P-MTAB-19506	ILLUMINA-CA	A20G14AAX1_s6	sequencing assay	ERX011219	75	75	75	  	  	  	  	  	  	P-MTAB-19507	75bp_mRNA_Seq_FCA_s_6_sequence.txt.gz	ftp://ftp.sra.ebi.ac.uk/vol1/fastq/ERR030/ERR030893/ERR030893.fastq.gz	ERR030893	75bp_mRNA_Seq_FCA_s_6_sequence.txt.gz	phred	ascii	@	kidney
HCT20142	organism part	2x50 PE mRNA-seq READ1	Homo sapiens	60	year	kidney	female	Caucasian	"Human kidney total RNA, lot 0908002"	P-MTAB-19502	HCT20142_PAIRED	total_RNA	PAIRED	5'-3'-3'-5'	184	0	TRANSCRIPTOMIC	RNA-Seq	cDNA	~ 0.5% phiX DNA	~210 bps	mRNA-Seq	P-MTAB-19506	ILLUMINA-CA	B20G06AAX1_s6	sequencing assay	ERX011182	50	100	100	Forward	Application	1	Reverse	Application Run	51	P-MTAB-19507	50bp_PE_mRNA_Seq_FCB_s_6_1_sequence.txt.gz	ftp://ftp.sra.ebi.ac.uk/vol1/fastq/ERR030/ERR030885/ERR030885_1.fastq.gz	ERR030885	50bp_PE_mRNA_Seq_FCB_s_6_1_sequence.txt.gz	phred	ascii	@	kidney
HCT20142	organism part	2x50 PE mRNA-seq READ2	Homo sapiens	60	year	kidney	female	Caucasian	"Human kidney total RNA, lot 0908002"	P-MTAB-19502	HCT20142_PAIRED	total_RNA	PAIRED	5'-3'-3'-5'	184	0	TRANSCRIPTOMIC	RNA-Seq	cDNA	~ 0.5% phiX DNA	~210 bps	mRNA-Seq	P-MTAB-19506	ILLUMINA-CA	B20G06AAX1_s6	sequencing assay	ERX011182	50	100	100	Forward	Application	1	Reverse	Application Run	51	P-MTAB-19507	50bp_PE_mRNA_Seq_FCB_s_6_2_sequence.txt.gz	ftp://ftp.sra.ebi.ac.uk/vol1/fastq/ERR030/ERR030885/ERR030885_2.fastq.gz	ERR030885	50bp_PE_mRNA_Seq_FCB_s_6_2_sequence.txt.gz	phred	ascii	@	kidney
HCT20143	organism part	1x75 single mRNA-Seq	Homo sapiens	77	year	heart	male	Caucasian	"Human heart total RNA, lot 07040023"	P-MTAB-19502	HCT20143_SINGLE	total_RNA	SINGLE	  	  	  	TRANSCRIPTOMIC	RNA-Seq	cDNA	~ 0.5% phiX DNA	~210 bps	mRNA-Seq	P-MTAB-19506	ILLUMINA-CA	A20G14AAX1_s7	sequencing assay	ERX011183	75	75	75	  	  	  	  	  	  	P-MTAB-19507	75bp_mRNA_Seq_FCA_s_7_sequence.txt.gz	ftp://ftp.sra.ebi.ac.uk/vol1/fastq/ERR030/ERR030894/ERR030894.fastq.gz	ERR030894	75bp_mRNA_Seq_FCA_s_7_sequence.txt.gz	phred	ascii	@	heart
HCT20143	organism part	2x50 PE mRNA-seq READ1	Homo sapiens	77	year	heart	male	Caucasian	"Human heart total RNA, lot 07040023"	P-MTAB-19502	HCT20143_PAIRED	total_RNA	PAIRED	5'-3'-3'-5'	188	0	TRANSCRIPTOMIC	RNA-Seq	cDNA	~ 0.5% phiX DNA	~210 bps	mRNA-Seq	P-MTAB-19506	ILLUMINA-CA	B20G06AAX1_s7	sequencing assay	ERX011197	50	100	100	Forward	Application	1	Reverse	Application Run	51	P-MTAB-19507	50bp_PE_mRNA_Seq_FCB_s_7_1_sequence.txt.gz	ftp://ftp.sra.ebi.ac.uk/vol1/fastq/ERR030/ERR030886/ERR030886_1.fastq.gz	ERR030886	50bp_PE_mRNA_Seq_FCB_s_7_1_sequence.txt.gz	phred	ascii	@	heart
HCT20143	organism part	2x50 PE mRNA-seq READ2	Homo sapiens	77	year	heart	male	Caucasian	"Human heart total RNA, lot 07040023"	P-MTAB-19502	HCT20143_PAIRED	total_RNA	PAIRED	5'-3'-3'-5'	188	0	TRANSCRIPTOMIC	RNA-Seq	cDNA	~ 0.5% phiX DNA	~210 bps	mRNA-Seq	P-MTAB-19506	ILLUMINA-CA	B20G06AAX1_s7	sequencing assay	ERX011197	50	100	100	Forward	Application	1	Reverse	Application Run	51	P-MTAB-19507	50bp_PE_mRNA_Seq_FCB_s_7_2_sequence.txt.gz	ftp://ftp.sra.ebi.ac.uk/vol1/fastq/ERR030/ERR030886/ERR030886_2.fastq.gz	ERR030886	50bp_PE_mRNA_Seq_FCB_s_7_2_sequence.txt.gz	phred	ascii	@	heart
HCT20144	organism part	1x75 single mRNA-Seq	Homo sapiens	37	year	liver	male	Caucasian	"Human liver total RNA, lot 040000124"	P-MTAB-19502	HCT20144_SINGLE	total_RNA	SINGLE	  	  	  	TRANSCRIPTOMIC	RNA-Seq	cDNA	~ 0.5% phiX DNA	~210 bps	mRNA-Seq	P-MTAB-19506	ILLUMINA-CA	A20G14AAX1_s8	sequencing assay	ERX011211	75	75	75	  	  	  	  	  	  	P-MTAB-19507	75bp_mRNA_Seq_FCA_s_8_sequence.txt.gz	ftp://ftp.sra.ebi.ac.uk/vol1/fastq/ERR030/ERR030895/ERR030895.fastq.gz	ERR030895	75bp_mRNA_Seq_FCA_s_8_sequence.txt.gz	phred	ascii	@	liver
HCT20144	organism part	2x50 PE mRNA-seq READ1	Homo sapiens	37	year	liver	male	Caucasian	"Human liver total RNA, lot 040000124"	P-MTAB-19502	HCT20144_PAIRED	total_RNA	PAIRED	5'-3'-3'-5'	174	0	TRANSCRIPTOMIC	RNA-Seq	cDNA	~ 0.5% phiX DNA	~210 bps	mRNA-Seq	P-MTAB-19506	ILLUMINA-CA	B20G06AAX1_s8	sequencing assay	ERX011229	50	100	100	Forward	Application	1	Reverse	Application Run	51	P-MTAB-19507	50bp_PE_mRNA_Seq_FCB_s_8_1_sequence.txt.gz	ftp://ftp.sra.ebi.ac.uk/vol1/fastq/ERR030/ERR030887/ERR030887_1.fastq.gz	ERR030887	50bp_PE_mRNA_Seq_FCB_s_8_1_sequence.txt.gz	phred	ascii	@	liver
HCT20144	organism part	2x50 PE mRNA-seq READ2	Homo sapiens	37	year	liver	male	Caucasian	"Human liver total RNA, lot 040000124"	P-MTAB-19502	HCT20144_PAIRED	total_RNA	PAIRED	5'-3'-3'-5'	174	0	TRANSCRIPTOMIC	RNA-Seq	cDNA	~ 0.5% phiX DNA	~210 bps	mRNA-Seq	P-MTAB-19506	ILLUMINA-CA	B20G06AAX1_s8	sequencing assay	ERX011229	50	100	100	Forward	Application	1	Reverse	Application Run	51	P-MTAB-19507	50bp_PE_mRNA_Seq_FCB_s_8_2_sequence.txt.gz	ftp://ftp.sra.ebi.ac.uk/vol1/fastq/ERR030/ERR030887/ERR030887_2.fastq.gz	ERR030887	50bp_PE_mRNA_Seq_FCB_s_8_2_sequence.txt.gz	phred	ascii	@	liver

We'll use the [`pandas`](http://pandas.pydata.org) data analysis library to read the data. But we'll need a few caveats.

1. The first three lines of the data don't match the tabular format, so we'll need to ignore them with `skiprows=3`.
2. The row names indicating the gene name are the first two columns, so we'll need to specify that with `index_col=[0, 1]`, which says that the index columns/row names are the 0th and 1st columns, since we're counting from zero in the computer world.

Let's import pandas and all the other packages we'll need._____no_output_____

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import flotilla:0: FutureWarning: IPython widgets are experimental and may change in the future.
expression = pd.read_table('E-MTAB-513.tsv', skiprows=3, index_col=[0, 1])
expression.head()_____no_output_____

Interesting side note: you'll notice that "animal ovary" is the only thing indicated as "animal." This is because in the [Experimental Factor Ontology](http://bioportal.bioontology.org/ontologies/EFO) (EFO), they are defined as "[animal ovary](http://bioportal.bioontology.org/ontologies/EFO/?p=classes&conceptid=http%3A%2F%2Fwww.ebi.ac.uk%2Fefo%2FEFO_0000973&jump_to_nav=true)." This is because the EFO defines [plant ovary](http://bioportal.bioontology.org/ontologies/EFO/?p=classes&conceptid=http%3A%2F%2Fwww.ebi.ac.uk%2Fefo%2FEFO_0001052&jump_to_nav=true) separately. Apparently, in the venn diagram of the organs in animals versus the organs in plants, ovary is one of the few things that overlap! Cool! Thanks to [Nick Semenkovich](https://nick.semenkovich.com/) for [figuring this out](https://twitter.com/semenko/status/542049262725386240).

![Plant and animal organ overlap](http://i.imgur.com/JlgUDA8.png)

For `flotilla`, we follow the machine learning standard of using matrices in the format $(\text{samples}) \times (\text{features})$, like this

![Machine learning standard of a samples times feature matrix](http://i.imgur.com/Ckg4FiS.png)

Since this data is $(\text{features}) \times (\text{samples})$, we simply need to transpose the matrix with `.T`_____no_output_____

expression = expression.T
expression.head()_____no_output_____

Now, let's also replace all our NAs with 0s. This makes sense because if a gene is not detected, then its expression value will be 0. From the header file of the original data, it said:

    Genes matching: 'protein_coding' exactly, specifically expressed in any Organism part above the expression level cutoff: 0.5 in experiment E-MTAB-513

So we're forcing everything with expression less than 0.5 down to 0. Out of curiousity, let's see what was the minimum value left over after they did this 0.5 filter:_____no_output_____

expression.min().min()_____no_output_____

Cool, pretty close to 0.5. Now let's replace all NAs with 0, with `fillna(0)`._____no_output_____

expression = expression.fillna(0)_____no_output_____

Finally, we will add 1 and log-transform the data, so it's closer to normally distributed. Gene expression data is known to be log-normal._____no_output_____

expression = np.log2(expression + 1)_____no_output_____

### Create metadata about the expression features_____no_output_____The other thing that will make this data simpler to work with is making the columns of the data just use the crazy unique ENSEMBL id like "`ENSG00000280433`". First, let's check to see if the common names are actually unique. We'll expand out the column names to a list of tuples using `expression.columns.tolist()`_____no_output_____

ensembl_ids = pd.Index([a for a, b in expression.columns.tolist()])
gene_names = pd.Index([b for a, b in expression.columns.tolist()])_____no_output_____len(ensembl_ids.unique())_____no_output_____len(gene_names.unique())_____no_output_____

So there's fewer unique gene names, meaning we should use the ENSEMBL ids for the unique IDs. We'll do this by resetting the columns of `expression`, and creating metadata about the expression features, stored as `expression_feature_data`.

First, let's reassign the columns as the `ensembl_ids` we created from before._____no_output_____

expression.columns = ensembl_ids_____no_output_____

Now let's create the `expression_feature_data` DataFrame, and add a column of `'gene_name'` for the renamed feature._____no_output_____

expression_feature_data = pd.DataFrame(index=ensembl_ids)
expression_feature_data['gene_name'] = gene_names
expression_feature_data.head()_____no_output_____

## Preparing the metadata_____no_output_____For `flotilla`, every project is required to have metadata. We'll create one from scratch using the sample names from the expression data._____no_output_____

metadata = pd.DataFrame(index=expression.index)
metadata.head()_____no_output_____

The first category we'll use is pretty straightforward, it'll just be the name of the tissue. We can just use the index as the `'phenotype'`._____no_output_____

metadata['phenotype'] = metadata.index
metadata.head()_____no_output_____

Next, let's add some categories on the data, grouping different tissue types together that have the same structure or function. My awesome MD/PhD friend [Cynthia Hsu](http://mstp.ucsd.edu/people/Pages/grad-school.aspx) (you have to search for her name on the webpage) came up with these categories._____no_output_____

# All of these tissue types are part of the reproductive system
metadata['reproductive'] = metadata.phenotype.isin(['animal ovary', 'testis'])

# ALl of these tissue types generate hormones
metadata['hormonal'] = metadata.phenotype.isin(['animal ovary', 'testis', 'adrenal gland', 'thyroid'])

# These tissues are part of in the immune system
metadata['immune'] = metadata.phenotype.isin(['leukocyte', 'thyroid', 'lymph node'])

# These tissues are fatty
metadata['fatty'] = metadata.phenotype.isin(['adipose tissue', 'brain', 'breast'])

# These tissues contain either smooth (involuntary) or skeletal (voluntary) muscle
metadata['muscle'] = metadata.phenotype.isin(['colon', 'heart', 'prostate', 'skeletal muscle'])

# These tissues' main function is to filter blood in some way
metadata['filtration'] = metadata.phenotype.isin(['colon', 'kidney', 'liver'])

# These tissues have high blood flow to them, compared to other tissues
metadata['high_blood_flow'] = metadata.phenotype.isin(['brain', 'colon', 'kidney', 'liver', 'lung'])_____no_output_____

### Assign colors to the phenotypes_____no_output_____Now we need to choose colors for the data. Since we have 16 samples, none of the usual [ColorBrewer](http://bl.ocks.org/mbostock/5577023) colors apply because the maximum color set there is `Paired`, which is 12 colors. So we'll use a human-friendly version of the hue-lightness-saturation (hls) scale, called "husl". Read more at the [`seaborn` color tutorial](http://web.stanford.edu/~mwaskom/software/seaborn/tutorial/color_palettes.html)._____no_output_____

colors = sns.color_palette('husl', len(expression.index))
sns.palplot(colors)_____no_output_____

Let's create an iterator so we can easily loop over this list of colors without having to reference indices._____no_output_____

colors_iter = iter(colors)_____no_output_____

Finally, let's make the phenotype to color mapping as a dictionary._____no_output_____

phenotype_to_color = {phenotype: colors_iter.next() for phenotype in metadata.phenotype}
phenotype_to_color_____no_output_____

## Make a `flotilla` study!_____no_output_____

study = flotilla.Study(metadata, expression_data=expression,
                       metadata_phenotype_to_color=phenotype_to_color,
                       expression_feature_data=expression_feature_data,
                       expression_feature_rename_col='gene_name',
                       species='hg19')
study.expression.feature_data.head()2015-01-11 13:50:44	Initializing Study
2015-01-11 13:50:44	Initializing Predictor configuration manager for Study
2015-01-11 13:50:44	Predictor ExtraTreesClassifier is of type <class 'sklearn.ensemble.forest.ExtraTreesClassifier'>
2015-01-11 13:50:44	Added ExtraTreesClassifier to default predictors
2015-01-11 13:50:44	Predictor ExtraTreesRegressor is of type <class 'sklearn.ensemble.forest.ExtraTreesRegressor'>
2015-01-11 13:50:44	Added ExtraTreesRegressor to default predictors
2015-01-11 13:50:44	Predictor GradientBoostingClassifier is of type <class 'sklearn.ensemble.gradient_boosting.GradientBoostingClassifier'>
2015-01-11 13:50:44	Added GradientBoostingClassifier to default predictors
2015-01-11 13:50:44	Predictor GradientBoostingRegressor is of type <class 'sklearn.ensemble.gradient_boosting.GradientBoostingRegressor'>
2015-01-11 13:50:44	Added GradientBoostingRegressor to default predictors
2015-01-11 13:50:44	Loading metadata
2015-01-11 13:50:44	Loading species metadata from ~/flotilla_packages
https://s3-us-west-2.amazonaws.com/flotilla-projects/ercc/ERCC_Controls.txt has not been downloaded before.
	Downloading now to /home/jovyan/flotilla_projects/hg19/ERCC_Controls.txt
study.interactive_pca()featurewise : False
y_pc : 2
data_type : expression
std_multiplier : 2.0
most_variant_features : False
show_point_labels : False
plot_violins : False
sample_subset : all_samples
feature_subset : variant
bokeh : False
color_samples_by : phenotype
x_pc : 1
list_link :
study.plot_gene('RBFOX1')_____no_output_____study.plot_gene('ADIPOQ')_____no_output_____study.plot_gene('OCA2')_____no_output_____study.plot_gene('MAPT')_____no_output_____era_metadata = pd.read_table("E-MTAB-513.sdrf.txt")_____no_output_____from pprint import pprint_____no_output_____pprint(sorted(era_metadata.columns.tolist()))['Assay Name',
 'Characteristics[age]',
 'Characteristics[ethnic group]',
 'Characteristics[organism part]',
 'Characteristics[organism]',
 'Characteristics[sex]',
 'Comment[CYCLE_COUNT]',
 'Comment[ENA_EXPERIMENT]',
 'Comment[ENA_RUN]',
 'Comment[FASTQ_URI]',
 'Comment[LIBRARYPREP]',
 'Comment[LIBRARY_LAYOUT]',
 'Comment[LIBRARY_SELECTION]',
 'Comment[LIBRARY_SOURCE]',
 'Comment[LIBRARY_STRATEGY]',
 'Comment[NOMINAL_LENGTH]',
 'Comment[NOMINAL_SDEV]',
 'Comment[ORIENTATION]',
 'Comment[READ_INDEX_0_BASE_COORD]',
 'Comment[READ_INDEX_0_READ_CLASS]',
 'Comment[READ_INDEX_0_READ_TYPE]',
 'Comment[READ_INDEX_1_BASE_COORD]',
 'Comment[READ_INDEX_1_READ_CLASS]',
 'Comment[READ_INDEX_1_READ_TYPE]',
 'Comment[SEQUENCE_LENGTH]',
 'Comment[SPOT_LENGTH]',
 'Comment[SUBMITTED_FILE_NAME]',
 'Comment[ascii_offset]',
 'Comment[biosource provider]',
 'Comment[insertSize]',
 'Comment[quality_encoding]',
 'Comment[quality_scoring_system]',
 'Comment[spiked_in]',
 'Description',
 'Extract Name',
 'Factor Value[organism part]',
 'Material Type',
 'Material Type.1',
 'Performer',
 'Protocol REF',
 'Protocol REF.1',
 'Protocol REF.2',
 'Scan Name',
 'Source Name',
 'Technology Type',
 'Unit[TimeUnit]']
era_metadata['Comment[biosource provider]']_____no_output_____era_metadata['Scan Name']_____no_output_____era_metadata['Material Type']_____no_output_____era_metadata['Material Type.1']_____no_output_____era_metadata.Description_____no_output_____study.interactive_clustermap()data_type : expression
metric : euclidean
sample_subset : all_samples
feature_subset : biomark_neural_panel
fig_height :
scale_fig_by_data : True
fig_width :
list_link :
method : average
study.save('bodymap2')_____no_output_____