diff --git a/descriptor_role/descriptor_role.ipynb b/descriptor_role/descriptor_role.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..969919921a4641ff1520e88be6ef4b51e1a8820d
--- /dev/null
+++ b/descriptor_role/descriptor_role.ipynb
@@ -0,0 +1,638 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "ExecuteTime": {
+     "end_time": "2020-09-02T17:38:25.190477Z",
+     "start_time": "2020-09-02T17:38:25.181926Z"
+    }
+   },
+   "outputs": [],
+   "source": [
+    "%%HTML\n",
+    "<script>\n",
+    "\n",
+    "window.findCellIndicesByTag = function findCellIndicesByTag(tagName) {\n",
+    "  return (Jupyter.notebook.get_cells()\n",
+    "    .filter(\n",
+    "      ({metadata: {tags}}) => tags && tags.includes(tagName)\n",
+    "    )\n",
+    "    .map((cell) => Jupyter.notebook.find_cell_index(cell))\n",
+    "  );\n",
+    "};\n",
+    "\n",
+    "window.runCells = function runCells(tagName) {\n",
+    "    var c = window.findCellIndicesByTag(tagName);\n",
+    "    Jupyter.notebook.execute_cells(c);\n",
+    "};\n",
+    "\n",
+    "</script>"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "<div id=\"teaser\" style=' background-position:  right center; background-size: 00px; background-repeat: no-repeat; \n",
+    "    padding-top: 20px;\n",
+    "    padding-right: 10px;\n",
+    "    padding-bottom: 170px;\n",
+    "    padding-left: 10px;\n",
+    "    border-bottom: 14px double #333;\n",
+    "    border-top: 14px double #333;' > \n",
+    "\n",
+    "   \n",
+    "   <div style=\"text-align:center\">\n",
+    "    <b><font size=\"6.4\">Predicting energy differences between crystal structures: (Meta-)stability of octet-binary compounds</font></b>    \n",
+    "  </div>\n",
+    "    \n",
+    "<p>\n",
+    "created by: Mohammad-Yasin Arif, Luigi Sbailò, Thomas A. R. Purcell, Luca M. Ghiringhelli, and Matthias Scheffler\n",
+    "   \n",
+    "based on the original version designed by: Angelo Ziletti, Emre Ahmetcik, Runhai Ouyang, Luca M. Ghiringhelli, and Matthias Scheffler<br><br>\n",
+    "   \n",
+    "Fritz Haber Institute of the Max Planck Society, Faradayweg 4-6, D-14195 Berlin, Germany <br>\n",
+    "<span class=\"nomad--last-updated\" data-version=\"v1.0.0\">[Last updated: Sep 5, 2020]</span>\n",
+    "\n",
+    "  \n",
+    "<div> \n",
+    "<img  style=\"float: left;\" src=\"assets/descriptor_role/Logo_MPG.png\" width=\"200\"> \n",
+    "<img  style=\"float: right;\" src=\"assets/descriptor_role/Logo_NOMAD.png\" width=\"250\">\n",
+    "</div>\n",
+    "</div>"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {
+    "ExecuteTime": {
+     "end_time": "2020-09-07T23:35:12.780844Z",
+     "start_time": "2020-09-07T23:35:12.772398Z"
+    },
+    "init_cell": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<script>\n",
+       "    code_show=true; \n",
+       "    function code_toggle() {\n",
+       "        if (code_show)\n",
+       "        {\n",
+       "            $('div.input').hide();\n",
+       "        } \n",
+       "        else \n",
+       "        {\n",
+       "            $('div.input').show();\n",
+       "        }\n",
+       "        code_show = !code_show\n",
+       "    } \n",
+       "    $( document ).ready(code_toggle);\n",
+       "    window.runCells(\"startup\");\n",
+       "</script>\n",
+       "The raw code for this notebook is by default hidden for easier reading.\n",
+       "To toggle on/off the raw code, click <a href=\"javascript:code_toggle()\">here</a>.\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%%HTML\n",
+    "<script>\n",
+    "    code_show=true; \n",
+    "    function code_toggle() {\n",
+    "        if (code_show)\n",
+    "        {\n",
+    "            $('div.input').hide();\n",
+    "        } \n",
+    "        else \n",
+    "        {\n",
+    "            $('div.input').show();\n",
+    "        }\n",
+    "        code_show = !code_show\n",
+    "    } \n",
+    "    $( document ).ready(code_toggle);\n",
+    "    window.runCells(\"startup\");\n",
+    "</script>\n",
+    "The raw code for this notebook is by default hidden for easier reading.\n",
+    "To toggle on/off the raw code, click <a href=\"javascript:code_toggle()\">here</a>."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Introduction\n",
+    "This tutorial shows how to find descriptive parameters (short formulas) that predict the crystal structure (here, rocksalt (RS) or zincblende (ZB)), using the example of octet binary compounds. It is based on the algorithm sure independence screening and sparsifying operator (SISSO), that enables to search for optimal descriptor by scanning huge feature spaces.\n",
+    "\n",
+    "<div style=\"padding: 1ex; margin-top: 1ex; margin-bottom: 1ex; border-style: dotted; border-width: 1pt; border-color: blue; border-radius: 3px;\">R. Ouyang, S. Curtarolo, E. Ahmetcik, M. Scheffler, L. M. Ghiringhelli: <span style=\"font-style: italic;\">SISSO: a compressed-sensing method for identifying the best low-dimensional descriptor in an immensity of offered candidates</span>, Phys. Rev. Materials  2, 083802 (2018) <a href=\"https://journals.aps.org/prmaterials/abstract/10.1103/PhysRevMaterials.2.083802\" target=\"_blank\">[PDF]</a>.</div>\n",
+    "\n",
+    "With the default settings, the method reproduces the same results from:\n",
+    "\n",
+    "<div style=\"padding: 1ex; margin-top: 1ex; margin-bottom: 1ex; border-style: dotted; border-width: 1pt; border-color: blue; border-radius: 3px;\">L. M. Ghiringhelli, J. Vybiral, S. V. Levchenko, C. Draxl, M. Scheffler: <span style=\"font-style: italic;\">Big Data of Materials Science: Critical Role of the Descriptor</span>,  Phys. Rev. Lett. 114, 105503 (2015) <a href=\"http://journals.aps.org/prl/abstract/10.1103/PhysRevLett.114.105503\">[PDF]</a>,</div>"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "<details>\n",
+    "    <summary>\n",
+    "        <div style=\"padding: 1ex; margin-top: 1ex; margin-bottom: 1ex; border-style: dotted; border-width: 1pt; border-color: blue; border-radius: 3px;\"><b>Explanation of the method (click to expand)</b></div></summary>\n",
+    "\n",
+    "We present a tool for predicting the crystal structure of octet binary compounds, by using a set of descriptive parameters (a descriptor) based on free-atom data of the atomic species constituting the binary material. We apply a newly developed method: sure independence screening and sparsifying operator (SISSO), that allows to find an optimal descriptor in a huge feature space containing billions of features. In this tutorial an $\\ell_0$-optimization is used as the sparsifying operator.\n",
+    "The method is described in:\n",
+    "               \n",
+    "<div style=\"padding: 1ex; margin-top: 1ex; margin-bottom: 1ex; border-style: dotted; border-width: 1pt; border-color: blue; border-radius: 3px;\">\n",
+    "R. Ouyang, S. Curtarolo, E. Ahmetcik, M. Scheffler, L. M. Ghiringhelli: <span style=\"font-style: italic;\">SISSO: a compressed-sensing method for identifying the best low-dimensional descriptor in an immensity of offered candidates</span>, Phys. Rev. Materials  2, 083802 (2018) <a href=\"https://journals.aps.org/prmaterials/abstract/10.1103/PhysRevMaterials.2.083802\" target=\"_blank\">[PDF]</a>. <br> </div>\n",
+    "               \n",
+    "SISSO($\\ell_0$) works iteratively. In the first iteration, a number k of features is collected that have the largest correlation (scalar product) with the property vector. The feature with the largest correlation is simply the 1D descriptor. Next, a residual is constructed as the error made at the first iteration. A new set of k features is now selected as those having the largest  correlation with the residual. The 2D descriptor is the pair of features that yield the smallest fitting error upon least square regression, among all possible pairs contained in the union of the sets selected in this and the first iteration. In each next iteration a new residual is constructed as the error made in the previous iteration, then a new set of k features is extracted as those that have largest correlation with each new residual. The nD descriptor is the n-tuple of features that yield the smallest fitting error upon least square regression, among all possible n-tuples contained in the union of the sets obtained in each new iteration and all the previous iterations. If k=1 the method collapses to the so-called orthogonal matching pursuit.\n",
+    "               \n",
+    "The prediction of the ground-state structure for binary compounds from a simple descriptor has a notable history in materials science [1-7], where descriptors were designed by chemically/physically-inspired intuition. The tool presented here allows for the machine-learning-aided automatic discovery of a descriptor and a model for the prediction of the difference in energy between a selected pair of structures for 82 octet binary materials.\n",
+    "\n",
+    "By running the tutorial with the default setting, the (RS vs. ZB) results of the <a href=\"http://journals.aps.org/prl/abstract/10.1103/PhysRevLett.114.10550\" target=\"_blank\">PRL 2015</a> identified by the LASSO+$\\ell_0$ method can be recovered. SISSO and LASSO+$\\ell_0$ do not always yield the same results (see <a href=\"http://analytics-toolkit.nomad-coe.eu/tutorial-SIS\">compressed-sensing tutorial</a>) but in this case the default model parameters were tuned to obtain the same results.\n",
+    "Additionally, in <a href=\"http://journals.aps.org/prl/abstract/10.1103/PhysRevLett.114.10550\" target=\"_blank\">PRL-2015</a>, a slightly different criterion for the construction of the feature set was adopted, compared to <a href=\"https://journals.aps.org/prmaterials/abstract/10.1103/PhysRevMaterials.2.083802\" target=\"_blank\">PRM-2018</a>. For the sake of reproducing exactly the results of <a href=\"http://journals.aps.org/prl/abstract/10.1103/PhysRevLett.114.10550\" target=\"_blank\">PRL-2015</a>, the default settings in the input widget include \"PRL2015\" as choice for \"SISSO rung\".\n",
+    "               \n",
+    "   References:\n",
+    "            <ol>\n",
+    "                <li>J. A. van Vechten, Phys. Rev. 182, 891 (1969).</li>\n",
+    "                <li>J. C. Phillips, Rev. Mod. Phys. 42, 317 (1970).</li>\n",
+    "                <li>J. John and A. N. Bloch, Phys. Rev. Lett. 33, 1095 (1974).</li>\n",
+    "                <li>J. R. Chelikowsky and J. C. Phillips, Phys. Rev. B 17, 2453 (1978).</li>\n",
+    "                <li>A. Zunger, Phys. Rev. B 22, 5839 (1980).</li>\n",
+    "                <li>D. G. Pettifor, Solid State Commun. 51, 31 (1984).</li>\n",
+    "                <li>Y. Saad, D. Gao, T. Ngo, S. Bobbitt, J. R. Chelikowsky, and W. Andreoni, Phys. Rev. B 85, 104104 (2012).</li>\n",
+    "                </ol>\n",
+    "\n",
+    "\n",
+    "In this example, you can run a compressed-sensing based algorithm for finding the optimal descriptor and model that predicts the difference in energy between crystal structures (here, zincblende vs. rocksalt).\n",
+    "The descriptor is selected out of a large number of candidates constructed as functions of basic input features, the primary features.\n",
+    "\n",
+    "</details>"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "The idea demonstrated in this tutorial is to start from simple physical quantities (\"primary features\", here properties of the constituent free atoms such as orbital radii), to generate millions (or billions) of candidate formulas by applying arithmetic operations combining primary features. These candidate formulas constitute the so-called \"feature space\". Then, SISSO is used to select only a few of these formulas that explain the data.\n",
+    "\n",
+    "By clicking directly on \"Run\" below, you can reproduce results from the above publication, or you can modify the settings to produce your own results. To the purpose, in the panel below, you can select primary features and allowed operations by clicking the check-boxes. You can also select the SISSO rung (i.e., the number of iterations in the construction of the feature space), the number of features that are selected at each iteration of the SIS step, and the max number of dimensions of the model. Then, press \"Run\". After the results are shown for all models from one dimensional to the max chosen dimension, you can press \"Plot interactive map\" to reveal a map of the RS vs ZB relative stability, for the highest dimensional model. If the highest dimension model is 2D, the separation line between the two phases (i.e., the locus where the predicted $\\Delta$E is zero) is shown. For higher dimensional models, the 3rd and 4th dimensions can be controlled by the size of the Marker or the Color. Drop-down menus allow to assign axes, markers, and colors, to the descriptor components of choice"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {
+    "ExecuteTime": {
+     "end_time": "2020-09-07T23:35:14.358151Z",
+     "start_time": "2020-09-07T23:35:12.782531Z"
+    },
+    "init_cell": true,
+    "tags": [
+     "startup"
+    ]
+   },
+   "outputs": [
+    {
+     "data": {
+      "application/vnd.jupyter.widget-view+json": {
+       "model_id": "7cfe39040a2a4a90a815b3111f21e11f",
+       "version_major": 2,
+       "version_minor": 0
+      },
+      "text/plain": [
+       "_ColormakerRegistry()"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "import os\n",
+    "import pandas as pd\n",
+    "import numpy as np\n",
+    "from itertools import combinations\n",
+    "from time import time\n",
+    "import matplotlib.pyplot as plt \n",
+    "import scipy.stats as ss\n",
+    "import warnings\n",
+    "from collections import Counter\n",
+    "from sklearn.kernel_ridge import KernelRidge\n",
+    "from sklearn.model_selection import GridSearchCV, LeaveOneOut\n",
+    "from IPython.display import HTML, clear_output\n",
+    "import ipywidgets as widgets\n",
+    "\n",
+    "import plotly.graph_objects as go\n",
+    "from ipywidgets import widgets, interactive\n",
+    "from jupyter_jsmol import JsmolView\n",
+    "\n",
+    "import nglview\n",
+    "from ase.io import read\n",
+    "\n",
+    "from descriptor_role.utils import generate_structures\n",
+    "from descriptor_role.visualizer import Visualizer\n",
+    "from cpp_sisso import generate_fs, SISSORegressor, generate_phi_0_from_csv, FeatureSpace\n",
+    "\n",
+    "# set display options for the notebook \n",
+    "%matplotlib inline\n",
+    "warnings.filterwarnings('ignore')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {
+    "ExecuteTime": {
+     "end_time": "2020-09-07T23:35:14.497884Z",
+     "start_time": "2020-09-07T23:35:14.374405Z"
+    },
+    "init_cell": true,
+    "tags": [
+     "startup"
+    ]
+   },
+   "outputs": [],
+   "source": [
+    "# load data\n",
+    "RS_structures = read(\"data/descriptor_role/RS_structures.xyz\", index=':')\n",
+    "ZB_structures = read(\"data/descriptor_role/ZB_structures.xyz\", index=':')\n",
+    "\n",
+    "def generate_table(RS_structures, ZB_structures):\n",
+    "\n",
+    "    for RS, ZB in zip(RS_structures, ZB_structures):\n",
+    "        energy_diff = RS.info['energy'] - ZB.info['energy']\n",
+    "        min_struc_type = 'RS' if energy_diff < 0 else 'ZB'\n",
+    "        struc_obj_min = RS if energy_diff < 0 else ZB\n",
+    "\n",
+    "        yield [RS.info['energy'], ZB.info['energy'],\n",
+    "               energy_diff, min_struc_type,\n",
+    "               RS.info['Z'], ZB.info['Z'],\n",
+    "               RS.info['period'], ZB.info['period'],\n",
+    "               RS.info['IP'], ZB.info['IP'],\n",
+    "               RS.info['EA'], ZB.info['EA'],\n",
+    "               RS.info['E_HOMO'], ZB.info['E_HOMO'],\n",
+    "               RS.info['E_LUMO'], ZB.info['E_LUMO'],\n",
+    "               RS.info['r_s'], ZB.info['r_s'],\n",
+    "               RS.info['r_p'], ZB.info['r_p'],\n",
+    "               RS.info['r_d'], ZB.info['r_d'],\n",
+    "               abs(RS.info['r_p']+RS.info['r_s']-ZB.info['r_p']-ZB.info['r_s']),\n",
+    "               abs(RS.info['r_p']-RS.info['r_s'])+abs(ZB.info['r_p']-ZB.info['r_s']),\n",
+    "               RS, ZB, struc_obj_min]\n",
+    "    \n",
+    "df = pd.DataFrame(\n",
+    "    generate_table(RS_structures, ZB_structures),\n",
+    "    columns=['energy_RS', 'energy_ZB', \n",
+    "             'energy_diff', 'min_struc_type', \n",
+    "             'Z_A (nuc_charge)', 'Z_B (nuc_charge)', \n",
+    "             'period_A (unitless)', 'period_B (unitless)', \n",
+    "             'IP_A (eV_IP)', 'IP_B (eV_IP)', \n",
+    "             'EA_A (eV_IP)', 'EA_B (eV_IP)', \n",
+    "             'E_HOMO_A (eV)', 'E_HOMO_B (eV)', \n",
+    "             'E_LUMO_A (eV)', 'E_LUMO_B (eV)', \n",
+    "             'r_s_A', 'r_s_B', \n",
+    "             'r_p_A', 'r_p_B', \n",
+    "             'r_d_A', 'r_d_B',\n",
+    "             'r_sigma', 'r_pi',\n",
+    "             'struc_obj_RS', 'struc_obj_ZB', 'struc_obj_min'],\n",
+    "    index=list(RS.get_chemical_formula() for RS in RS_structures)\n",
+    ")\n",
+    "\n",
+    "# print data without structure objects\n",
+    "df_reduced = df.drop(['energy_RS', 'energy_ZB', 'min_struc_type', 'struc_obj_RS', 'struc_obj_ZB', 'struc_obj_min'], axis=1)\n",
+    "#df_reduced"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {
+    "ExecuteTime": {
+     "end_time": "2020-09-07T23:35:14.501983Z",
+     "start_time": "2020-09-07T23:35:14.499428Z"
+    },
+    "init_cell": true,
+    "tags": [
+     "startup"
+    ]
+   },
+   "outputs": [],
+   "source": [
+    "def plot_2d_solution(b):\n",
+    "    with out2:\n",
+    "        clear_output()\n",
+    "        generate_structures (RS_structures,ZB_structures)\n",
+    "        visualizer=Visualizer(df, sisso, feat_space)\n",
+    "        visualizer.show()\n",
+    "        "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {
+    "ExecuteTime": {
+     "end_time": "2020-09-07T23:35:14.513239Z",
+     "start_time": "2020-09-07T23:35:14.503363Z"
+    },
+    "init_cell": true,
+    "tags": [
+     "startup"
+    ]
+   },
+   "outputs": [],
+   "source": [
+    "def get_feat_space_and_sr(\n",
+    "    df,\n",
+    "    ops=[\"add\", \"abs_diff\", \"div\", \"sq\", \"exp\"],\n",
+    "    cols=\"all\",\n",
+    "    max_phi=2,\n",
+    "    n_sis_select=50,\n",
+    "    remove_double_divison=True,\n",
+    "    max_dim=3,\n",
+    "    n_residual=1,\n",
+    "    default=True,\n",
+    "):\n",
+    "    phi_0, prop_unit, prop, prop_test, task_sizes_train, task_sizes_test, leave_out_inds = generate_phi_0_from_csv(\n",
+    "        df, \"energy_diff\", cols=cols, task_key=None, leave_out_frac=0.0, leave_out_inds=None\n",
+    "    )\n",
+    "    if default:\n",
+    "        feat_space = FeatureSpace(\n",
+    "            \"./data/descriptor_role/phi.txt\", \n",
+    "            phi_0, \n",
+    "            task_sizes_train, \n",
+    "            n_sis_select, \n",
+    "            1.0\n",
+    "        )\n",
+    "    else:\n",
+    "        feat_space = generate_fs(\n",
+    "            phi_0, \n",
+    "            prop, \n",
+    "            task_sizes_train, \n",
+    "            ops,  \n",
+    "            max_phi, \n",
+    "            n_sis_select\n",
+    "        )\n",
+    "        \n",
+    "    sisso = SISSORegressor(\n",
+    "        feat_space,\n",
+    "        prop_unit,\n",
+    "        prop,\n",
+    "        prop_test,\n",
+    "        task_sizes_train,\n",
+    "        task_sizes_test,\n",
+    "        leave_out_inds,\n",
+    "        max_dim,\n",
+    "        1,\n",
+    "        1\n",
+    "    )\n",
+    "    return feat_space, sisso"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {
+    "ExecuteTime": {
+     "end_time": "2020-09-07T23:35:14.526034Z",
+     "start_time": "2020-09-07T23:35:14.514653Z"
+    },
+    "init_cell": true,
+    "tags": [
+     "startup"
+    ]
+   },
+   "outputs": [],
+   "source": [
+    "def prl_select(change):\n",
+    "    if change['new'] == 'PRL set':\n",
+    "        default_selection('')\n",
+    "    else:\n",
+    "        for widget in op_list+feat_list:\n",
+    "            widget.disabled = False\n",
+    "\n",
+    "def default_selection(b):\n",
+    "    default_operations = ['add','abs_diff','exp','sq','div']\n",
+    "    default_features = ['IP','EA','r_s','r_p','r_d']\n",
+    "    for op, widget in zip(possible_operations, op_list):\n",
+    "        widget.value = op in default_operations\n",
+    "        widget.disabled = True\n",
+    "    for feat, widget in zip(possible_features, feat_list):\n",
+    "        widget.value = feat in default_features\n",
+    "        widget.disabled = True\n",
+    "    tier_selection.value = 'PRL set'\n",
+    "    feat_per_iter_selection.value = 50\n",
+    "    dimension_selection.value = 2\n",
+    "    \n",
+    "def find_descriptors(b):\n",
+    "    with out2:\n",
+    "        clear_output()    \n",
+    "    with out1:\n",
+    "        clear_output()\n",
+    "        print('Calculating...', flush=True)\n",
+    "        selected_features = []\n",
+    "        allowed_operations = []\n",
+    "        for op, widget in zip(possible_operations, op_list):\n",
+    "            if widget.value:\n",
+    "                allowed_operations.append(op)\n",
+    "        \n",
+    "        for feat, widget in zip(possible_features, feat_list):\n",
+    "            if widget.value:\n",
+    "                if feat == 'r_sigma' or feat == 'r_pi':\n",
+    "                    selected_features.append(feat)\n",
+    "                else:\n",
+    "                    selected_features.extend([feat+nuc for nuc in ['_A', '_B']])       \n",
+    "        \n",
+    "        if tier_selection.value == 'PRL set':\n",
+    "            selected_features = \"all\"\n",
+    "            tier = 2\n",
+    "            default = True\n",
+    "        else:\n",
+    "            tier = tier_selection.value\n",
+    "            default = False\n",
+    "            \n",
+    "        global feat_space\n",
+    "        global sisso\n",
+    "        feat_space, sisso = get_feat_space_and_sr(\n",
+    "            df = df_reduced,\n",
+    "            ops = allowed_operations,\n",
+    "            cols = selected_features,\n",
+    "            max_phi = tier,\n",
+    "            n_sis_select = feat_per_iter_selection.value,\n",
+    "            remove_double_divison=True,\n",
+    "            max_dim = dimension_selection.value,\n",
+    "            n_residual = 1,\n",
+    "            default = default)\n",
+    "        \n",
+    "        clear_output()\n",
+    "        if (dimension_selection.value>1):\n",
+    "            plot_button.disabled=False\n",
+    "        else:\n",
+    "            plot_button.disabled=True\n",
+    "\n",
+    "        print(\"Number of features generated: \" + str(feat_space.n_feat))\n",
+    "\n",
+    "        try:\n",
+    "            sisso.fit()\n",
+    "            for i in range(dimension_selection.value):\n",
+    "                print(str(i+1)+'D model')\n",
+    "                print(\"RMSE: {:.4} | Descriptor: {}\".format(sisso.models[i][0].rmse, sisso.models[i][0]))\n",
+    "                string = \"c0:{:.4}\".format(sisso.models[i][0].coefs[0][-1])\n",
+    "                for j in range(i+1):\n",
+    "                    string = string + str(\"  |  a\"+str(j)+\":{:.4}\".format(sisso.models[i][0].coefs[0][j]))\n",
+    "                print(string + '\\n')\n",
+    "                \n",
+    "                    \n",
+    "        except RuntimeError:\n",
+    "            print(\"\\nThe number of selected features per SIS iteration is bigger than the number \"\n",
+    "                  + \"of features available.\\nPlease reduce the number of selected features per \"\n",
+    "                  + \"SIS iteration or increase the number of selected features and operations.\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {
+    "ExecuteTime": {
+     "end_time": "2020-09-07T23:35:14.800409Z",
+     "start_time": "2020-09-07T23:35:14.527254Z"
+    },
+    "init_cell": true,
+    "scrolled": false,
+    "tags": [
+     "startup"
+    ]
+   },
+   "outputs": [
+    {
+     "data": {
+      "application/vnd.jupyter.widget-view+json": {
+       "model_id": "3284145a3e6142b3995cc305850bbdb1",
+       "version_major": 2,
+       "version_minor": 0
+      },
+      "text/plain": [
+       "VBox(children=(HBox(children=(VBox(children=(Label(value=''), Checkbox(value=True, disabled=True, indent=False…"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "cb_layout = widgets.Layout(width = '15px')\n",
+    "thin_layout = widgets.Layout(width = '100px')\n",
+    "mid_layout = widgets.Layout(width = '200px')\n",
+    "wide_layout = widgets.Layout(width = '300px')\n",
+    "\n",
+    "#possible_operations = ['add', 'sub', 'abs_diff', 'mult', 'div', 'exp', 'neg_exp', 'inv', 'sq', 'cb', \n",
+    "#                       'six_pow', 'sqrt', 'cbrt', 'log', 'abs', 'sin', 'cos']\n",
+    "possible_operations = ['add', 'sub', 'abs_diff', 'mult', 'div', 'exp', 'neg_exp', 'inv', 'sq', 'cb', \n",
+    "                        'sqrt', 'cbrt', 'log', 'abs']\n",
+    "\n",
+    "possible_features = ['Z','IP','EA','E_HOMO','E_LUMO','r_s','r_p','r_d', 'r_sigma', 'r_pi']\n",
+    "\n",
+    "tooltips = {\n",
+    "    \"Z\" : \"Atomic number\",\n",
+    "    \"IP\" : \"Atomic ionization potential\",\n",
+    "    \"EA\" : \"Atomic electron affinity\",\n",
+    "    \"E_HOMO\" : \"Energy of highest occupied atomic orbital\",\n",
+    "    \"E_LUMO\" : \"Energy of lowest unoccupied molecular orbital\",\n",
+    "    \"r_s\" : \"Radius at which the radial probability density of the valence s orbital is maximum\",\n",
+    "    \"r_p\" : \"Radius at which the radial probability density of the valence p orbital is maximum\",\n",
+    "    \"r_d\" : \"Radius at which the radial probability density of the valence d orbital is maximum\",\n",
+    "    \"r_sigma\" : \"John-Bloch's indicator 1: |rp(A) + rs(A) - rp(B)  - rs(B)|  [Phys. Rev. Lett. 33. 1095 (1974)\",\n",
+    "    \"r_pi\": \"John-Bloch's indicator2: |rp(A) - rs(A)| +| rp(B) - rs(B)| [Phys. Rev. Lett. 33. 1095 (1974)]\"\n",
+    "}\n",
+    "\n",
+    "labels = {\n",
+    "    'add' : '$x + y$', 'sub' : '$x - y$', 'abs_diff' : '$|x - y|$', 'mult' : '$x \\cdot y$', 'div' : '$x / y$',\n",
+    "    'exp' : '$\\exp(x)$', 'neg_exp' : '$\\exp(-x)$', 'inv' : '$1/x$', 'sq' : '$x^2$', 'cb' : '$x^3$', \n",
+    "    'six_pow' : '$x^6$', 'sqrt' : '$\\sqrt{x}$', 'cbrt' : '$\\sqrt[3]{x}$', 'log' : '$\\log(x)$',\n",
+    "    'abs' :  '$|x|$', 'sin' : '$\\sin(x)$', 'cos' : '$\\cos(x)$', 'Z' : '$Z$', 'IP' : '$IP$', 'EA' : '$EA$',\n",
+    "    'E_HOMO' : '$E_{HOMO}$', 'E_LUMO' : '$E_{LUMO}$', 'r_s' : '$r_s$', 'r_p' : '$r_p$', 'r_d' :  '$r_d$',\n",
+    "    'r_sigma' : '$r_\\sigma$', 'r_pi' : '$r_\\pi$'\n",
+    "}\n",
+    "\n",
+    "op_list = []\n",
+    "op_labels  = []\n",
+    "feat_list = []\n",
+    "feat_labels = []\n",
+    "for operation in possible_operations:\n",
+    "    op_list.append(widgets.Checkbox(description='', value=True, indent=False, layout=cb_layout))\n",
+    "    op_labels.append(widgets.Label(value=labels[operation]))\n",
+    "for feature in possible_features:\n",
+    "    feat_list.append(widgets.Checkbox(description=tooltips[feature], value=True, indent=False, layout=cb_layout))\n",
+    "    feat_labels.append(widgets.Label(value=labels[feature]))\n",
+    "    \n",
+    "op_box = widgets.VBox([widgets.Label()]+op_list)\n",
+    "op_label_box = widgets.VBox([widgets.Label(value='Operations:', layout=thin_layout)]+op_labels)\n",
+    "feat_box = widgets.VBox([widgets.Label()]+feat_list)\n",
+    "feat_label_box = widgets.VBox([widgets.Label(value='Features:', layout=thin_layout)]+feat_labels)\n",
+    "\n",
+    "tier_selection = widgets.Dropdown(options=['PRL set', 1,2,3], layout=thin_layout)\n",
+    "feat_per_iter_selection = widgets.BoundedIntText(value=26, min=1, max=100, step=1, layout=thin_layout)\n",
+    "dimension_selection = widgets.BoundedIntText(value = 3, min=1, max=4, step=1, layout = thin_layout)\n",
+    "settings_box = widgets.VBox([\n",
+    "    widgets.Label(value='Settings:', layout=wide_layout),\n",
+    "    widgets.Label(value='SISSO Tier Level:', layout=wide_layout),\n",
+    "    tier_selection,\n",
+    "    widgets.Label(value='Number of selected features per SIS iteration:', layout=wide_layout),\n",
+    "    feat_per_iter_selection,\n",
+    "    widgets.Label(value='Maximum number of dimensions:', layout=wide_layout),\n",
+    "    dimension_selection])\n",
+    "\n",
+    "default_button = widgets.Button(description = 'Default selection', layout=mid_layout)\n",
+    "descriptor_button = widgets.Button(description = 'Run', layout=mid_layout)\n",
+    "plot_button = widgets.Button(description = 'Plot interactive map', disabled=True, layout=mid_layout)\n",
+    "default_button.on_click(default_selection)\n",
+    "descriptor_button.on_click(find_descriptors)\n",
+    "plot_button.on_click(plot_2d_solution)\n",
+    "button_box = widgets.VBox([default_button, descriptor_button, plot_button])\n",
+    "\n",
+    "out1 = widgets.Output()\n",
+    "out2 = widgets.Output()\n",
+    "\n",
+    "gui_box = widgets.HBox([op_box, op_label_box, feat_box, feat_label_box, settings_box, button_box])\n",
+    "out_box = widgets.VBox([gui_box, out1, out2])\n",
+    "\n",
+    "tier_selection.observe(prl_select, names='value')\n",
+    "\n",
+    "default_selection('')\n",
+    "display(out_box)"
+   ]
+  }
+ ],
+ "metadata": {
+  "celltoolbar": "Initialization Cell",
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.7.9"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/descriptor_role/visualizer.py b/descriptor_role/visualizer.py
index 0e04738e5ddae08ff628711755e793a641249e1c..6606573ef43e7701228bda768b26b64a037f79b4 100644
--- a/descriptor_role/visualizer.py
+++ b/descriptor_role/visualizer.py
@@ -40,6 +40,12 @@ class Visualizer:
                             "longdash",
                             "dashdot",
                             "longdashdot"]
+        self.gradient_list = ['Blue to red',
+                              'Blue to green',
+                              'Green to red',
+                              'Grey scale',
+                              'Purple scale',
+                              'Turquoise scale']
         self.bg_color = 'rgba(229,236,246, 0.5)'
         self.zb_color = "#EB8273"
         self.rs_color = "rgb(138, 147, 248)"
@@ -173,6 +179,9 @@ class Visualizer:
         self.scatter_line = self.fig.data[2]
         if self.total_features == 2:
             self.scatter_line.visible = True
+        else:
+            self.widg_linewidth.disabled = True
+            self.widg_linestyle.disabled = True
 
         self.update_markers()
 
@@ -294,36 +303,50 @@ class Visualizer:
                     string = 'rgb(' + str(0) + "," + str(value) + "," + str(value) + ')'
                     self.ZB_colors[i] = string
 
-            if gradient == 'Red scale':
+            shade_RS = 0.7 * (
+                        self.df_selected.loc[self.df_selected['Structure'] == 'RS'][feature].to_numpy() - min_value) / \
+                       (max_value - min_value)
+            shade_ZB = 0.7 * (
+                        self.df_selected.loc[self.df_selected['Structure'] == 'ZB'][feature].to_numpy() - min_value) / \
+                       (max_value - min_value)
+            if gradient == 'Blue to green':
                 for i, e in enumerate(shade_RS):
-                    value = 255 * (0.7 - e)
-                    string = 'rgb(' + str(value) + "," + str(0) + "," + str(0) + ')'
+                    value = 255 * e
+                    value2 = 255 - value
+                    string = 'rgb(' + str(0) + "," + str(value) + "," + str(value2) + ')'
                     self.RS_colors[i] = string
                 for i, e in enumerate(shade_ZB):
-                    value = 255 * (0.7 - e)
-                    string = 'rgb(' + str(value) + "," + str(0) + "," + str(0) + ')'
+                    value = 255 * e
+                    value2 = 255 - value
+                    string = 'rgb(' + str(0) + "," + str(value) + "," + str(value2) + ')'
                     self.ZB_colors[i] = string
 
-            if gradient == 'Blue scale':
+            if gradient == 'Blue to red':
                 for i, e in enumerate(shade_RS):
-                    value = 255 * (0.7 - e)
-                    string = 'rgb(' + str(0) + "," + str(0) + "," + str(value) + ')'
+                    value = 255 * e
+                    value2 = 255 - value
+                    string = 'rgb(' + str(value) + "," + str(0) + "," + str(value2) + ')'
                     self.RS_colors[i] = string
                 for i, e in enumerate(shade_ZB):
-                    value = 255 * (0.7 - e)
-                    string = 'rgb(' + str(0) + "," + str(0) + "," + str(value) + ')'
+                    value = 255 * e
+                    value2 = 255 - value
+                    string = 'rgb(' + str(value) + "," + str(0) + "," + str(value2) + ')'
                     self.ZB_colors[i] = string
 
-            if gradient == 'Green scale':
+            if gradient == 'Green to red':
                 for i, e in enumerate(shade_RS):
-                    value = 255 * (0.7 - e)
-                    string = 'rgb(' + str(0) + "," + str(value) + "," + str(0) + ')'
+                    value = 255 * e
+                    value2 = 255 - value
+                    string = 'rgb(' + str(value) + "," + str(value2) + "," + str(0) + ')'
                     self.RS_colors[i] = string
                 for i, e in enumerate(shade_ZB):
-                    value = 255 * (0.7 - e)
-                    string = 'rgb(' + str(0) + "," + str(value) + "," + str(0) + ')'
+                    value = 255 * e
+                    value2 = 255 - value
+                    string = 'rgb(' + str(value) + "," + str(value2) + "," + str(0) + ')'
                     self.ZB_colors[i] = string
 
+
+
     def handle_xfeat_change(self, change):
         # changes the feature plotted on the x-axis
         # separating line is modified accordingly
@@ -561,11 +584,12 @@ class Visualizer:
     def plotappearance_button_clicked(self, button):
         if self.widg_box_utils.layout.visibility == 'visible':
             self.widg_box_utils.layout.visibility = 'hidden'
-            for i in range(270, -1, -1):
+            for i in range(420, -1, -1):
                 self.widg_box_viewers.layout.top = str(i) + 'px'
+
             self.widg_box_utils.layout.bottom = '0px'
         else:
-            for i in range(271):
+            for i in range(421):
                 self.widg_box_viewers.layout.top = str(i) + 'px'
             self.widg_box_utils.layout.bottom = '400px'
             self.widg_box_utils.layout.visibility = 'visible'
@@ -726,30 +750,26 @@ class Visualizer:
 
         self.widg_box_utils.layout.visibility = 'hidden'
         self.widg_gradient.layout.visibility = 'hidden'
-        box_print = widgets.VBox([self.widg_printdescription,
-                                  widgets.HBox([self.widg_print_button, self.widg_print_out]),
-                                  widgets.HBox([self.widg_plot_name, self.widg_plot_format, self.widg_scale])])
-        box_print.layout.border = 'dashed 1px'
-        box_print.layout.max_width = '750px'
 
-        box_feat = widgets.HBox([widgets.VBox([self.widg_featx, self.widg_featy]),
-                                 widgets.VBox([self.widg_featmarker,
-                                               widgets.HBox([self.widg_featcolor, self.widg_gradient])
-                                               ])
-                                 ])
+        # box_print.layout.border = 'dashed 1px'
+        # self.box_print.layout.max_width = '750px'
+
 
-        box_print.layout.height = '110px'
-        box_feat.layout.height = '110px'
-        box_feat.layout.top = '40px'
-        box_print.layout.top = '30px'
+        # self.box_print.layout.height = '110px'
+        self.box_feat.layout.height = '110px'
+        self.box_feat.layout.top = '30px'
+        # box_print.layout.top = '30px'
         self.widg_plotutils_button.layout.left = '50px'
+        # self.widg_plotutils_button.layout.top='30px'
 
         self.widg_box_utils.layout.border = 'dashed 1px'
         self.widg_box_utils.right = '100px'
         self.widg_box_utils.layout.max_width = '700px'
 
-        container = widgets.VBox([box_print, box_feat, self.fig,
+        container = widgets.VBox([
+                                  self.box_feat, self.fig,
                                   self.widg_plotutils_button,
+
                                   self.widg_box_viewers,
                                   self.widg_box_utils
                                   ])
@@ -780,12 +800,7 @@ class Visualizer:
         )
         self.widg_gradient = widgets.Dropdown(
             description='-gradient',
-            options=['Grey scale',
-                     'Purple scale',
-                     'Turquoise scale',
-                     'Red scale',
-                     'Blue scale',
-                     'Green scale'],
+            options=self.gradient_list,
             value='Grey scale',
             layout=widgets.Layout(width='150px', right='20px')
         )
@@ -921,14 +936,19 @@ class Visualizer:
         )
         self.widg_print_button = widgets.Button(
             description='Print',
-            layout=widgets.Layout(left='90px', width='210px')
+            layout=widgets.Layout(left='50px', width='600px')
         )
         self.widg_print_out = widgets.Output(
-            layout=widgets.Layout(left='90px', width='400px')
+            layout=widgets.Layout(left='150px', width='400px')
         )
         self.widg_printdescription = widgets.Label(
-            value="Click 'Print' to export the plot in the desired format. The resolution of the image can be increased"
-                  " by increasing the 'Scale' value."
+            value="Click 'Print' to export the plot in the desired format.",
+            layout=widgets.Layout(left='50px', width='640px')
+
+        )
+        self.widg_printdescription2 = widgets.Label(
+            value="The resolution of the image can be increased by increasing the 'Scale' value.",
+            layout = widgets.Layout(left='50px', width='640px')
         )
         self.widg_featuredescription = widgets.Label(
             value="The dropdown menus select the features to visualize."
@@ -948,10 +968,6 @@ class Visualizer:
                   "the plot.",
             layout=widgets.Layout(left='50px', width='640px')
         )
-        self.widg_printdescription = widgets.Label(
-            value="Click 'Print' to export the plot in the desired format. The resolution of the image can be increased"
-                  " by increasing the 'Scale' value."
-        )
         self.widg_plotutils_button = widgets.Button(
             description='Toggle on/off the plot appearance utils',
             layout=widgets.Layout(width='600px')
@@ -964,7 +980,10 @@ class Visualizer:
                                             self.widg_colordescription, self.widg_colordescription2,
                                             widgets.HBox([self.widg_rscolor, self.widg_zbcolor, self.widg_bgcolor]),
                                             widgets.HBox([self.widg_bgtoggle_button,self.widg_updatecolor_button,
-                                                          self.widg_reset_button])
+                                                          self.widg_reset_button]),
+                                            self.widg_printdescription, self.widg_printdescription2,
+                                            widgets.HBox([self.widg_plot_name, self.widg_plot_format, self.widg_scale]),
+                                            self.widg_print_button, self.widg_print_out,
                                             ])
 
         file1 = open("./assets/descriptor_role/cross.png", "rb")
@@ -986,6 +1005,12 @@ class Visualizer:
         self.output_l = widgets.Output()
         self.output_r = widgets.Output()
 
+        self.box_feat = widgets.HBox([widgets.VBox([self.widg_featx, self.widg_featy]),
+                                 widgets.VBox([self.widg_featmarker,
+                                               widgets.HBox([self.widg_featcolor, self.widg_gradient])
+                                               ])
+                                 ])
+
         self.widg_box_viewers = widgets.VBox([self.widg_description, widgets.HBox([
             widgets.VBox([
                 widgets.HBox([self.widg_compound_text_l, self.widg_display_button_l,
diff --git a/metainfo.json b/metainfo.json
index 5dd52b4d568e1f23a50c9655ab8d9e44459bd37f..75cf71964fe77b93784e7cb495a010ec816d8a5c 100644
--- a/metainfo.json
+++ b/metainfo.json
@@ -2,7 +2,7 @@
   "authors": [
     "Arif, Mohammad-Yasin",
     "Sbailò, Luigi",
-    "Thomas A. R. Purcell",
+    "Purcell, Thomas A. R.",
     "Ghiringhelli, Luca M.",
     "Scheffler, Matthias"
   ],