diff --git a/exploratory_analysis.ipynb b/exploratory_analysis.ipynb
index be3fc4634c61122daa077f062e519fc0a28c6cf5..051b4c1334d9a29fd0d23c31a06ed0f935f61efe 100644
--- a/exploratory_analysis.ipynb
+++ b/exploratory_analysis.ipynb
@@ -95,6 +95,15 @@
     "We load below the packages required for the tutorial. Most of the clustering and embedding algorithms are contained in the scikit-learn and SciPy packages. We use Panda's dataframe for manipulating our dataset."
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "!pip install plotly"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
@@ -102,23 +111,30 @@
     "ExecuteTime": {
      "end_time": "2022-01-28T12:24:04.045301Z",
      "start_time": "2022-01-28T12:24:03.255791Z"
-    }
+    },
+    "scrolled": true
    },
    "outputs": [],
    "source": [
-    "from ase.io import read\n",
-    "import pandas as pd\n",
     "import numpy as np\n",
-    "from scipy.cluster.hierarchy import dendrogram, linkage, cut_tree\n",
+    "import pandas as pd\n",
+    "\n",
+    "from ase.io import read\n",
+    "\n",
     "from sklearn import preprocessing\n",
     "from sklearn.cluster import KMeans, DBSCAN, AgglomerativeClustering\n",
     "from sklearn.decomposition import PCA\n",
     "from sklearn.manifold import TSNE, MDS\n",
+    "\n",
+    "from scipy.cluster.hierarchy import dendrogram, linkage, cut_tree\n",
+    "\n",
     "import hdbscan\n",
+    "\n",
     "import plotly.graph_objects as go\n",
+    "import matplotlib.pyplot as plt\n",
+    "\n",
     "import ipywidgets as widgets\n",
-    "from IPython.display import display, clear_output\n",
-    "import matplotlib.pyplot as plt"
+    "from IPython.display import display, clear_output"
    ]
   },
   {
@@ -150,44 +166,69 @@
    "outputs": [],
    "source": [
     "# load data\n",
-    "RS_structures = read(\"data/exploratory_analysis/octet_binaries/RS_structures.xyz\", index=':')\n",
-    "ZB_structures = read(\"data/exploratory_analysis/octet_binaries/ZB_structures.xyz\", index=':')\n",
+    "RS_structures = read(\"data/exploratory_analysis/octet_binaries/RS_structures.xyz\", index=\":\")\n",
+    "ZB_structures = read(\"data/exploratory_analysis/octet_binaries/ZB_structures.xyz\", index=\":\")\n",
     "\n",
-    "def generate_table(RS_structures, ZB_structures):\n",
     "\n",
+    "def generate_table(RS_structures, ZB_structures):\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",
+    "        energy_diff = RS.info[\"energy\"] - ZB.info[\"energy\"]\n",
+    "        min_struc_type = \"RS\" if energy_diff < 0 else \"ZB\"\n",
+    "\n",
+    "        yield [\n",
+    "            RS.info[\"energy\"],\n",
+    "            ZB.info[\"energy\"],\n",
+    "            energy_diff,\n",
+    "            min_struc_type,\n",
+    "            RS.info[\"Z\"],\n",
+    "            ZB.info[\"Z\"],\n",
+    "            RS.info[\"period\"],\n",
+    "            ZB.info[\"period\"],\n",
+    "            RS.info[\"IP\"],\n",
+    "            ZB.info[\"IP\"],\n",
+    "            RS.info[\"EA\"],\n",
+    "            ZB.info[\"EA\"],\n",
+    "            RS.info[\"E_HOMO\"],\n",
+    "            ZB.info[\"E_HOMO\"],\n",
+    "            RS.info[\"E_LUMO\"],\n",
+    "            ZB.info[\"E_LUMO\"],\n",
+    "            RS.info[\"r_s\"],\n",
+    "            ZB.info[\"r_s\"],\n",
+    "            RS.info[\"r_p\"],\n",
+    "            ZB.info[\"r_p\"],\n",
+    "            RS.info[\"r_d\"],\n",
+    "            ZB.info[\"r_d\"],\n",
+    "        ]\n",
     "\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)', 'Z(B)',\n",
-    "             'period(A)', 'period(B)',\n",
-    "             'IP(A)', 'IP(B)',\n",
-    "             'EA(A)', 'EA(B)',\n",
-    "             'E_HOMO(A)', 'E_HOMO(B)',\n",
-    "             'E_LUMO(A)', 'E_LUMO(B)',\n",
-    "             'r_s(A)', 'r_s(B)',\n",
-    "             'r_p(A)', 'r_p(B)',\n",
-    "             'r_d(A)', 'r_d(B)',],\n",
-    "    index=list(RS.get_chemical_formula() for RS in RS_structures)\n",
-    ")\n"
+    "    columns=[\n",
+    "        \"energy_RS\",\n",
+    "        \"energy_ZB\",\n",
+    "        \"energy_diff\",\n",
+    "        \"min_struc_type\",\n",
+    "        \"Z(A)\",\n",
+    "        \"Z(B)\",\n",
+    "        \"period(A)\",\n",
+    "        \"period(B)\",\n",
+    "        \"IP(A)\",\n",
+    "        \"IP(B)\",\n",
+    "        \"EA(A)\",\n",
+    "        \"EA(B)\",\n",
+    "        \"E_HOMO(A)\",\n",
+    "        \"E_HOMO(B)\",\n",
+    "        \"E_LUMO(A)\",\n",
+    "        \"E_LUMO(B)\",\n",
+    "        \"r_s(A)\",\n",
+    "        \"r_s(B)\",\n",
+    "        \"r_p(A)\",\n",
+    "        \"r_p(B)\",\n",
+    "        \"r_d(A)\",\n",
+    "        \"r_d(B)\",\n",
+    "    ],\n",
+    "    index=list(RS.get_chemical_formula() for RS in RS_structures),\n",
+    ")"
    ]
   },
   {
@@ -208,7 +249,7 @@
    },
    "outputs": [],
    "source": [
-    "df['marker_symbol']= np.where(df['min_struc_type']=='RS','square-open','hexagram')"
+    "df[\"marker_symbol\"] = np.where(df[\"min_struc_type\"] == \"RS\", \"square-open\", \"hexagram\")"
    ]
   },
   {
@@ -230,8 +271,7 @@
    "outputs": [],
    "source": [
     "class Clustering:\n",
-    "\n",
-    "    def __init__ (self):\n",
+    "    def __init__(self):\n",
     "        self.df_flag = False\n",
     "        try:\n",
     "            df\n",
@@ -239,53 +279,61 @@
     "            print(\"Please define a dataframe 'df' and a features list\")\n",
     "            self.df_flag = True\n",
     "\n",
-    "    def kmeans (self, n_clusters, max_iter):\n",
+    "    def kmeans(self, n_clusters, max_iter):\n",
     "        if self.df_flag:\n",
     "            return\n",
-    "        cluster_labels = KMeans (n_clusters=n_clusters, max_iter=max_iter).fit_predict(df[features])\n",
-    "        print(max(cluster_labels)+1,' clusters were extracted.')\n",
-    "        df['clustering'] = 'k-means'\n",
-    "        df['cluster_label']=cluster_labels\n",
+    "        cluster_labels = KMeans(n_clusters=n_clusters, max_iter=max_iter).fit_predict(\n",
+    "            df[features]\n",
+    "        )\n",
+    "        print(max(cluster_labels) + 1, \" clusters were extracted.\")\n",
+    "        df[\"clustering\"] = \"k-means\"\n",
+    "        df[\"cluster_label\"] = cluster_labels\n",
     "\n",
-    "    def hierarchical (self, distance_threshold):\n",
+    "    def hierarchical(self, distance_threshold):\n",
     "        if self.df_flag:\n",
     "            return\n",
-    "        linkage_criterion = 'ward'\n",
-    "        Z = linkage(df[features], linkage_criterion )\n",
+    "        linkage_criterion = \"ward\"\n",
+    "        Z = linkage(df[features], linkage_criterion)\n",
     "        cluster_labels = cut_tree(Z, height=distance_threshold)\n",
-    "        print(int(max(cluster_labels))+1,' clusters were extracted.')\n",
-    "        df['clustering'] = 'Hierarchical - ' + linkage_criterion + ' criterion'\n",
-    "        df['cluster_label']=cluster_labels\n",
+    "        print(int(max(cluster_labels)) + 1, \" clusters were extracted.\")\n",
+    "        df[\"clustering\"] = \"Hierarchical - \" + linkage_criterion + \" criterion\"\n",
+    "        df[\"cluster_label\"] = cluster_labels\n",
     "\n",
-    "    def dbscan (self, eps, min_samples):\n",
+    "    def dbscan(self, eps, min_samples):\n",
     "        if self.df_flag:\n",
     "            return\n",
-    "        cluster_labels = DBSCAN(eps=eps, min_samples=min_samples).fit_predict(df[features])\n",
-    "        print(max(cluster_labels)+1,' clusters were extracted.')\n",
-    "        df['clustering'] = 'DBSCAN'\n",
-    "        df['cluster_label']=cluster_labels\n",
+    "        cluster_labels = DBSCAN(eps=eps, min_samples=min_samples).fit_predict(\n",
+    "            df[features]\n",
+    "        )\n",
+    "        print(max(cluster_labels) + 1, \" clusters were extracted.\")\n",
+    "        df[\"clustering\"] = \"DBSCAN\"\n",
+    "        df[\"cluster_label\"] = cluster_labels\n",
     "\n",
-    "    def hdbscan (self, min_cluster_size, min_samples):\n",
-    "        clusterer = hdbscan.HDBSCAN(min_cluster_size=min_cluster_size, min_samples=min_samples)\n",
+    "    def hdbscan(self, min_cluster_size, min_samples):\n",
+    "        clusterer = hdbscan.HDBSCAN(\n",
+    "            min_cluster_size=min_cluster_size, min_samples=min_samples\n",
+    "        )\n",
     "        clusterer.fit(df[features])\n",
-    "        cluster_labels=clusterer.labels_\n",
-    "        print(max(cluster_labels)+1,' clusters were extracted.')\n",
-    "        df['clustering']= 'HDBSCAN'\n",
-    "        df['cluster_label']=cluster_labels\n",
+    "        cluster_labels = clusterer.labels_\n",
+    "        print(max(cluster_labels) + 1, \" clusters were extracted.\")\n",
+    "        df[\"clustering\"] = \"HDBSCAN\"\n",
+    "        df[\"cluster_label\"] = cluster_labels\n",
     "\n",
-    "    def dpc (self, density = 0, delta = 0  ):\n",
+    "    def dpc(self, density=0, delta=0):\n",
     "        if self.df_flag:\n",
     "            return\n",
-    "        if density > 0 and delta > 0 :\n",
-    "            clu=DPCClustering(np.ascontiguousarray(df[features].to_numpy()), autoplot=False)\n",
+    "        if density > 0 and delta > 0:\n",
+    "            clu = DPCClustering(\n",
+    "                np.ascontiguousarray(df[features].to_numpy()), autoplot=False\n",
+    "            )\n",
     "            clu.autoplot = True\n",
-    "            clu.assign(density,delta)\n",
+    "            clu.assign(density, delta)\n",
     "            cluster_labels = clu.membership\n",
-    "            print(max(cluster_labels)+1,' clusters were extracted.')\n",
-    "            df['clustering'] = 'DPC'\n",
-    "            df['cluster_label']=cluster_labels\n",
+    "            print(max(cluster_labels) + 1, \" clusters were extracted.\")\n",
+    "            df[\"clustering\"] = \"DPC\"\n",
+    "            df[\"cluster_label\"] = cluster_labels\n",
     "        else:\n",
-    "            clu=DPCClustering(np.ascontiguousarray(df[features].to_numpy()))\n"
+    "            clu = DPCClustering(np.ascontiguousarray(df[features].to_numpy()))"
    ]
   },
   {
@@ -306,87 +354,96 @@
    },
    "outputs": [],
    "source": [
-    "def show_embedding ():\n",
+    "def show_embedding():\n",
+    "    btn_PCA = widgets.Button(description=\"PCA\")\n",
+    "    btn_MDS = widgets.Button(description=\"MDS\")\n",
+    "    btn_tSNE = widgets.Button(description=\"t-SNE\")\n",
     "\n",
-    "    btn_PCA = widgets.Button(description='PCA')\n",
-    "    btn_MDS = widgets.Button(description='MDS')\n",
-    "    btn_tSNE = widgets.Button(description='t-SNE')\n",
-    "\n",
-    "    def btn_eventhandler_embedding (obj):\n",
-    "\n",
-    "        method = str (obj.description)\n",
+    "    def btn_eventhandler_embedding(obj):\n",
+    "        method = str(obj.description)\n",
     "\n",
     "        try:\n",
-    "            df['clustering'][0]\n",
+    "            df[\"clustering\"][0]\n",
     "        except KeyError:\n",
     "            print(\"Please assign labels with a clustering algorithm\")\n",
     "            return\n",
     "\n",
-    "        if (method == 'PCA'):\n",
+    "        if method == \"PCA\":\n",
     "            transformed_data = PCA(n_components=2).fit_transform(df[features])\n",
-    "            df['x_emb']=transformed_data[:,0]\n",
-    "            df['y_emb']=transformed_data[:,1]\n",
-    "            df['embedding'] = 'PCA'\n",
-    "        elif (method == 'MDS'):\n",
-    "            transformed_data = MDS (n_components=2).fit_transform(df[features])\n",
-    "            df['x_emb']=transformed_data[:,0]\n",
-    "            df['y_emb']=transformed_data[:,1]\n",
-    "            df['embedding'] = 'MDS'\n",
-    "        elif (method == 't-SNE'):\n",
-    "            transformed_data = TSNE (n_components=2).fit_transform(df[features])\n",
-    "            df['x_emb']=transformed_data[:,0]\n",
-    "            df['y_emb']=transformed_data[:,1]\n",
-    "            df['embedding'] = 't-SNE'\n",
+    "            df[\"x_emb\"] = transformed_data[:, 0]\n",
+    "            df[\"y_emb\"] = transformed_data[:, 1]\n",
+    "            df[\"embedding\"] = \"PCA\"\n",
+    "        elif method == \"MDS\":\n",
+    "            transformed_data = MDS(n_components=2).fit_transform(df[features])\n",
+    "            df[\"x_emb\"] = transformed_data[:, 0]\n",
+    "            df[\"y_emb\"] = transformed_data[:, 1]\n",
+    "            df[\"embedding\"] = \"MDS\"\n",
+    "        elif method == \"t-SNE\":\n",
+    "            transformed_data = TSNE(n_components=2).fit_transform(df[features])\n",
+    "            df[\"x_emb\"] = transformed_data[:, 0]\n",
+    "            df[\"y_emb\"] = transformed_data[:, 1]\n",
+    "            df[\"embedding\"] = \"t-SNE\"\n",
     "        plot_embedding()\n",
     "\n",
     "    def plot_embedding():\n",
     "        with fig.batch_update():\n",
-    "\n",
-    "            for scatter in fig['data']:\n",
+    "            for scatter in fig[\"data\"]:\n",
     "                cl = scatter.meta\n",
-    "                scatter['x']=df[df['cluster_label']==cl]['x_emb']\n",
-    "                scatter['y']=df[df['cluster_label']==cl]['y_emb']\n",
-    "                scatter['customdata']=np.dstack((df[df['cluster_label']==cl]['min_struc_type'].to_numpy(),\n",
-    "                                                 df[df['cluster_label']==cl]['cluster_label'].to_numpy(),\n",
-    "                                                ))[0]\n",
-    "                scatter['hovertemplate']=r\"<b>%{text}</b><br><br> Low energy structure:  %{customdata[0]}<br>Cluster label:  %{customdata[1]}<br>\"\n",
-    "                scatter['marker'].symbol=df[df['cluster_label']==cl]['marker_symbol'].to_numpy()\n",
-    "                scatter['text']=df[df['cluster_label']==cl].index.to_list()\n",
+    "                scatter[\"x\"] = df[df[\"cluster_label\"] == cl][\"x_emb\"]\n",
+    "                scatter[\"y\"] = df[df[\"cluster_label\"] == cl][\"y_emb\"]\n",
+    "                scatter[\"customdata\"] = np.dstack(\n",
+    "                    (\n",
+    "                        df[df[\"cluster_label\"] == cl][\"min_struc_type\"].to_numpy(),\n",
+    "                        df[df[\"cluster_label\"] == cl][\"cluster_label\"].to_numpy(),\n",
+    "                    )\n",
+    "                )[0]\n",
+    "                scatter[\"hovertemplate\"] = (\n",
+    "                    r\"<b>%{text}</b><br><br> Low energy structure:  %{customdata[0]}<br>Cluster label:  %{customdata[1]}<br>\"\n",
+    "                )\n",
+    "                scatter[\"marker\"].symbol = df[df[\"cluster_label\"] == cl][\n",
+    "                    \"marker_symbol\"\n",
+    "                ].to_numpy()\n",
+    "                scatter[\"text\"] = df[df[\"cluster_label\"] == cl].index.to_list()\n",
     "\n",
     "            fig.update_layout(\n",
-    "                plot_bgcolor='rgba(229,236,246, 0.5)',\n",
+    "                plot_bgcolor=\"rgba(229,236,246, 0.5)\",\n",
     "                xaxis=dict(visible=True),\n",
     "                yaxis=dict(visible=True),\n",
-    "                legend_title_text='List of clusters',\n",
-    "                showlegend=True,)\n",
-    "        label_b.value =  \"Embedding method used: \" + str(df['embedding'][0])\n",
+    "                legend_title_text=\"List of clusters\",\n",
+    "                showlegend=True,\n",
+    "            )\n",
+    "        label_b.value = \"Embedding method used: \" + str(df[\"embedding\"][0])\n",
     "\n",
     "    btn_PCA.on_click(btn_eventhandler_embedding)\n",
     "    btn_MDS.on_click(btn_eventhandler_embedding)\n",
     "    btn_tSNE.on_click(btn_eventhandler_embedding)\n",
-    "    label_t = widgets.Label(value=\"Clustering algorithm used: \" + str(df['clustering'][0]))\n",
-    "    label_b = widgets.Label(value='Select a dimension reduction method to visualize the 2-dimensional embedding')\n",
+    "    label_t = widgets.Label(\n",
+    "        value=\"Clustering algorithm used: \" + str(df[\"clustering\"][0])\n",
+    "    )\n",
+    "    label_b = widgets.Label(\n",
+    "        value=\"Select a dimension reduction method to visualize the 2-dimensional embedding\"\n",
+    "    )\n",
     "\n",
     "    fig = go.FigureWidget()\n",
     "\n",
-    "    for cl in np.unique(df['cluster_label'].to_numpy()):\n",
+    "    for cl in np.unique(df[\"cluster_label\"].to_numpy()):\n",
     "        if cl == -1:\n",
-    "            name = 'Outliers'\n",
+    "            name = \"Outliers\"\n",
     "        else:\n",
-    "            name = 'Cluster ' + str(cl)\n",
-    "        fig.add_trace(go.Scatter(\n",
-    "            name=name,\n",
-    "            mode='markers',\n",
-    "            meta=cl\n",
-    "        ))\n",
+    "            name = \"Cluster \" + str(cl)\n",
+    "        fig.add_trace(go.Scatter(name=name, mode=\"markers\", meta=cl))\n",
     "\n",
-    "    fig.update_layout(plot_bgcolor='rgba(229,236,246, 0.5)',\n",
-    "                      width=800,\n",
-    "                      height=600,\n",
-    "                      xaxis=dict(visible=False, title='x_emb'),\n",
-    "                      yaxis=dict(visible=False, title='y_emb'))\n",
+    "    fig.update_layout(\n",
+    "        plot_bgcolor=\"rgba(229,236,246, 0.5)\",\n",
+    "        width=800,\n",
+    "        height=600,\n",
+    "        xaxis=dict(visible=False, title=\"x_emb\"),\n",
+    "        yaxis=dict(visible=False, title=\"y_emb\"),\n",
+    "    )\n",
     "\n",
-    "    return widgets.VBox([widgets.HBox ([btn_PCA,btn_MDS,btn_tSNE]),label_t, label_b, fig])"
+    "    return widgets.VBox(\n",
+    "        [widgets.HBox([btn_PCA, btn_MDS, btn_tSNE]), label_t, label_b, fig]\n",
+    "    )"
    ]
   },
   {
@@ -408,22 +465,22 @@
    "outputs": [],
    "source": [
     "features = []\n",
-    "features.append('IP(A)')\n",
-    "features.append('IP(B)')\n",
-    "features.append('EA(A)')\n",
-    "features.append('EA(B)')\n",
-    "features.append('Z(A)')\n",
-    "features.append('Z(B)')\n",
-    "features.append('E_HOMO(A)')\n",
-    "features.append('E_HOMO(B)')\n",
-    "features.append('E_LUMO(A)')\n",
-    "features.append('E_LUMO(B)')\n",
-    "features.append('r_s(A)')\n",
-    "features.append('r_s(B)')\n",
-    "features.append('r_p(A)')\n",
-    "features.append('r_p(B)')\n",
-    "features.append('r_d(A)')\n",
-    "features.append('r_d(B)')"
+    "features.append(\"IP(A)\")\n",
+    "features.append(\"IP(B)\")\n",
+    "features.append(\"EA(A)\")\n",
+    "features.append(\"EA(B)\")\n",
+    "features.append(\"Z(A)\")\n",
+    "features.append(\"Z(B)\")\n",
+    "features.append(\"E_HOMO(A)\")\n",
+    "features.append(\"E_HOMO(B)\")\n",
+    "features.append(\"E_LUMO(A)\")\n",
+    "features.append(\"E_LUMO(B)\")\n",
+    "features.append(\"r_s(A)\")\n",
+    "features.append(\"r_s(B)\")\n",
+    "features.append(\"r_p(A)\")\n",
+    "features.append(\"r_p(B)\")\n",
+    "features.append(\"r_d(A)\")\n",
+    "features.append(\"r_d(B)\")"
    ]
   },
   {
@@ -445,7 +502,7 @@
    },
    "outputs": [],
    "source": [
-    "df[features]=preprocessing.scale(df[features])"
+    "df[features] = preprocessing.scale(df[features])"
    ]
   },
   {
@@ -467,7 +524,7 @@
    },
    "outputs": [],
    "source": [
-    "hist = df[features].hist( bins=10, figsize = (20,15));"
+    "hist = df[features].hist(bins=10, figsize=(20, 15));"
    ]
   },
   {
@@ -505,7 +562,7 @@
    "outputs": [],
    "source": [
     "n_clusters = 2\n",
-    "max_iter =100\n",
+    "max_iter = 100\n",
     "Clustering().kmeans(n_clusters, max_iter)"
    ]
   },
