{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h1>17. More Matplotlib</h1>\n",
    "<h2>11/17/2023</h2>\n",
    "\n",
    "<h2>17.0 Last Time...</h2>\n",
    "<ul>\n",
    "    <li><b>matplotlib</b>'s <b>pyplot</b> module lets us use Matlab's powerful plotting tools in Python.</li>\n",
    "    <li>The <b>matplotlib.pyplot.plot()</b> function is a simple way to plot 2-D data.</li>\n",
    "    <li>We can specify axis limits as well as line style and color.</li>\n",
    "</ul>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h2>17.1 Keyword Strings</h2>\n",
    "\n",
    "With a normal scatterplot, you can convey two pieces of information for each point: (1) what the x value is, and (2) what the y value is. You can get additional information crammed into one plot by allowing the size and color of the points being plotted to vary!\n",
    "\n",
    "matplotlib.pyplot has a handy function for this particular application called <b>scatter()</b>. By default, you only need two arguments that consist of arrays of your x data and your y data."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23\n",
      " 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47\n",
      " 48 49]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<matplotlib.collections.PathCollection at 0x10e8e6c90>"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 17172 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "# Let's have our x values just be a count from 0 to 49.\n",
    "var1 = np.arange(50)\n",
    "print(var1)\n",
    "\n",
    "# And let's randomly generate some y values!\n",
    "var2 = var1 + 10*np.random.randn(50)\n",
    "\n",
    "plt.scatter(var1,var2)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Okay! So we have some information being shown here: we can see that there's a general positive trend going on here. But what if we have additional information (say this is temperature versus dewpoint temperature and we also know something about relative humidity)? We can convey that information using the 'c' argument in scatter(): the color of the data points."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.collections.PathCollection at 0x10e9a14d0>"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 28856 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Now we have a third variable that's a new set of random numbers from 0 to 50.\n",
    "\n",
    "var3 = 8*np.random.randint(0,50,50)\n",
    "plt.scatter(var1,var2,c=var3)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "More information has been conveyed! Let's try adding even more information - say, a fourth meteorological variable like wind speed - through the size of the circle, which is the 's' argument in scatter(). This marker size is in 'points' squared."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/opt/homebrew/Caskroom/miniconda/base/lib/python3.11/site-packages/matplotlib/collections.py:996: RuntimeWarning: invalid value encountered in sqrt\n",
      "  scale = np.sqrt(self._sizes) * dpi / 72.0 * self._factor\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<matplotlib.collections.PathCollection at 0x10ea0e6d0>"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 22120 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    " #This gives random numbers on a N(0,1) Gaussian.\n",
    "var4 = np.random.randn(50)*100\n",
    "plt.scatter(var1,var2,c=var3,s=var4)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h2>17.2 Categorical Variables</h2>\n",
    "\n",
    "Sometimes you have data in the form of categories! You may have, for instance, two different sets of tornado data (like in Homework 3), or three different future climate regimes, or five different locations. Any sort of comparative research will require this sort of categorical data analysis!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<BarContainer object of 3 artists>"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 8832 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "# Let's look at the example of three pieces of data.\n",
    "# They might be mean values of three parameters, average grades on an assignment, etc.\n",
    "names = ['groupa','groupb','groupc']\n",
    "values = [58.9,90.3,3]\n",
    "\n",
    "\n",
    "# We can start with a bar plot.\n",
    "plt.bar(names,values)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.collections.PathCollection at 0x10eaaee90>"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 9772 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# We can also create a scatterplot as seen above.\n",
    "plt.scatter(names,values)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[<matplotlib.lines.Line2D at 0x10eab6c90>]"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 23020 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Or a line plot!\n",
    "plt.plot(names,values)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h2>17.3 Controlling Line Properties</h2>\n",
    "\n",
    "There are a bunch of line attributes you can set! The line type/color/marker examples we saw earlier are shortcuts for common configurations, but there are a <i>lot</i> more. You can find the full list by googling <b>matplotlib.lines.Line2d</b>, or by calling the <b>plt.setp()</b> function with a line or lines as an argument."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "  agg_filter: a filter function, which takes a (m, n, 3) float array and a dpi value, and returns a (m, n, 3) array and two offsets from the bottom left corner of the image\n",
      "  alpha: scalar or None\n",
      "  animated: bool\n",
      "  antialiased or aa: bool\n",
      "  clip_box: `~matplotlib.transforms.BboxBase` or None\n",
      "  clip_on: bool\n",
      "  clip_path: Patch or (Path, Transform) or None\n",
      "  color or c: color\n",
      "  dash_capstyle: `.CapStyle` or {'butt', 'projecting', 'round'}\n",
      "  dash_joinstyle: `.JoinStyle` or {'miter', 'round', 'bevel'}\n",
      "  dashes: sequence of floats (on/off ink in points) or (None, None)\n",
      "  data: (2, N) array or two 1D arrays\n",
      "  drawstyle or ds: {'default', 'steps', 'steps-pre', 'steps-mid', 'steps-post'}, default: 'default'\n",
      "  figure: `~matplotlib.figure.Figure`\n",
      "  fillstyle: {'full', 'left', 'right', 'bottom', 'top', 'none'}\n",
      "  gapcolor: color or None\n",
      "  gid: str\n",
      "  in_layout: bool\n",
      "  label: object\n",
      "  linestyle or ls: {'-', '--', '-.', ':', '', (offset, on-off-seq), ...}\n",
      "  linewidth or lw: float\n",
      "  marker: marker style string, `~.path.Path` or `~.markers.MarkerStyle`\n",
      "  markeredgecolor or mec: color\n",
      "  markeredgewidth or mew: float\n",
      "  markerfacecolor or mfc: color\n",
      "  markerfacecoloralt or mfcalt: color\n",
      "  markersize or ms: float\n",
      "  markevery: None or int or (int, int) or slice or list[int] or float or (float, float) or list[bool]\n",
      "  mouseover: bool\n",
      "  path_effects: list of `.AbstractPathEffect`\n",
      "  picker: float or callable[[Artist, Event], tuple[bool, dict]]\n",
      "  pickradius: float\n",
      "  rasterized: bool\n",
      "  sketch_params: (scale: float, length: float, randomness: float)\n",
      "  snap: bool or None\n",
      "  solid_capstyle: `.CapStyle` or {'butt', 'projecting', 'round'}\n",
      "  solid_joinstyle: `.JoinStyle` or {'miter', 'round', 'bevel'}\n",
      "  transform: `~matplotlib.transforms.Transform`\n",
      "  url: str\n",
      "  visible: bool\n",
      "  xdata: 1D array\n",
      "  ydata: 1D array\n",
      "  zorder: float\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 25876 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "lines = plt.plot([1,2,3])\n",
    "plt.setp(lines)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's say you want to increase the width of a given line. You'd want to use the <b>linewidth</b> argument."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[<matplotlib.lines.Line2D at 0x10ec75290>]"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 22076 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import numpy as np\n",
    "plt.plot(np.arange(9),linewidth=5.0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[<matplotlib.lines.Line2D at 0x10eb6ad10>]"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 26972 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Likewise, you can set the color.\n",
    "plt.plot(np.arange(20),linewidth=20,color='darkblue')\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[<matplotlib.lines.Line2D at 0x10ed55290>]"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 20248 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# If you have markers, you can change their properties as well!\n",
    "plt.plot(np.arange(10),'-o',markeredgecolor='red',markerfacecolor='yellow')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h2>17.4 Multiple Figures and Axes</h2>\n",
    "\n",
    "We often want to deal with multiple subplots within the same figure. As a behind-the-scenes note, pyplot keeps track of the \"current\" figure and axes, which can be referred to using <b>gcf()</b> and <b>gca()</b>, respectively. You probably won't have to worry about this too often.\n",
    "\n",
    "The <b>subplot()</b> function refers to a particular subplot within a set. It has three arguments: number of rows, number of columns, and then the specific number of this plot (which ranges from 1 to number_rows*number_columns)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 42996 characters]",
      "text/plain": [
       "<Figure size 640x480 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Let's create a couple of subplots of fairly complex data:\n",
    "# a damped oscillation and an undamped oscillation.\n",
    "import numpy as np\n",
    "# Start by creating a function that will give us a decaying oscillation.\n",
    "def f(t):\n",
    "    return np.exp(-t)*np.cos(2*np.pi*t)\n",
    "\n",
    "\n",
    "# Next, let's have two sets of x values:\n",
    "# the first is more widely spaced than the second,\n",
    "# but they cover the same range of data.\n",
    "t1 = np.arange(0,5,0.1)\n",
    "t2 = np.arange(0,5,0.02)\n",
    "\n",
    "\n",
    "# First, we create a setup where we have two rows and 1 column of\n",
    "# plots, and we're referring to the first plot.\n",
    "plt.subplot(2,1,1)\n",
    "plt.plot(t1,f(t1),'ob',t2,f(t2),'k')\n",
    "\n",
    "# Next, we'll refer to the second plot.\n",
    "\n",
    "plt.subplot(2,1,2)\n",
    "plt.plot(t2,np.cos(2*np.pi*t2),'r--')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<b>Exercise:</b> Make 4 subplots (2 rows, 2 columns) using the x values below and plot whatever functions you like on them (sin(x), cos(x), 2/x, etc.)!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[<matplotlib.lines.Line2D at 0x10ef55d10>]"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 49072 characters]",
      "text/plain": [
       "<Figure size 640x480 with 4 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "x = np.arange(0.0,10,0.01)\n",
    "\n",
    "plt.subplot(2,2,1)\n",
    "plt.plot(x,np.sin(x))\n",
    "plt.subplot(2,2,2)\n",
    "plt.plot(x,np.cos(x))\n",
    "plt.subplot(2,2,3)\n",
    "plt.plot(x,2*np.cos(x))\n",
    "plt.subplot(2,2,4)\n",
    "plt.plot(x,4*np.sin(x))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h2>17.5 Working with Text</h2>\n",
    "\n",
    "You can use the <b>text()</b> function to place text in any arbitrary location. As seen above, some useful text-related functions include <b>xlabel()</b>, <b>ylabel()</b>, and <b>title()</b>.\n",
    "\n",
    "As a side note, if you want to use mathematical expressions in text, it can get a little confusing. You'll want to start your string with the letter r, then surround it with quotation marks followed by dollar signs. The conventions are the same as in LaTeX, and you can find the details by googling 'LaTeX math'."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[41.32270515 86.64818776 48.41249733 ... 39.1275195  74.85441181\n",
      " 59.70951104]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "Text(20, 0.025, '$\\\\mu=60 \\\\sigma=15$')"
      ]
     },
     "execution_count": 68,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 32640 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Let's generate a histogram from a set of random values in a distribution\n",
    "# with a specified mean and standard deviation.\n",
    "mu,sigma =60,15\n",
    "x = mu + sigma *np.random.randn(10000)\n",
    "print(x)\n",
    "\n",
    "# Let's create a histogram!\n",
    "plt.hist(x,100,density=1,facecolor='g')\n",
    "plt.grid(True)\n",
    "plt.axis([0,100,0,0.03])\n",
    "plt.xlabel('grades')\n",
    "plt.ylabel('frequency')\n",
    "plt.title('hist of phys midterm2 grades',fontsize=24)\n",
    "plt.text(20,.025,r\"$\\mu=60 \\sigma=15$\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "There's also a method of annotating text that is called, as you might expect, <b>annotate()</b>. An example follows!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(-2.0, 2.0)"
      ]
     },
     "execution_count": 72,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 36900 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "t = np.arange(0,5,.01)\n",
    "s = np.cos(2*np.pi*t)\n",
    "plt.plot(t,s)\n",
    "plt.annotate('local max',xy=(2,1),xytext=(3,1.5),arrowprops=dict(facecolor=\"black\"))\n",
    "plt.ylim(-2,2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h2>17.6 Nonlinear Axes</h2>\n",
    "\n",
    "If your data spans many orders of magnitude, it can be helpful to create nonlinear axes using <b>xscale()</b> or <b>yscale()</b>."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 81,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 103864 characters]",
      "text/plain": [
       "<Figure size 640x480 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Let's do something called fixing the random state.\n",
    "# Typically when you generate random numbers, every time you\n",
    "# run the code you'll get a different result.\n",
    "# Setting a particular random seed will ensure that we can reproduce\n",
    "# the same results every time for demonstration purposes.\n",
    "\n",
    "np.random.seed(19680801)\n",
    "\n",
    "# Let's just make up some data in the interval (0,1)\n",
    "y = np.random.normal(loc=.0,scale=.4,size=1000)\n",
    "y =y[(y>0) & (y<1)]\n",
    "x = np.arange(len(y))\n",
    "\n",
    "plt.subplot(2,1,1)\n",
    "plt.title('linear')\n",
    "plt.plot(x,y)\n",
    "plt.yscale('linear')\n",
    "plt.grid(True)\n",
    "plt.subplot(2,1,2)\n",
    "plt.title(\"logarithmic\")\n",
    "plt.plot(x,y)\n",
    "plt.yscale('log')\n",
    "plt.grid(True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h2>17.7 Take-Home Points</h2>\n",
    "<ul>\n",
    "    <li>The scatter() function can make use of keyword strings to set the shape and color of points on the plot.</li>\n",
    "    <li>We can also use categorical variables to plot groups of information.</li>\n",
    "    <li>There are many line properties that can be edited!</li>\n",
    "    <li>Subplots can be added using the subplot() function.</li>\n",
    "    <li>Text can be added or annotated on plots.</li>\n",
    "    <li>Nonlinear axes can be added using xscale() or yscale().</li>\n",
    "</ul>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "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.11.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
