.. _ch05-python-matplotlib: =============================================================== Matplotlib =============================================================== Google drive folder with Jupyter Notebooks used in class: `Jupyter Notebooks from class `_ The ``matplotlib`` library is probably the single most used Python package for 2D-graphics. It provides both a quick way to visualize data from Python, and create publication-quality figures in many formats. We are going to explore Matplotlib in interactive mode covering most common cases. We will also look at the object oriented interface which provides more control and flexibility over the generated figures. An extensive gallery of examples using `Matplotlib `_ can found at the `Matplotlib examples page `_. See also a summary of `pyplot commands `_. Some useful plotting options can also found in the SciPy `lecture notes `_. ------------------------------------------------------------------------------ IPython ------------------------------------------------------------------------------ ``IPython`` is an enhanced interactive Python shell that has lots of interesting features including named inputs and outputs, access to shell commands, improved debugging and much more. When we start it with the command line argument ``--pylab``, it allows interactive Matplotlib sessions that has Matlab/Mathematica-like functionality. ------------------------------------------------------------------------------ Matplotlib and pyplot ------------------------------------------------------------------------------ There are nice tools for making plots of 1d and 2d data (curves, contour plots, etc.) in the ``pyplot`` sub-module of Matplotlib. To see some of what's possible (and learn how to do it), visit the `Matplotlib gallery `_. Clicking on a figure displays the Python code needed to create it. The best way to get Matplotlib working interactively in a standard Python shell is to do .. code-block:: python >>> import numpy as np >>> import matplotlib.pyplot as plt >>> plt.interactive(True) >>> x = np.linspace(-1, 1, 50) >>> plt.plot(x, x**2, 'o-') Notice also that, since ``pylab`` includes both ``matplotlib`` and ``numpy``, you can get the exact same features using a more compact way as follows .. code-block:: python >>> import pylab >>> pylab.interactive(True) Then you should be able to do .. code-block:: python >>> x = pylab.linspace(-1, 1, 50) >>> pylab.plot(x, x**2, 'o-') and see a plot of a parabola appear. .. _fig01: .. figure:: ./_figures/figure_1.png :align: center A simple plot of :math:`y = x^2`. You should also be able to use the buttons on the window to interact with the plot, e.g. zoom in and out, change white space, change axis types, etc. Alternatively, you could do .. code-block:: python >>> from pylab import * >>> interactive(True) With this approach you don't need to start every pylab function name with pylab, e.g. .. code-block:: python >>> x = linspace(-1, 1, 50) >>> plot(x, x**2, 'o-') In these notes we'll generally use module names just so it's clear where things come from. If you use the IPython shell instead, you can do .. code-block:: console $ ipython --pylab In [1]: x = linspace(-1, 1, 50) In [2]: plot(x, x**2, 'o-') The ``--pylab`` flag causes everything to be imported from pylab and set up for interactive plotting. --------------------------------- Matplotlib and Jupyter Notebooks --------------------------------- If you prefer to use Jupyter Notebooks you can get a more *Matlab-like* environment. In a cell of the Jupyter Notebook, type; .. code-block:: python %matplotlib inline import numpy as np import matplotlib.pyplot as plt And on the next cell, .. code-block:: python x = np.linspace(-1, 1, 50) plt.plot(x, x**2, 'o-') When you execute the cell above, (by hitting ``ctrl+enter``) you can see a figure as an output. .. _ch05-python-matplotlib-flash1d-hdf5: -------------------------------- Labels, titles, grids, legends -------------------------------- Let's continue with the plot of the parabola. Note that because we used ``plt.interactive(True)`` we can enter subsequent commands while the plot is already open. First, add some axis labels and a plot title: .. code-block:: python >>> plt.xlabel('x') >>> plt.ylabel('y') >>> plt.title(r'$y=x^2$') .. note:: To use LaTex notation in Matplotlib plots you'll need to use raw strings prefixed by an ``r`` as in the previous commands. Math mode can then be used safely by wrapping text with dollar signs. This is particularly needed when including Greek text or other items that would otherwise appear as escape codes. For example .. code-block:: python >>> plt.xlabel(r'$\alpha$') >>> # versus >>> plt.xlabel('$\alpha$') Those axis labels and the title are quite small. The ``xlabel``, ``ylabel``, and ``title`` functions can take in keyword arguments to control the text properties. Let's change the axis labels to make everything larger: .. code-block:: python >>> plt.xlabel(r'$x$',fontsize=16) >>> plt.ylabel(r'$y$',fontsize=16) >>> plt.title(r'$y=x^2$',fontsize=18) Grid lines are often helpful to guide the viewer's eye. These can be applied to major ticks, minor ticks, or both, and to the x-axis, y-axis, or both axes. For example .. code-block:: python >>> plt.grid(which='both',axis='both') After applying these changes you should have the following figure: .. _fig02: .. figure:: ./_figures/figure_2.png :align: center A simple plot of :math:`y = x^2` with some nicer formatting. ------------------------------------------- Plotting multiple lines ------------------------------------------- We now consider an example of plotting more than one function in the same figure. In the script below, we’ve instantiated (and commented) all the figure settings that influence the appearance of the plot. .. literalinclude:: ./codes/plot_sin_cos.py :language: python :linenos: :download:`Download this code <./codes/plot_sin_cos.py>` .. _fig03: .. figure:: ./_figures/figure_sin_cos.png :align: center A figure of :math:`\sin(x)` and :math:`\cos(x)` functions over :math:`[-\pi,\pi]`. The next example demonstrates a simple way to read in some FLASH 2D data, extract a 1D slice, and plot a 1D density profile. The test problem is called the Shu-Osher shock tube problem, details of which are available at `the FLASH users guide `_. .. literalinclude:: ./codes/plot_flash_1d.py :language: python :linenos: :download:`Download this code <./codes/plot_flash_1d.py>` :download:`Download the hdf5 data file <./codes/ppm-hllc_hdf5_chk_0009>` .. note:: After downloading the data file, you may need to remove the file extension ``.txt`` if it has one.) .. _fig04: .. figure:: ./_figures/figure_3.png :align: center 1D density and pressure profiles for the Shu-Osher shock tube problem. Exercise: Return to finite difference approximations ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ We finished the NumPy section with three example codes, the first of which was :ref:`ch04-python-numpy-findiff`. Return to that example, and add plots of the exact and approximate derivatives, as well as plots for the error in the approximation. In particular, do the following: * On one plot show the exact first derivative and both approximations * Use different line styles for each line and add a legend * Plot the error on the same plot using a second y-axis * Repeat for the second derivative Plotting the error on the same figure using a different scale requires us to dig a little deeper into how figures are created. In this case we'll pull out the figure and axis objects explicitly and work with them. Consider the following code snippet: .. code-block:: python # Generate plots fig, ax = plt.subplots() # Deriv and approximations ax.plot(xf,ex_fFD,'-k',xf,fFD,'-b',xc,cFD,'-r') ax.legend(('Exact','Fwd. Diff.','Ctr. Diff.'),loc='upper left') ax.set_xlabel('x',fontsize=14) ax.set_ylabel('Derivative',fontsize=14) ax.set_title('Finite difference approximation',fontsize=16) ax.grid('both') # Create second axis for the error # Note that we clone the x-axis instead of making a new y-axis ax_err = ax.twinx() ax_err.plot(xf,np.abs(fFD - ex_fFD),'--b',xc,np.abs(cFD - ex_cFD),'--r') ax_err.set_ylabel('Absolute error') fig.tight_layout() plt.show() Here we call ``plot`` directly on the axis object, instead of working through the static interface ``plt.*``. Most of the functions are the same, but note the ``set_`` prefix on the label and title functions. This approach requires a little more set up, but allows much greater flexibility in what you can plot. .. _ch05-python-matplotlib-flash2d3d-hdf5: ------------------------------------------------------------------------------ Advanced plots -- 2D plots, 3D plots, subplots and more ------------------------------------------------------------------------------ So far we have covered some basic features for producing plots from 1D data. Let's briefly take a look at an example which produces 2D plots of a Rayleigh-Taylor instability. This is an unstable configuration where a heavy fluid lies *above* a light fluid in the presence gravity. See the `wiki `_ page for more information. To do this we'll use this plotting script which manages all of the HDF5 file format stuff and pulls out the individual fields. .. literalinclude:: ./codes/gpplot.py :language: python :linenos: :download:`Download this code <./codes/gpplot.py>` :download:`Download the hdf5 data file <./codes/RayleighTaylor0128_3_002975.h5>` * A contour plot of the density can be generated by calling: .. code-block:: console python gpplot.py RayleighTaylor0128_3_002975.h5 dens .. _fig05: .. figure:: ./_figures/raytay.png :align: center :scale: 75 % Plot of the density field at time :math:`T=1.95` using ``imshow`` * Line plots of the density along a couple slices can be generated as: .. literalinclude:: ./codes/sliceRayTay.py :download:`Download this code <./codes/sliceRayTay.py>` .. _figSlice: .. figure:: ./_figures/rayTaySlice.png :align: center Density along slices of the flow * A surface plot of the internal energy using ``plot_surface``: .. literalinclude:: ./codes/surfRayTay.py :download:`Download this code <./codes/surfRayTay.py>` .. _fig06: .. figure:: ./_figures/rayTayEInt.png :align: center Surface plot of internal energy * A wireframe plot of the pressure using ``plot_wireframe``: .. literalinclude:: ./codes/wireframeRayTay.py :download:`Download this code <./codes/wireframeRayTay.py>` .. _fig07: .. figure:: ./_figures/figure_7.png :align: center Wireframe plot of the pressure One can also produce a plot with multiple subplots: .. literalinclude:: ./codes/plot_flash_subplot.py :language: python :linenos: :download:`Download this code <./codes/plot_flash_subplot.py>` :download:`Download the data <./codes/subplot_data.tar.gz>` .. note:: Notice in the above example that there are two ``for-loops``, where the first loop finds the global min and max of the time varying densities over a series of times, :math:`t=0.01, 0.02, 0.03, 0.04, 0.05, 0.06`. The second loop uses the obtained minimum (:math:`\rho_{\min}`) and maximum (:math:`\rho_{\max}`) densities in order to plot six subfigures in a consistent color scheme. Otherwise, all six subfigures would use different color scales, making it hard to compare the density values over time. .. _fig10: .. figure:: ./_figures/figure_9.png :align: center :scale: 60 % 2D subplots of density at various times. There is plenty more to learn, and many great examples can be found on the Matplotlib gallery page. If you have a mental image of a figure you want to create, have a look there first for anything that may be similar. * `Matplotlib homepage `_ * `gallery `_ * `pyplot commands `_