@@ -520,7 +577,7 @@
    },
    "outputs": [],
    "source": [
-    "print(df['cluster_label'][:10])"
+    "print(df[\"cluster_label\"][:10])"
    ]
   },
   {
@@ -576,18 +633,28 @@
    },
    "outputs": [],
    "source": [
-    "def composition_RS_ZB (df):\n",
-    "    df_cm = pd.DataFrame (columns=['RS','ZB','Materials in cluster'], dtype=object)\n",
+    "def composition_RS_ZB(df):\n",
+    "    df_cm = pd.DataFrame(columns=[\"RS\", \"ZB\", \"Materials in cluster\"], dtype=object)\n",
     "\n",
-    "    n_clusters = df['cluster_label'].max() + 1\n",
+    "    n_clusters = df[\"cluster_label\"].max() + 1\n",
     "\n",
-    "    for i in range (n_clusters):\n",
-    "        Tot = len(df.loc[df['cluster_label']==i])\n",
-    "        if (Tot == 0):\n",
+    "    for i in range(n_clusters):\n",
+    "        Tot = len(df.loc[df[\"cluster_label\"] == i])\n",
+    "        if Tot == 0:\n",
     "            continue\n",
-    "        RS = int(100*len(df.loc[(df['cluster_label']==i) & (df['min_struc_type']=='RS')])/len(df.loc[df['cluster_label']==i]))\n",
-    "        ZB = int(100*len(df.loc[(df['cluster_label']==i) & (df['min_struc_type']=='ZB')])/len(df.loc[df['cluster_label']==i]))\n",
-    "        df_cm = df_cm.append({'RS':RS, 'ZB':ZB, \"Materials in cluster\":Tot},ignore_index=True)\n",
+    "        RS = int(\n",
+    "            100\n",
+    "            * len(df.loc[(df[\"cluster_label\"] == i) & (df[\"min_struc_type\"] == \"RS\")])\n",
+    "            / len(df.loc[df[\"cluster_label\"] == i])\n",
+    "        )\n",
+    "        ZB = int(\n",
+    "            100\n",
+    "            * len(df.loc[(df[\"cluster_label\"] == i) & (df[\"min_struc_type\"] == \"ZB\")])\n",
+    "            / len(df.loc[df[\"cluster_label\"] == i])\n",
+    "        )\n",
+    "        df_cm = df_cm.append(\n",
+    "            {\"RS\": RS, \"ZB\": ZB, \"Materials in cluster\": Tot}, ignore_index=True\n",
+    "        )\n",
     "\n",
     "    return df_cm"
    ]
