{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# default_exp visualization.basic_plots"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Visualizations Basic Plots\n",
    "> Common utilities for visualizing/plotting recsys data and patterns."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#hide\n",
    "from nbdev.showdoc import *"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "import matplotlib.pyplot as plt\n",
    "import seaborn as sns\n",
    "\n",
    "import pandas as pd\n",
    "import numpy as np"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "class Visual:\n",
    "    def __init__(self):\n",
    "        pass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "class BasicVisual(Visual):\n",
    "    def __init__(self, figsize=(10,10), show=True, save=False, pallete='viridis',\n",
    "                 style='whitegrid', rot=45, label_x='label_x', label_y='label_y',\n",
    "                 title='Basic Plot', nrows=1, ncols=1):\n",
    "        super(BasicVisual, self).__init__()\n",
    "        self.nrows = nrows\n",
    "        self.ncols = ncols\n",
    "        self.figsize = figsize\n",
    "        self.show = show\n",
    "        self.pallete = pallete\n",
    "        self.style = style\n",
    "        self.rot = rot\n",
    "        self.label_x = label_x\n",
    "        self.label_y = label_y\n",
    "        self.title = title\n",
    "\n",
    "        self._plot()\n",
    "\n",
    "    def plot(self):\n",
    "        raise NotImplementedError\n",
    "\n",
    "    def _plot(self):\n",
    "        self.fig, self.ax = plt.subplots(nrows=self.nrows, ncols=self.ncols,\n",
    "                                         figsize=self.figsize)\n",
    "        sns.set_palette(self.pallete)\n",
    "        sns.set_style(self.style)\n",
    "        plt.xticks(rotation=self.rot)\n",
    "        plt.xlabel(self.label_x)\n",
    "        plt.ylabel(self.label_y)\n",
    "        plt.title(self.title)\n",
    "\n",
    "        self.plot()\n",
    "\n",
    "        plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "class CountPlot(BasicVisual):\n",
    "    def __init__(self, data_x, data_y, add_pct=True, **kwargs):\n",
    "        self.data_x = data_x\n",
    "        self.data_y = data_y\n",
    "        self.add_pct = add_pct\n",
    "        super(CountPlot, self).__init__(**kwargs)\n",
    "\n",
    "    def plot(self):\n",
    "        sns.barplot(x=self.data_x, y=self.data_y, ax=self.ax)\n",
    "        if self.add_pct:\n",
    "            self.pct_patch()\n",
    "\n",
    "    def pct_patch(self):\n",
    "        tot_pct = 0\n",
    "        total = np.sum(self.data_y)\n",
    "        for p in self.ax.patches:\n",
    "            height = p.get_height()\n",
    "            self.ax.text(p.get_x()+p.get_width()/2.,\n",
    "                    height + 1,\n",
    "                    '{:1.2f}%'.format(height*100/total),\n",
    "                    ha=\"center\")\n",
    "            tot_pct+= height*100/total"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 14908 characters]\n",
      "text/plain": [
       "<Figure size 504x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "df = pd.DataFrame.from_dict({\n",
    "    'genres':['Drama','Comedy'],\n",
    "    'count':[40,20],\n",
    "})\n",
    "\n",
    "kwargs = {'label_x':'genres', 'label_y':'count of genre', 'figsize':(7,4)}\n",
    "\n",
    "cp = CountPlot(data_x = df.genres.values,\n",
    "               data_y = df['count'].values,\n",
    "               **kwargs)\n",
    "\n",
    "cp.plot()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "class LongTailPlot(BasicVisual):\n",
    "    def __init__(self, item_ids, user_ids, **kwargs):\n",
    "        kwargs['nrows'] = 1\n",
    "        kwargs['ncols'] = 2\n",
    "        self.df = pd.DataFrame.from_dict({\n",
    "            'user_id':user_ids,\n",
    "            'item_id':item_ids,\n",
    "        })\n",
    "        super(LongTailPlot, self).__init__(**kwargs)\n",
    "\n",
    "    def plot(self):\n",
    "        item_rate_count = self.df.groupby(\"item_id\")[\"user_id\"].nunique().sort_values(ascending=False)\n",
    "        self.ax[0].bar(x=item_rate_count.index, height=item_rate_count.values, width=1.0, align=\"edge\")\n",
    "        self.ax[0].set_xticks([])\n",
    "        self.ax[0].set(title=\"long tail of rating frequency\", \n",
    "                    xlabel=\"item ordered by decreasing frequency\", \n",
    "                    ylabel=\"#ratings\")\n",
    "\n",
    "        count = item_rate_count.value_counts()\n",
    "        sns.scatterplot(x=np.log(count.index), y=np.log(count.values), ax=self.ax[1])\n",
    "        self.ax[1].set(title=\"log-log plot\", xlabel=\"#ratings (log scale)\", ylabel=\"#items (log scale)\")  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 28820 characters]\n",
      "text/plain": [
       "<Figure size 1008x360 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "<__main__.LongTailPlot at 0x7f20c9976f10>"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df = pd.DataFrame.from_dict({\n",
    "    'item_id':[1,1,2,2,2,2,3,4,4],\n",
    "    'user_id':[1,2,2,2,3,3,4,4,4],\n",
    "})\n",
    "\n",
    "kwargs = {'figsize':(14,5)}\n",
    "\n",
    "LongTailPlot(item_ids=df.item_id.values, user_ids=df.user_id.values, **kwargs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "class LongTailPlotv2(BasicVisual):\n",
    "    def __init__(self, item_ids, percentage=None, x_labels=True, **kwargs):\n",
    "        \"\"\"\n",
    "        Plots the long tail for a user-item interaction dataset.\n",
    "        ----------\n",
    "        item_ids: \n",
    "            list of item ids\n",
    "        percentage: float, default=None\n",
    "            percent of volume to consider as the head (percent as a decimal)\n",
    "            (if default=None no line will be plotted)\n",
    "        x_tables bool, default=True\n",
    "            if True, plot x-axis tick labels\n",
    "            if False, no x-axis tick labels will be plotted.\n",
    "        Returns:\n",
    "        -------\n",
    "            A long tail plot\n",
    "        \"\"\"\n",
    "        self.df = pd.DataFrame.from_dict({\n",
    "            'item_id':item_ids,\n",
    "        })\n",
    "        self.percentage = percentage\n",
    "        self.x_labels = x_labels\n",
    "        super(LongTailPlotv2, self).__init__(**kwargs)\n",
    "\n",
    "    def plot(self):\n",
    "        from matplotlib.lines import Line2D\n",
    "\n",
    "        #calculate cumulative volumes\n",
    "        volume_df = self.df['item_id'].value_counts().reset_index()\n",
    "        volume_df.columns = ['item_id', \"volume\"]\n",
    "        volume_df['item_id'] = volume_df['item_id'].astype(str)\n",
    "        volume_df['cumulative_volume'] = volume_df['volume'].cumsum()\n",
    "        volume_df['percent_of_total_volume'] = volume_df['cumulative_volume']/volume_df['volume'].sum()\n",
    "\n",
    "        #line plot of cumulative volume\n",
    "        x = range(0,len(volume_df))\n",
    "        sns.lineplot(x=x, y=volume_df[\"volume\"].values, color=\"black\", ax=self.ax)\n",
    "        plt.xticks(x)\n",
    "\n",
    "        #set labels\n",
    "        if self.percentage != None:\n",
    "            #plot vertical line at the tail location\n",
    "            head = volume_df[volume_df[\"percent_of_total_volume\"] <= self.percentage]\n",
    "            tail = volume_df[volume_df[\"percent_of_total_volume\"] > self.percentage]\n",
    "            items_in_head = len(head)\n",
    "            items_in_tail = len(tail)\n",
    "            plt.axvline(x=items_in_head, color=\"red\",  linestyle='--')\n",
    "\n",
    "            # fill area under plot\n",
    "            head = head.append(tail.head(1))\n",
    "            x1 = head.index.values\n",
    "            y1 = head['volume']\n",
    "            x2 = tail.index.values\n",
    "            y2 = tail['volume']\n",
    "            self.ax.fill_between(x1, y1, color=\"blue\", alpha=0.2)\n",
    "            self.ax.fill_between(x2, y2,  color=\"orange\", alpha=0.2)\n",
    "\n",
    "            #create legend\n",
    "            legend_elements = [Line2D([0], [0], marker='o', color='w', label=str(items_in_head)+': items in the head', markerfacecolor='blue', markersize=5),\n",
    "                            Line2D([0], [0], marker='o', color='w', label=str(items_in_tail)+': items in the tail', markerfacecolor='orange', markersize=5)]\n",
    "            self.ax.legend(handles=legend_elements, loc=1)\n",
    "\n",
    "        else:\n",
    "            x1 = volume_df['item_id']\n",
    "            y1 = volume_df['volume']\n",
    "            self.ax.fill_between(x1, y1, color=\"blue\", alpha=0.3)\n",
    "        if self.x_labels == False:\n",
    "            plt.xticks([], [])\n",
    "            self.ax.set(xticklabels=[])\n",
    "        else:\n",
    "            self.ax.set_xticklabels(labels = volume_df['item_id'], rotation = 45, ha=\"right\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 25060 characters]\n",
      "text/plain": [
       "<Figure size 648x360 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "<__main__.LongTailPlotv2 at 0x7f20bdbcb710>"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "item_ids = [1,1,2,2,2,2,3,4,4]\n",
    "\n",
    "kwargs = {'figsize':(9,5)}\n",
    "\n",
    "LongTailPlotv2(item_ids=df.item_id.values, percentage=0.5, **kwargs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "class MatrixPlot(BasicVisual):\n",
    "    def __init__(self, rating_matrix, interpolation=None, vmax=1, vmin=0, **kwargs):\n",
    "        self.rating_matrix = rating_matrix\n",
    "        self.interpolation=interpolation\n",
    "        self.vmax=vmax\n",
    "        self.vmin=vmin\n",
    "        super(MatrixPlot, self).__init__(**kwargs)\n",
    "\n",
    "    def plot(self):\n",
    "        plt.imshow(self.rating_matrix, interpolation=self.interpolation,\n",
    "                   vmax=self.vmax, vmin=self.vmin)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 566444 characters]\n",
      "text/plain": [
       "<Figure size 720x720 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "<__main__.MatrixPlot at 0x7f20c7c594d0>"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rating_matrix = np.vstack((np.random.randint(0,1, size=(1000,1000)),\n",
    "                             np.random.randint(0,5, size=(500,1000))))\n",
    "rating_matrix_binary = rating_matrix > 0\n",
    "np.random.shuffle(rating_matrix_binary)\n",
    "MatrixPlot(rating_matrix_binary)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "class ConfusionMatrix(BasicVisual):\n",
    "    def __init__(self, y, yhat, **kwargs):\n",
    "        self.y = y\n",
    "        self.yhat = yhat\n",
    "        super(ConfusionMatrix, self).__init__(**kwargs)\n",
    "\n",
    "    def plot(self):\n",
    "        from itertools import product\n",
    "        from sklearn.metrics import confusion_matrix\n",
    "\n",
    "        cm = confusion_matrix(self.y, self.yhat, labels=[1,0])\n",
    "        cm = np.round(cm.astype('float') / cm.sum(axis=1)[:, np.newaxis],4)*100\n",
    "\n",
    "        fmt = \".2f\"\n",
    "        _ = cm.max() / 2. # TODO: Unused argument\n",
    "        descriptions = np.array([[\"True Positive\", \"False Negative\"], [\"False Positive\", \"True Negatives\"]])\n",
    "        colors = np.array([[\"green\", \"red\"], [\"red\", \"green\"]])\n",
    "        plt.imshow([[0,0],[0,0]], interpolation='nearest', cmap=plt.cm.Greys)\n",
    "        for i, j in product(range(cm.shape[0]), range(cm.shape[1])):\n",
    "                plt.text(j, i, format(cm[i, j], fmt)+'%\\n' + descriptions[i, j],\n",
    "                        horizontalalignment=\"center\",\n",
    "                        color=colors[i,j])\n",
    "        plt.axhline(y=0.5, xmin=0, xmax=1, color=\"black\", linewidth=0.75)\n",
    "        plt.axvline(x=0.5, ymin=0, ymax=1, color=\"black\", linewidth=0.75)\n",
    "        plt.ylabel('True')\n",
    "        plt.xlabel('Predicted')\n",
    "        plt.title(\"Confusion Matrix\")\n",
    "        plt.xticks([0,1], [1,0], rotation=45)\n",
    "        plt.yticks([0,1], [1,0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 15368 characters]\n",
      "text/plain": [
       "<Figure size 360x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "<__main__.ConfusionMatrix at 0x7f20c659e1d0>"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "kwargs = {'figsize':(5,4)}\n",
    "\n",
    "ConfusionMatrix(y=[1,0,0,1,1], yhat=[1,1,0,0,1], **kwargs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "class EmbeddingPlot(BasicVisual):\n",
    "    def __init__(self, vectors, labels=None, **kwargs):\n",
    "        self.vectors = vectors\n",
    "        self.labels = labels\n",
    "        kwargs['figsize'] = (12, len(vectors))\n",
    "        super(EmbeddingPlot, self).__init__(**kwargs)\n",
    "\n",
    "    def plot(self):\n",
    "        sns.heatmap(self.vectors, vmax=2, vmin=-2, ax=self.ax, cmap=self.pallete)\n",
    "        if self.labels:\n",
    "            self.ax.set_yticklabels(self.labels, rotation=self.rot)\n",
    "            self.ax.tick_params(axis='both', which='major', labelsize=30)\n",
    "        plt.tick_params(axis='x',          # changes apply to the x-axis\n",
    "                        which='both',      # both major and minor ticks are affected\n",
    "                        bottom=False,      # ticks along the bottom edge are off\n",
    "                        top=False,         # ticks along the top edge are off\n",
    "                        labelbottom=False) # labels along the bottom edge are off\n",
    "        # From https://github.com/mwaskom/seaborn/issues/1773\n",
    "        # fix for mpl bug that cuts off top/bottom of seaborn viz\n",
    "        b, t = plt.ylim() # discover the values for bottom and top\n",
    "        b += 0.5 # Add 0.5 to the bottom\n",
    "        t -= 0.5 # Subtract 0.5 from the top\n",
    "        plt.ylim(b, t) # update the ylim(bottom, top) values"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 22352 characters]\n",
      "text/plain": [
       "<Figure size 864x360 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "<__main__.EmbeddingPlot at 0x7f717d962b90>"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "kwargs = {'rot':0, 'pallete':'RdBu'}\n",
    "EmbeddingPlot(vectors=np.random.randint(-1, 3, size=(5,100)), labels=['king', 'water', 'god', 'love', 'star'], **kwargs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "class ClusterPlot(BasicVisual):\n",
    "    def __init__(self, labels, embedding_clusters, word_clusters, **kwargs):\n",
    "        self.labels = labels\n",
    "        self.embedding_clusters = embedding_clusters\n",
    "        self.word_clusters = word_clusters\n",
    "        super(ClusterPlot, self).__init__(**kwargs)\n",
    "\n",
    "    def plot(self):\n",
    "        for label, embeddings, words in zip(self.labels, self.embedding_clusters, self.word_clusters):\n",
    "            x = embeddings[:,0]\n",
    "            y = embeddings[:,1]\n",
    "            plt.scatter(x, y, label=label)\n",
    "            for i, word in enumerate(words):\n",
    "                plt.annotate(word, alpha=0.5, xy=(x[i], y[i]), xytext=(5, 2), \n",
    "                            textcoords='offset points', ha='right', va='bottom', size=8)\n",
    "        plt.legend(loc=4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 26212 characters]\n",
      "text/plain": [
       "<Figure size 720x720 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "<__main__.ClusterPlot at 0x7f717ca4bc90>"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "embedding_clusters = np.vstack((np.random.random(size=(1,5,5))*2,\n",
    "                                np.random.random(size=(1,5,5))*-2))\n",
    "word_clusters = [['apple', 'banana', 'mango', 'pineapple', 'orange'], ['red', 'green', 'orange', 'magenta', 'cyan']]\n",
    "labels = ['fruits', 'animals']\n",
    "\n",
    "ClusterPlot(labels, embedding_clusters, word_clusters)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "class TimelinePlot(BasicVisual):\n",
    "    def __init__(self, data, xticks_type='Month', xticks_interval=3, **kwargs):\n",
    "        self.combined_data = data\n",
    "        self.xticks_type = xticks_type\n",
    "        self.xticks_interval = xticks_interval\n",
    "        super(TimelinePlot, self).__init__(**kwargs)\n",
    "\n",
    "    def plot(self):\n",
    "        from datetime import datetime\n",
    "        import matplotlib.dates as mdates\n",
    "        import matplotlib.patches as mpatches\n",
    "\n",
    "        # Group data by date\n",
    "        if self.xticks_type=='Day':\n",
    "            self.combined_data['date'] = self.combined_data['date'].dt.strftime('%Y-%m-%d')\n",
    "            self.combined_data['date'] = self.combined_data['date'].apply(lambda x: datetime.strptime(x, \"%Y-%m-%d\"))\n",
    "        else:\n",
    "            self.combined_data['date'] = self.combined_data['date'].dt.strftime('%B %Y')\n",
    "            self.combined_data['date'] = self.combined_data['date'].apply(lambda x: datetime.strptime(x, \"%B %Y\"))     \n",
    "        \n",
    "        self.combined_data = self.combined_data.groupby(['type', 'date', 'color']).size().rename('count').reset_index().sort_values('date')\n",
    "        self.combined_data['name'] = self.combined_data['count'].map(str)+ ' '+self.combined_data['type']\n",
    "        names = self.combined_data['name'].tolist()\n",
    "        colors = self.combined_data['color'].tolist()\n",
    "        dates = self.combined_data['date'].tolist()\n",
    "\n",
    "        # Plot\n",
    "        levels = np.array([-9, 9, -7, 7, -5, 5, -3, 3, -1, 1])\n",
    "\n",
    "        # Create the base line\n",
    "        start = min(dates)\n",
    "        stop = max(dates)\n",
    "        self.ax.plot((start, stop), (0, 0), 'k', alpha=.5)\n",
    "\n",
    "        # Create annotations\n",
    "        for ii, (iname, idate, icol) in enumerate(zip(names, dates, colors)):\n",
    "            level = levels[ii % len(levels)]\n",
    "            vert = 'top' if level < 0 else 'bottom'\n",
    "            self.ax.scatter(idate, 0, s=100, facecolor=icol, edgecolor='k', zorder=9999)\n",
    "            self.ax.plot((idate, idate), (0, level), c=icol, alpha=1.0, lw=2)\n",
    "            self.ax.text(idate, level, iname, horizontalalignment='center', verticalalignment=vert, fontsize=12, backgroundcolor=icol)\n",
    "        # Set the xticks formatting\n",
    "        if self.xticks_type=='Month':\n",
    "            self.ax.get_xaxis().set_major_locator(mdates.MonthLocator(interval=self.xticks_interval))\n",
    "            self.ax.get_xaxis().set_major_formatter(mdates.DateFormatter(\"%B %Y\"))\n",
    "        elif self.xticks_type=='Day':\n",
    "            self.ax.get_xaxis().set_major_locator(mdates.DayLocator(interval=self.xticks_interval))\n",
    "            self.ax.get_xaxis().set_major_formatter(mdates.DateFormatter(\"%Y-%m-%d\"))\n",
    "        elif self.xticks_type=='Year':\n",
    "            self.ax.get_xaxis().set_major_locator(mdates.YearLocator())\n",
    "            self.ax.get_xaxis().set_major_formatter(mdates.DateFormatter(\"%Y\"))        \n",
    "        self.fig.autofmt_xdate()\n",
    "        #Legend\n",
    "        legend = []\n",
    "        for index, row in self.combined_data[['type', 'color']].drop_duplicates().iterrows():\n",
    "            legend += [mpatches.Patch(color=row['color'], label=row['type'])]\n",
    "        plt.legend(handles=legend, loc='center left', bbox_to_anchor=(1, 0.5))\n",
    "        \n",
    "        # Remove components for a cleaner look\n",
    "        plt.setp((self.ax.get_yticklabels() + self.ax.get_yticklines() + list(self.ax.spines.values())), visible=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 26984 characters]\n",
      "text/plain": [
       "<Figure size 864x360 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "<__main__.TimelinePlot at 0x7f717b03ca90>"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# likes\n",
    "likes_data = pd.DataFrame({'type':'Like', \n",
    "                        'date':['Jun 2016', 'Jun 2016', 'Sept 2016'],\n",
    "                        'color':'green'})\n",
    "likes_data['date'] = pd.to_datetime(likes_data['date'])\n",
    "\n",
    "# professional registration\n",
    "comments_data = pd.DataFrame({'type':'Comment', \n",
    "                        'date':['Jul 2016', 'Aug 2016', 'Sept 2016', 'Sept 2016'],\n",
    "                        'color':'blue'})\n",
    "comments_data['date'] = pd.to_datetime(comments_data['date'])\n",
    "\n",
    "combined_data = pd.concat([likes_data, comments_data])\n",
    "\n",
    "kwargs = {'figsize':(12,5)}\n",
    "\n",
    "TimelinePlot(combined_data, xticks_type='Day', xticks_interval=7, **kwargs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "class ImageGridPlot(BasicVisual):\n",
    "    def __init__(self, paths, labels, columns=5, **kwargs):\n",
    "        self.paths = paths\n",
    "        self.labels = labels\n",
    "        self.columns = columns\n",
    "        kwargs['figsize'] = (15,int(0.625 * len(paths)))\n",
    "        # kwargs['nrows'] = len(paths) / columns + 1\n",
    "        # kwargs['ncols'] = (15,int(0.625 * len(paths)))\n",
    "        super(ImageGridPlot, self).__init__(**kwargs)\n",
    "\n",
    "    def plot(self):\n",
    "        from skimage import io\n",
    "\n",
    "        for i, path in enumerate(self.paths):\n",
    "            plt.subplot(len(self.paths) / self.columns + 1, self.columns, i + 1)\n",
    "            image = io.imread(path)\n",
    "            plt.imshow(image)\n",
    "            plt.xticks(color = 'w', fontsize = 0.1)\n",
    "            plt.yticks(color = 'w', fontsize = 0.1)\n",
    "            plt.xlabel(self.labels[i], fontsize = 12)\n",
    "            plt.tight_layout(h_pad=0.4, w_pad=0)\n",
    "            plt.subplots_adjust(wspace=None, hspace=None)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "cat1.png            100%[===================>]   4.93K  --.-KB/s    in 0s      \n",
      "cat2.png            100%[===================>]   5.87K  --.-KB/s    in 0s      \n"
     ]
    }
   ],
   "source": [
    "!wget -q --show-progress -O cat1.png \"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcT7nrOEKnuu0ek-bvr3MOq5JqL6-bm6-0-DyA&usqp=CAU\"\n",
    "!wget -q --show-progress -O cat2.png \"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTvTSWBQeuHSGP2wLQTNsPOTHp0ok7CVQ2bGQ&usqp=CAU\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 330672 characters]\n",
      "text/plain": [
       "<Figure size 1080x504 with 12 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "<__main__.ImageGridPlot at 0x7f7177949a90>"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df = pd.DataFrame.from_dict({\n",
    "    'Path':['cat1.png', 'cat2.png'],\n",
    "    'Label':['A','B']\n",
    "})\n",
    "\n",
    "df = df.append([df]*5,ignore_index=True)\n",
    "\n",
    "ImageGridPlot(paths=df.Path.values,\n",
    "              labels=df.Label.values)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Author: Sparsh A.\n",
      "\n",
      "Last updated: 2021-12-26 19:04:15\n",
      "\n",
      "recohut: 0.0.7\n",
      "\n",
      "Compiler    : GCC 7.5.0\n",
      "OS          : Linux\n",
      "Release     : 5.4.144+\n",
      "Machine     : x86_64\n",
      "Processor   : x86_64\n",
      "CPU cores   : 2\n",
      "Architecture: 64bit\n",
      "\n",
      "skimage   : 0.18.3\n",
      "pandas    : 1.1.5\n",
      "IPython   : 5.5.0\n",
      "seaborn   : 0.11.2\n",
      "matplotlib: 3.2.2\n",
      "numpy     : 1.19.5\n",
      "\n"
     ]
    }
   ],
   "source": [
    "#hide\n",
    "%reload_ext watermark\n",
    "%watermark -a \"Sparsh A.\" -m -iv -u -t -d -p recohut"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "name": "python3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
