{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Visualization\n",
    "PySwarms implements tools for visualizing the behavior of your swarm. These are built on top of `matplotlib`, thus rendering charts that are easy to use and highly-customizable."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In this example, we will demonstrate three plotting methods available on PySwarms:\n",
    "- `plot_cost_history`: for plotting the cost history of a swarm given a matrix\n",
    "- `plot_contour`: for plotting swarm trajectories of a 2D-swarm in two-dimensional space\n",
    "- `plot_surface`: for plotting swarm trajectories of a 2D-swarm in three-dimensional space"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Import modules\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "from IPython.display import Image\n",
    "\n",
    "# Import PySwarms\n",
    "import pyswarms as ps\n",
    "from pyswarms.utils.functions import single_obj as fx\n",
    "from pyswarms.utils.plotters import (plot_cost_history, plot_contour, plot_surface)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The first step is to create an optimizer. Here, we're going to use Global-best PSO to find the minima of a sphere function. As usual, we simply create an instance of its class `pyswarms.single.GlobalBestPSO` by passing the required parameters that we will use. Then, we'll call the `optimize()` method for 100 iterations."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2019-05-18 16:04:30,391 - pyswarms.single.global_best - INFO - Optimize for 100 iters with {'c1': 0.5, 'c2': 0.3, 'w': 0.9}\n",
      "pyswarms.single.global_best: 100%|██████████|100/100, best_cost=3.82e-8\n",
      "2019-05-18 16:04:31,656 - pyswarms.single.global_best - INFO - Optimization finished | best cost: 3.821571688965892e-08, best pos: [ 1.68014465e-04 -9.99342611e-05]\n"
     ]
    }
   ],
   "source": [
    "options = {'c1':0.5, 'c2':0.3, 'w':0.9}\n",
    "optimizer = ps.single.GlobalBestPSO(n_particles=50, dimensions=2, options=options)\n",
    "cost, pos = optimizer.optimize(fx.sphere, iters=100)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Plotting the cost history\n",
    "\n",
    "To plot the cost history, we simply obtain the `cost_history` from the `optimizer` class and pass it to the `cost_history` function. Furthermore, this method also accepts a keyword argument `**kwargs` similar to `matplotlib`. This enables us to further customize various artists and elements in the plot. In addition, we can obtain the following histories from the same class:\n",
    "- mean_neighbor_history: average local best history of all neighbors throughout optimization\n",
    "- mean_pbest_history: average personal best of the particles throughout optimization"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 720x576 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plot_cost_history(cost_history=optimizer.cost_history)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Animating swarms\n",
    "The `plotters` module offers two methods to perform animation, `plot_contour()` and `plot_surface()`. As its name suggests, these methods plot the particles in a 2-D or 3-D space.\n",
    "\n",
    "Each animation method returns a `matplotlib.animation.Animation` class that still needs to be animated by a `Writer` class (thus necessitating the installation of a writer module). For the proceeding examples, we will convert the animations into a JS script. In such case, we need to invoke some extra methods to do just that."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Lastly, it would be nice to add meshes in our swarm to plot the sphere function. This enables us to visually recognize where the particles are with respect to our objective function. We can accomplish that using the `Mesher` class."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "from pyswarms.utils.plotters.formatters import Mesher"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Initialize mesher with sphere function\n",
    "m = Mesher(func=fx.sphere)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "There are different formatters available in the `pyswarms.utils.plotters.formatters` module to customize your plots and visualizations. Aside from `Mesher`, there is a `Designer` class for customizing font sizes, figure sizes, etc. and an `Animator` class to set delays and repeats during animation."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Plotting in 2-D space\n",
    "\n",
    "We can obtain the swarm's position history using the `pos_history` attribute from the `optimizer` instance. To plot a 2D-contour, simply pass this together with the `Mesher` to the `plot_contour()` function. In addition, we can also mark the global minima of the sphere function, `(0,0)`, to visualize the swarm's \"target\"."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%capture\n",
    "# Make animation\n",
    "animation = plot_contour(pos_history=optimizer.pos_history,\n",
    "                         mesher=m,\n",
    "                         mark=(0,0))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2019-05-18 16:04:34,422 - matplotlib.animation - INFO - Animation.save using <class 'matplotlib.animation.ImageMagickWriter'>\n",
      "2019-05-18 16:04:34,425 - matplotlib.animation - INFO - MovieWriter.run: running command: ['convert', '-size', '720x576', '-depth', '8', '-delay', '10.0', '-loop', '0', 'rgba:-', 'plot0.gif']\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<img src=\"plot0.gif\"/>"
      ],
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Enables us to view it in a Jupyter notebook\n",
    "animation.save('plot0.gif', writer='imagemagick', fps=10)\n",
    "Image(url='plot0.gif')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Plotting in 3-D space\n",
    "\n",
    "To plot in 3D space, we need a position-fitness matrix with shape `(iterations, n_particles, 3)`. The first two columns indicate the x-y position of the particles, while the third column is the fitness of that given position. You need to set this up on your own, but we have provided a helper function  to compute this automatically"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Obtain a position-fitness matrix using the Mesher.compute_history_3d()\n",
    "# method. It requires a cost history obtainable from the optimizer class\n",
    "pos_history_3d = m.compute_history_3d(optimizer.pos_history)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Make a designer and set the x,y,z limits to (-1,1), (-1,1) and (-0.1,1) respectively\n",
    "from pyswarms.utils.plotters.formatters import Designer\n",
    "d = Designer(limits=[(-1,1), (-1,1), (-0.1,1)], label=['x-axis', 'y-axis', 'z-axis'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%capture\n",
    "# Make animation\n",
    "animation3d = plot_surface(pos_history=pos_history_3d, # Use the cost_history we computed\n",
    "                           mesher=m, designer=d,       # Customizations\n",
    "                           mark=(0,0,0))               # Mark minima"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2019-05-18 16:04:57,791 - matplotlib.animation - INFO - Animation.save using <class 'matplotlib.animation.ImageMagickWriter'>\n",
      "2019-05-18 16:04:57,792 - matplotlib.animation - INFO - MovieWriter.run: running command: ['convert', '-size', '720x576', '-depth', '8', '-delay', '10.0', '-loop', '0', 'rgba:-', 'plot1.gif']\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<img src=\"plot1.gif\"/>"
      ],
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "animation3d.save('plot1.gif', writer='imagemagick', fps=10)\n",
    "Image(url='plot1.gif')"
   ]
  }
 ],
 "metadata": {
  "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.6.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}