@@ -644,7 +711,7 @@
    },
    "outputs": [],
    "source": [
-    "distance_threshold=20\n",
+    "distance_threshold = 20\n",
     "Clustering().hierarchical(distance_threshold=distance_threshold)"
    ]
   },
@@ -698,8 +765,8 @@
    },
    "outputs": [],
    "source": [
-    "Z = linkage(df[features], 'ward' )\n",
-    "dendrogram(Z, truncate_mode='lastp',p=11);"
+    "Z = linkage(df[features], \"ward\")\n",
+    "dendrogram(Z, truncate_mode=\"lastp\", p=11);"
    ]
   },
   {
@@ -738,8 +805,8 @@
    "outputs": [],
    "source": [
     "eps = 3\n",
-    "min_samples= 8\n",
-    "Clustering().dbscan(eps,min_samples)"
+    "min_samples = 8\n",
+    "Clustering().dbscan(eps, min_samples)"
    ]
   },
   {
@@ -951,7 +1018,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "Clustering().dpc(2.4,3.8)"
+    "Clustering().dpc(2.4, 3.8)"
    ]
   },
   {
@@ -1000,7 +1067,7 @@
  ],
  "metadata": {
   "kernelspec": {
-   "display_name": "Python 3",
+   "display_name": "Python 3 (ipykernel)",
    "language": "python",
    "name": "python3"
   },
@@ -1014,7 +1081,7 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.7.3"
+   "version": "3.9.13"
   }
  },
  "nbformat": 4,
diff --git a/requirements.in b/requirements.in
index d8773816104d711df5ab42fc8a6694564f0c3b9e..370619699dfe3db4783b55beba8c9465aa533ed3 100644
--- a/requirements.in
+++ b/requirements.in
@@ -1,6 +1,7 @@
 numpy
 pandas
 matplotlib
+plotly
 scikit-learn
 hdbscan
 ase