{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "Introduction to Matplotlib\n", "==" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "skip" } }, "source": [ "Now that we can start doing serious numerical analysis with Numpy arrays, we also reach the stage where we can no longer print out hundreds or thousands of values, so we need to be able to make plots to show the results." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The **Matplotlib** package can be used to make scientific-grade plots. You can import it with:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import matplotlib.pyplot as plt" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "In a jupyter notebook, it is often helpful to add a cell containing:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%matplotlib inline" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "(``%matplotlib`` is a so-called \"magic function\") so that the plots will appear inside the notebook.\n", "\n", "In more recent versions of matplotlib there is also ``%matplotlib notebook`` which is an interactive output." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Basic plotting" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "The main plotting function is called ``plot``:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.plot([1,2,3,6,4,2,3,4])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the above example, we only gave a single list, so it will assume the x values are the indices of the list/array." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "However, we can instead specify the x values:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.plot([3.3, 4.4, 4.5, 6.5], [3., 5., 6., 7.])" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "Matplotlib can take Numpy arrays, so we can do for example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "x = np.linspace(0., 10., 50)\n", "y = np.sin(x)\n", "plt.plot(x, y)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "The ``plt.plot()`` function is actually quite complex, and for example can take arguments specifying the type of point, the color of the line, and the width of the line:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.plot(x, y, marker='o', color='green', linewidth=2)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "The line can be hidden with:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.plot(x, y, marker='o', color='green', linewidth=0)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "If you are interested, you can specify some of these attributes with a special syntax, which you can read up more about in the Matplotlib documentation:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.plot(x, y, 'go') # means green and circles" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Exercise 1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We start off by loading the ``data/munich_temperatures_average_with_bad_data.txt`` file which we encountered in the introduction to Numpy (section 10):" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# The following code reads in the file and removes bad values\n", "import numpy as np\n", "date, temperature = np.loadtxt('data/munich_temperatures_average_with_bad_data.txt', unpack=True)\n", "keep = np.abs(temperature) < 90\n", "date = date[keep]\n", "temperature = temperature[keep]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now that the data has been read in, plot the temperature against time:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# your solution here" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next, plot the data against the fraction of the year (all years on top of each other).\n", "For this, the ``%`` (modulo) operator is useful to find the fractional part of the dates:\n", " 1982.2762%1 = 0.2762" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# your solution here" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Other types of plots" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Scatter plots" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "While the ``plt.plot()`` function can be used to show scatter plots, it is mainly used for line plots, and the ``plt.scatter()`` function is more often used for scatter plots, because it allows more fine control of the markers:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x = np.random.random(100)\n", "y = np.random.random(100)\n", "plt.scatter(x, y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Histograms" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "Histograms are easy to plot using the ``plt.hist()`` function:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "v = np.random.uniform(0., 10., 100)\n", "h = plt.hist(v,bins=[0,2,4,6,8,10],density=True) # we do h= to capture the output of the function, but we don't use it (here)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In older version of python, the option to normalize the histogram was called ``normed=True``, but this now often puts out warnings or does not work anymore." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Images" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "You can also show two-dimensional arrays with the ``plt.imshow()`` function:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "array = np.random.random((64, 64))\n", "plt.imshow(array)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "And the colormap can be changed:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.imshow(array, cmap=plt.cm.gist_heat)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Contours" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Often, countour plots are useful to illustrate 3D data. This can be done using ``plt.contour()``:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x = np.arange(-2.0, 2.0, 0.005)\n", "y = np.arange(-2.0, 2.0, 0.005)\n", "xx, yy = np.meshgrid(x, y)\n", "zz = np.exp(-xx**2 - yy**2)*(xx-yy)**2\n", "\n", "plt.axes().set_aspect('equal') # equal aspect ratio\n", "\n", "contour_set = plt.contour(xx, yy, zz) # returns a set of contour lines for plt.clabel\n", "plt.clabel(contour_set) # creates labels with gaps in the contours" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the above, we used the ``np.meshgrid()`` function which is useful when the plotting functions (and also other functions in general) require the ``X`` and ``Y`` coordinates in a special format. To understand the ``np.meshgrid()`` function better, consider the following example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# For example:\n", "x = [1,2,3]\n", "y = [1,2]\n", "a, b = np.meshgrid(x, y)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(np.shape(a), np.shape(b))\n", "print(a)\n", "print(b)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "So for each of the chosen ``x`` and ``y`` points, ``a`` and ``b`` contain the values of ``x`` and ``y``, respectively." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# at coordinate (0|1), we have (note: the first index determines y, the second x)\n", "print(x[0], y[1], a[1][0], b[1][0])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Field lines" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For a **vector field**, you can plot a depiction of the field lines with **plt.streamplot()**\n", "\n", "Here this is done in the x-y plane for the field\n", " $$\\vec{K}(\\vec{r})=\\vec{K}(x,y,z) = (-y,x,0) = \\vec{e}_z \\times \\vec{r}$$\n", " \n", "We again use **np.meshgrid()** :" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x=np.arange(-10,10,0.1)\n", "y=np.arange(-10,10,0.1)\n", "\n", "xx,yy=np.meshgrid(x,y) # define meshgrid of all coordinates\n", " # (can also work out radii etc)\n", "kx =-yy\n", "ky = xx\n", "\n", "plt.streamplot(x,y,kx,ky,color='k')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Customizing plots" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "You can also customize plots. For example, the following code adds axis labels, and sets the x and y ranges explicitly:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x = np.random.random(100)\n", "y = np.random.random(100)\n", "plt.scatter(x, y)\n", "plt.xlabel('x values')\n", "plt.ylabel('y values')\n", "plt.xlim(0., 1.)\n", "plt.ylim(0., 1.)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Saving plots to files" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "To save a plot to a file, you can do for example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x = np.random.random(100)\n", "y = np.random.random(100)\n", "plt.scatter(x, y)\n", "plt.xlabel('x values')\n", "plt.ylabel('y values')\n", "plt.xlim(0., 1.)\n", "plt.ylim(0., 1.)\n", "\n", "plt.savefig('my_plot.png')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "and you can then view the resulting file like you would view a normal image (check the current folder)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Interactive plotting" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "One of the features of Matplotlib is the ability to make interactive plots. When using IPython, you can do:\n", "\n", " %matplotlib qt\n", " \n", "or\n", "\n", " %matplotlib notebook\n", " \n", "(somwhat dependent on the version) to change the backend to be interactive, after which plots that you make will be interactive." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Learning more" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "skip" } }, "source": [ "The easiest way to find out more about a function and available options is to use the ``?`` help in IPython:\n", "\n", " In [11]: plt.hist?\n", "\n", " Definition: plt.hist(x, bins=10, range=None, normed=False, weights=None, cumulative=False, bottom=None, histtype='bar', align='mid', orientation='vertical', rwidth=None, log=False, color=None, label=None, stacked=False, hold=None, **kwargs)\n", " Docstring:\n", " Plot a histogram.\n", "\n", " Call signature::\n", "\n", " hist(x, bins=10, range=None, normed=False, weights=None,\n", " cumulative=False, bottom=None, histtype='bar', align='mid',\n", " orientation='vertical', rwidth=None, log=False,\n", " color=None, label=None, stacked=False,\n", " **kwargs)\n", "\n", " Compute and draw the histogram of *x*. The return value is a\n", " tuple (*n*, *bins*, *patches*) or ([*n0*, *n1*, ...], *bins*,\n", " [*patches0*, *patches1*,...]) if the input contains multiple\n", " data.\n", "\n", " etc.\n", "\n", "But sometimes you don't even know how to make a specific type of plot, in which case you can look at the [Matplotlib Gallery](http://matplotlib.org/gallery.html) for example plots and scripts.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Exercise 2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "1. Use Numpy to generate 10000 random values following a Gaussian/Normal distribution using ``np.random.normal()``, and make a histogram. Adjust the number of bins to properly see the Gaussian. Over-plot a Gaussian function using a colored line, and adjust the normalization so that the histogram and the line are aligned.\n", "\n", "2. Do the same for a Poisson distribution. Compare the Poisson distribution for expectation values $\\lambda <15$ with the appropriate Gaussian." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# your solution here" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Exercise 3 [Bonus]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Work out the magnetic field lines of two equal but infinite line currents along the z-axis that are separated by a distance $a$ along the y-axis.\n", "\n", "Since the stream lines are scaled, one can drop constants.\n", "\n", "The $\\vec{B}$-Field of a single line current $I$ is\n", "$$\\vec{B} (\\vec{r})= \\frac{\\mu_0 I}{2 \\pi} \\frac{1}{|\\vec{r}|} \\vec{e}_{\\varphi}$$\n", " \n", "**Only** with time left: Can you plot the fieldlines in the x-y plane for a circular coil with radius a in the x-z plane?\n", "The Biot-Savart law for a wire element is\n", "\n", "$$d\\vec{B} (\\vec{r})= \\frac{\\mu_0 I}{4 \\pi} \\frac{d \\vec{l} \\times \\vec{r}}{|\\vec{r}|^3}$$\n", "\n", "where $\\vec{r}$ is the vector from the current element to the place of measurement.\n", "\n", "You can even code the problem in a way that you can add an aribitrary number of coils, e.g. for a long coil or a ring coil (torus)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# your solution here" ] } ], "metadata": { "anaconda-cloud": {}, "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.8.10" } }, "nbformat": 4, "nbformat_minor": 1 }