diff --git a/data/dessert.png b/data/dessert.png new file mode 100644 index 0000000..cb66995 Binary files /dev/null and b/data/dessert.png differ diff --git a/data/stained_glass_barcelona.png b/data/stained_glass_barcelona.png new file mode 100644 index 0000000..6f1780b Binary files /dev/null and b/data/stained_glass_barcelona.png differ diff --git a/data/stinkbug.png b/data/stinkbug.png new file mode 100644 index 0000000..6d6c4d0 Binary files /dev/null and b/data/stinkbug.png differ diff --git a/image_tutorial.ipynb b/image_tutorial.ipynb new file mode 100644 index 0000000..91914b5 --- /dev/null +++ b/image_tutorial.ipynb @@ -0,0 +1,174 @@ +{ + "metadata": { + "name": "image_tutorial" + }, + "nbformat": 2, + "worksheets": [ + { + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# Matplotlib image tutorial", + "", + "This is a copy of the official [matplotlib introductory image tutorial](http://matplotlib.sourceforge.net/users/image_tutorial.html)", + "in the form of a notebook." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "%pylab inline", + "import matplotlib.pyplot as plt", + "import matplotlib.image as mpimg", + "import numpy as np" + ], + "language": "python", + "outputs": [], + "prompt_number": 1 + }, + { + "cell_type": "code", + "collapsed": true, + "input": [ + "img = mpimg.imread('data/stinkbug.png')" + ], + "language": "python", + "outputs": [], + "prompt_number": 2 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "plt.imshow(img)" + ], + "language": "python", + "outputs": [], + "prompt_number": 3 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "lum_img = img[:,:,0]", + "fig, ax = plt.subplots()", + "imgplot = ax.imshow(lum_img)" + ], + "language": "python", + "outputs": [], + "prompt_number": 4 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "imgplot.set_cmap('hot')", + "imgplot.figure" + ], + "language": "python", + "outputs": [], + "prompt_number": 5 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "imgplot.set_cmap('spectral')", + "imgplot.figure" + ], + "language": "python", + "outputs": [], + "prompt_number": 6 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "imgplot.set_cmap('spectral')", + "fig.colorbar(imgplot)", + "fig" + ], + "language": "python", + "outputs": [], + "prompt_number": 7 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "plt.hist(lum_img.flatten(), 256, range=(0.0,1.0), fc='k', ec='k');" + ], + "language": "python", + "outputs": [], + "prompt_number": 8 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10,4))", + "", + "imgplot1 = ax1.imshow(lum_img)", + "ax1.set_title('Before')", + "fig.colorbar(imgplot1, ax=ax1, ticks=[0.1,0.3,0.5,0.7], orientation ='horizontal')", + "", + "imgplot2 = ax2.imshow(lum_img)", + "imgplot2.set_clim(0.0,0.7)", + "ax2.set_title('After')", + "fig.colorbar(imgplot2, ax=ax2, ticks=[0.1,0.3,0.5,0.7], orientation='horizontal');" + ], + "language": "python", + "outputs": [], + "prompt_number": 9 + }, + { + "cell_type": "code", + "collapsed": true, + "input": [ + "import Image", + "img = Image.open('data/stinkbug.png') # Open image as PIL image object", + "rsize = img.resize((img.size[0]/10, img.size[1]/10)) # Use PIL to resize", + "rsizeArr = np.asarray(rsize) # Get array back" + ], + "language": "python", + "outputs": [], + "prompt_number": 10 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "imgplot = plt.imshow(rsizeArr, interpolation='bilinear')" + ], + "language": "python", + "outputs": [], + "prompt_number": 11 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "imgplot.set_interpolation('nearest')", + "imgplot.figure" + ], + "language": "python", + "outputs": [], + "prompt_number": 12 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "imgplot.set_interpolation('bicubic')", + "imgplot.figure" + ], + "language": "python", + "outputs": [], + "prompt_number": 13 + } + ] + } + ] +} \ No newline at end of file diff --git a/mapping_seismic_stations.ipynb b/mapping_seismic_stations.ipynb new file mode 100644 index 0000000..ce11a8d --- /dev/null +++ b/mapping_seismic_stations.ipynb @@ -0,0 +1,186 @@ +{ + "metadata": { + "name": "mapping_seismic_stations" + }, + "nbformat": 2, + "worksheets": [ + { + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# Mapping seismic stations in the Himalayas with Numpy and Matplotlib", + "## Or reading datasets with custom dtypes and plotting Earth-based data with basemap" + ] + }, + { + "cell_type": "markdown", + "source": [ + "In this exercise, we consider loading measurement files with the format:", + "", + "
", 
+      "# Station  Lat    Long   Elev ", 
+      "BIRA\t26.4840\t87.2670\t0.0120", 
+      "BUNG\t27.8771\t85.8909\t1.1910", 
+      "etc...", 
+      "
", + "", + "These are seismic measurement stations in the Himalaya, with the elevation indicated in km. Data with a structure such as this is common in many disciplines, and because we have a combination of text and numerical fields, we can't directly load it into a regular numpy array.", + "", + "But we can use numpy's ability to [define custom data types (dtypes)](http://docs.scipy.org/doc/numpy/reference/arrays.dtypes.html) to compactly describe our data in a single array, which we can then manipulate.", + "", + "If you have the basemap matplotlib toolkit installed, at the end of this example we will show a real Earth map and overlay the station locations on top of that.", + "", + "We start by configuring pylab support and loading the required modules." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "%pylab inline" + ], + "language": "python", + "outputs": [], + "prompt_number": 1 + }, + { + "cell_type": "code", + "collapsed": true, + "input": [ + "import numpy as np", + "import matplotlib.pyplot as plt" + ], + "language": "python", + "outputs": [], + "prompt_number": 2 + }, + { + "cell_type": "markdown", + "source": [ + "Now, we need to describe this dataset. There are several ways of declaring a dtype, in this simple case we show two equivalent ones. See the [numpy reference docs](http://docs.scipy.org/doc/numpy/reference/arrays.dtypes.html) for more details:" + ] + }, + { + "cell_type": "code", + "collapsed": true, + "input": [ + "# Data descriptor to make a proper array.", + "dt = [('station','S4'), ('lat',np.float32), ('lon',np.float32), ('elev',np.float32) ]", + "", + "# This is an alternate and fully equivalent form:", + "dt = dict(names = ('station','lat','lon','elev'),", + " formats = ('S4',np.float32,np.float32,np.float32) )" + ], + "language": "python", + "outputs": [], + "prompt_number": 4 + }, + { + "cell_type": "markdown", + "source": [ + "Now, we load the data using this dtype we've constructed, and view it as a recarray for convenient named-field access:" + ] + }, + { + "cell_type": "code", + "collapsed": true, + "input": [ + "data_fname = os.path.join('data', 'stations.txt')", + "tab = np.loadtxt(data_fname, dt).view(np.recarray)" + ], + "language": "python", + "outputs": [], + "prompt_number": 3 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "ptitle = 'Seismic stations in the Himalaya'", + "print ptitle", + "print 'Stations:', tab.station", + "print 'Elevations (km):', tab.elev", + "print 'First station:', tab[0]", + "print 'Mean latitude:', tab.lat.mean()" + ], + "language": "python", + "outputs": [], + "prompt_number": 4 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "f1, ax = plt.subplots(figsize = (8,5))", + "", + "# Make the size of the circles proportional to the elevation", + "sizes = 40*(tab.elev+1)", + "s = ax.scatter(tab.lon, tab.lat, s=sizes, c=tab.elev)", + "", + "# The colorbar must be associated with the return value of scatter()", + "f1.colorbar(s)", + "ax.set_title(ptitle)", + "# Now add text labels for all the stations. ", + "", + "# Note: when accessing single elements of the recarray, the named field", + "# syntax doesn't work and we must access the fields via ['name']", + "for record in tab:", + " ax.text(record['lon']+0.1, record['lat']+0.1, record['station'], weight='bold')" + ], + "language": "python", + "outputs": [], + "prompt_number": 23 + }, + { + "cell_type": "markdown", + "source": [ + "If we find the matplotlib basemap toolkit, we can show an even better plot by", + "overlaying the stations on top of a map of Earth at that location. But we", + "check this import so the code runs even without basemap." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "try:", + " from mpl_toolkits.basemap import Basemap", + "except ImportError:", + " pass", + "else:", + " # Draw the stations on a real map of the Earth.", + " # Find boundaries ", + " lon0 = 0.995*tab.lon.min()", + " lon1 = 1.01*tab.lon.max()", + " lat0 = 0.995*tab.lat.min()", + " lat1 = 1.01*tab.lat.max()", + " # Geographic grid to draw", + " parallels = np.linspace(lat0, lat1, 5)", + " meridians = np.linspace(lon0, lon1, 5)", + "", + " # Resolution of the basemap to load ('f' is *very* expensive)", + " resolution = 'i' # intermediate resolution for map info", + "", + " f2, ax2 = plt.subplots(figsize=(10,6))", + " m = Basemap(lon0, lat0, lon1, lat1, resolution=resolution, ax=ax2)", + " m.drawcountries(color=(1,1,0)) # country boundaries yellow", + " m.drawrivers(color=(0,1,1)) # rivers in cyan", + " m.bluemarble() # NASA bluemarble image", + " m.drawparallels(parallels, labels=[1,0,0,0], fmt='%.2f')", + " m.drawmeridians(meridians, labels=[0,0,0,1], fmt='%.2f')", + " s = m.scatter(tab.lon, tab.lat, s=sizes, c=tab.elev, zorder=10, alpha=0.6)", + " f2.colorbar(s)", + " ax2.set_title(ptitle)", + " for record in tab:", + " ax2.text( record['lon']+0.05, record['lat']+0.05, record['station'], ", + " weight='bold', color='yellow', zorder=10)" + ], + "language": "python", + "outputs": [], + "prompt_number": 29 + } + ] + } + ] +} \ No newline at end of file diff --git a/mapping_seismic_stations_interactive.ipynb b/mapping_seismic_stations_interactive.ipynb new file mode 100644 index 0000000..d0ad6ba --- /dev/null +++ b/mapping_seismic_stations_interactive.ipynb @@ -0,0 +1,138 @@ +{ + "metadata": { + "name": "mapping_seismic_stations_interactive" + }, + "nbformat": 2, + "worksheets": [ + { + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# Mapping seismic stations in the Himalayas with Numpy and Matplotlib", + "## Part II - Interactive event handling" + ] + }, + { + "cell_type": "markdown", + "source": [ + "Here, we extend the plot above by adding an event handler that prints the location (four-letter string) of the station you click on.", + "", + "We use a threshold for distance, and discriminate between a click below threshold (considered to be 'on') vs a miss, in which case we indicate what the closest station is, its coordinates and the distance to it from the click.", + "", + "In order to get interactive plot windows that support event handling, we must restart the kernel and activate pylab but *not* in `inline` mode." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "%pylab" + ], + "language": "python", + "outputs": [], + "prompt_number": 1 + }, + { + "cell_type": "code", + "collapsed": true, + "input": [ + "import sys", + "import numpy as np", + "import matplotlib.pyplot as plt" + ], + "language": "python", + "outputs": [], + "prompt_number": 4 + }, + { + "cell_type": "markdown", + "source": [ + "We quickly reload the data using the same approach as in the previous exercise" + ] + }, + { + "cell_type": "code", + "collapsed": true, + "input": [ + "# Data descriptor to make a proper array.", + "dt = [('station','S4'), ('lat',np.float32), ('lon',np.float32), ('elev',np.float32) ]", + "data_fname = os.path.join('data', 'stations.txt')", + "tab = np.loadtxt(data_fname, dt).view(np.recarray)" + ], + "language": "python", + "outputs": [], + "prompt_number": 2 + }, + { + "cell_type": "markdown", + "source": [ + "We start by defining our `StationPicker` object that will do the job:" + ] + }, + { + "cell_type": "code", + "collapsed": true, + "input": [ + "class StationPicker(object):", + " def __init__(self, figure, stations, eps=0.10, axis=None):", + " self.figure = figure", + " self.stations = stations", + " self.cid = figure.canvas.mpl_connect('button_press_event', self)", + " if axis is None:", + " axis = figure.axes[0]", + " self.axis = axis", + " self.eps = eps", + "", + " def __call__(self, event):", + " #print 'click', event # dbg", + " if event.inaxes != self.axis:", + " return", + " self.figure.canvas.draw()", + " # Compute the distance from the click to all stations", + " lats = self.stations['lat']", + " longs = self.stations['lon']", + " click_lat, click_long = event.xdata, event.ydata", + " lat_d = lats - click_lat", + " lon_d = longs - click_long", + " dist = np.sqrt(lat_d**2 + lon_d**2)", + " nearest_i = dist.argmin()", + " near_dist = dist[nearest_i]", + " nearest = self.stations[nearest_i]", + " #print 'Nearest distance:', near_dist # dbg", + " if near_dist < self.eps:", + " print \"HIT! You clicked on\", nearest['station']", + " else:", + " print \"No hit, nearest is:\", nearest['station']", + " print \"It is at:\", nearest['lat'], nearest['lon']", + " print \"Distance to it:\", near_dist", + " sys.stdout.flush()" + ], + "language": "python", + "outputs": [], + "prompt_number": 5 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "fig, ax = plt.subplots()", + "ax.scatter(tab['lat'], tab['lon'], 40*(tab['elev']+1), c=tab['elev'] )", + "# We can now make a picker with that binds the figure and the data", + "StationPicker(fig, tab)" + ], + "language": "python", + "outputs": [], + "prompt_number": 13 + }, + { + "cell_type": "code", + "collapsed": true, + "input": [], + "language": "python", + "outputs": [] + } + ] + } + ] +} \ No newline at end of file diff --git a/matplotlib_beyond_basics.ipynb b/matplotlib_beyond_basics.ipynb new file mode 100644 index 0000000..2d24ab7 --- /dev/null +++ b/matplotlib_beyond_basics.ipynb @@ -0,0 +1,1154 @@ +{ + "metadata": { + "name": "matplotlib_beyond_basics" + }, + "nbformat": 2, + "worksheets": [ + { + "cells": [ + { + "cell_type": "markdown", + "source": [ + " Matplotlib: Beyond the basics", + "===============================", + "", + "Status and plan for today", + "=========================", + "", + "By now you know the basics of:", + "", + "- Numpy array creation and manipulation.", + "- Display of data in numpy arrays, sufficient for interactive exploratory work.", + "", + "Hopefully after this week you will:", + "", + "- Know how to polish those figures to the point where they can go to a journal.", + "- Understand matplotlib's internal model enough to:", + " - know where to look for knobs to fine-tune", + " - better understand the help and examples online", + " - use it as a development platform for complex visualization", + "", + "" + ] + }, + { + "cell_type": "markdown", + "source": [ + "Matplotlib's main APIs: ``pyplot`` and object-oriented", + "======================================================", + "", + "Matplotlib is a library that can be thought of as having two main ways of being", + "used:", + "", + "- via ``pyplot`` calls, as a high-level, matlab-like library that automatically", + " manages details like figure creation.", + "", + "- via its internal object-oriented structure, that offers full control over all", + " aspects of the figure, at the cost of slightly more verbose calls for the", + " common case.", + "", + "The pyplot api:", + "", + "- Easiest to use.", + "- Sufficient for simple and moderately complex plots.", + "- Does not offer complete control over all details.", + "", + "Before we look at our first simple example, we must activate pylab support in the notebook, leave only one option below uncommented and execute the cell:" + ] + }, + { + "cell_type": "code", + "collapsed": true, + "input": [ + "#%pylab # use this for floating figures", + "%pylab inline # use this for inlined figures" + ], + "language": "python", + "outputs": [] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "x = np.linspace(0, 2*np.pi)", + "y = np.sin(x)", + "plt.plot(x,y, label='sin(x)')", + "plt.legend()", + "plt.title('Harmonic')", + "plt.xlabel('x')", + "plt.ylabel('y')", + "", + "# Add one line to that plot", + "z = np.cos(x)", + "plt.plot(x, z, label='cos(x)')", + "", + "# Make a second figure with a simple plot", + "plt.figure()", + "plt.plot(x, np.sin(2*x), label='sin(2x)')", + "plt.legend()" + ], + "language": "python", + "outputs": [], + "prompt_number": 1 + }, + { + "cell_type": "markdown", + "source": [ + "Here is how to create the same two plots, using explicit management of the figure and axis objects:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "f, ax = plt.subplots() # we manually make a figure and axis", + "ax.plot(x,y, label='sin(x)') # it's the axis who plots", + "ax.legend()", + "ax.set_title('Harmonic') # we set the title on the axis", + "ax.set_xlabel('x') # same with labels", + "ax.set_ylabel('y')", + "", + "# Make a second figure with a simple plot. We can name the figure with a", + "# different variable name as well as its axes, and then control each", + "f1, ax1 = plt.subplots()", + "ax1.plot(x, np.sin(2*x), label='sin(2x)')", + "ax1.legend()", + "", + "# Since we now have variables for each axis, we can add back to the first", + "# figure even after making the second", + "ax.plot(x, z, label='cos(x)')" + ], + "language": "python", + "outputs": [], + "prompt_number": 2 + }, + { + "cell_type": "markdown", + "source": [ + "It\u2019s important to understand the existence of these objects, even if you use mostly the top-level pyplot calls most of the time. Many things can be accomplished in MPL with mostly pyplot and a little bit of tweaking of the underlying objects. We\u2019ll revisit the object-oriented API later.", + "", + "Important commands to know about, and which matplotlib uses internally a lot:", + "", + " gcf() # get current figure", + " gca() # get current axis" + ] + }, + { + "cell_type": "markdown", + "source": [ + "Making subplots", + "===============", + "", + "The simplest command is:", + "", + " f, ax = plt.subplots()", + "", + "which is equivalent to:", + "", + " f = plt.figure()", + " ax = f.add_subplot(111)", + "", + "By passing arguments to `subplots`, you can easily create a regular plot grid:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "x = np.linspace(0, 2*np.pi, 400)", + "y = np.sin(x**2)", + "", + "# Just a figure and one subplot", + "f, ax = plt.subplots()", + "ax.plot(x, y)", + "ax.set_title('Simple plot')", + "", + "# Two subplots, unpack the output array immediately", + "f, (ax1, ax2) = plt.subplots(1, 2, sharey=True)", + "ax1.plot(x, y)", + "ax2.scatter(x, y)", + "", + "# Put a figure-level title", + "f.suptitle('Sharing Y axis')" + ], + "language": "python", + "outputs": [], + "prompt_number": 3 + }, + { + "cell_type": "markdown", + "source": [ + "And finally, an arbitrarily complex grid can be made with ``subplot2grid``:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "f = plt.figure()", + "ax1 = plt.subplot2grid((3,3), (0,0), colspan=3)", + "ax2 = plt.subplot2grid((3,3), (1,0), colspan=2)", + "ax3 = plt.subplot2grid((3,3), (1, 2), rowspan=2)", + "ax4 = plt.subplot2grid((3,3), (2, 0))", + "ax5 = plt.subplot2grid((3,3), (2, 1))", + "", + "# Let's turn off visibility of all tick labels here", + "for ax in f.axes:", + " for t in ax.get_xticklabels()+ax.get_yticklabels():", + " t.set_visible(False)", + "", + "# And add a figure-level title at the top", + "f.suptitle('Subplot2grid')" + ], + "language": "python", + "outputs": [], + "prompt_number": 4 + }, + { + "cell_type": "markdown", + "source": [ + "Manipulating properties across matplotlib", + "=========================================", + "", + "In matplotlib, most properties for lines, colors, etc, can be set directly in", + "the call:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "plt.plot([1,2,3], linestyle='--', color='r')" + ], + "language": "python", + "outputs": [], + "prompt_number": 5 + }, + { + "cell_type": "markdown", + "source": [ + "But for finer control you can get a hold of the returned line object (more on", + "these objects later)::", + "", + " In [1]: line, = plot([1,2,3])", + "", + "These line objects have a lot of properties you can control, a full list is", + "seen here by tab-completing in IPython::", + "", + " In [2]: line.set", + " line.set line.set_drawstyle line.set_mec", + " line.set_aa line.set_figure line.set_mew", + " line.set_agg_filter line.set_fillstyle line.set_mfc", + " line.set_alpha line.set_gid line.set_mfcalt", + " line.set_animated line.set_label line.set_ms", + " line.set_antialiased line.set_linestyle line.set_picker", + " line.set_axes line.set_linewidth line.set_pickradius", + " line.set_c line.set_lod line.set_rasterized", + " line.set_clip_box line.set_ls line.set_snap", + " line.set_clip_on line.set_lw line.set_solid_capstyle", + " line.set_clip_path line.set_marker line.set_solid_joinstyle", + " line.set_color line.set_markeredgecolor line.set_transform", + " line.set_contains line.set_markeredgewidth line.set_url", + " line.set_dash_capstyle line.set_markerfacecolor line.set_visible", + " line.set_dashes line.set_markerfacecoloralt line.set_xdata", + " line.set_dash_joinstyle line.set_markersize line.set_ydata", + " line.set_data line.set_markevery line.set_zorder", + " ", + "", + "But the ``setp`` call (short for set property) can be very useful, especially", + "while working interactively because it contains introspection support, so you", + "can learn about the valid calls as you work::", + "", + " In [7]: line, = plot([1,2,3])", + "", + " In [8]: setp(line, 'linestyle')", + " linestyle: [ ``'-'`` | ``'--'`` | ``'-.'`` | ``':'`` | ``'None'`` | ``' '`` | ``''`` ] and any drawstyle in combination with a linestyle, e.g. ``'steps--'``. ", + "", + " In [9]: setp(line)", + " agg_filter: unknown", + " alpha: float (0.0 transparent through 1.0 opaque) ", + " animated: [True | False] ", + " antialiased or aa: [True | False]", + " ...", + " ... much more output elided", + " ...", + "", + "In the first form, it shows you the valid values for the 'linestyle' property,", + "and in the second it shows you all the acceptable properties you can set on the", + "line object. This makes it very easy to discover how to customize your figures", + "to get the visual results you need.", + "", + "Furthermore, setp can manipulate multiple objects at a time:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "x = linspace(0, 2*pi)", + "y1 = sin(x)", + "y2 = sin(2*x)", + "lines = plt.plot(x, y1, x, y2)", + "", + "# We will set the width and color of all lines in the figure at once:", + "plt.setp(lines, linewidth=2, color='r')" + ], + "language": "python", + "outputs": [], + "prompt_number": 6 + }, + { + "cell_type": "markdown", + "source": [ + "Finally, if you know what properties you want to set on a specific object, a", + "plain ``set`` call is typically the simplest form:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "line, = plt.plot([1,2,3])", + "line.set(lw=2, c='red',ls='--')" + ], + "language": "python", + "outputs": [], + "prompt_number": 7 + }, + { + "cell_type": "markdown", + "source": [ + "Understanding what matplotlib returns: lines, axes and figures", + "==============================================================", + "", + "Lines", + "-----", + "", + "In a simple plot:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "plt.plot([1,2,3])" + ], + "language": "python", + "outputs": [], + "prompt_number": 8 + }, + { + "cell_type": "markdown", + "source": [ + "The return value of the plot call is a list of lines, which can be manipulated", + "further. If you capture the line object (in this case it's a single line so we", + "use a one-element tuple):" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "line, = plt.plot([1,2,3])", + "line.set_color('r')" + ], + "language": "python", + "outputs": [], + "prompt_number": 11 + }, + { + "cell_type": "markdown", + "source": [ + "One line property that is particularly useful to be aware of is ``set_data``:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "# Create a plot and hold the line object", + "line, = plt.plot([1,2,3], label='my data')", + "plt.grid()", + "plt.title('My title')", + "", + "# ... later, we may want to modify the x/y data but keeping the rest of the", + "# figure intact, with our new data:", + "x = np.linspace(0, 1)", + "y = x**2", + "", + "# This can be done by operating on the data object itself", + "line.set_data(x, y)", + "", + "# Now we must set the axis limits manually. Note that we can also use xlim", + "# and ylim to set the x/y limits separately.", + "plt.axis([0,1,0,1])", + "", + "# Note, alternatively this can be done with:", + "ax = plt.gca() # get currently active axis object", + "ax.relim()", + "ax.autoscale_view()", + "", + "# as well as requesting matplotlib to draw", + "plt.draw()" + ], + "language": "python", + "outputs": [], + "prompt_number": 12 + }, + { + "cell_type": "markdown", + "source": [ + "The next important component, axes", + "----------------------------------", + " ", + "The ``axis`` call above was used to set the x/y limits of the axis. And in", + "previous examples we called ``.plot`` directly on axis objects. Axes are the", + "main object that contains a lot of the user-facing functionality of matplotlib::", + "", + " In [15]: f = plt.figure()", + "", + " In [16]: ax = f.add_subplot(111)", + "", + " In [17]: ax.", + " Display all 299 possibilities? (y or n)", + " ax.acorr ax.hitlist", + " ax.add_artist ax.hlines", + " ax.add_callback ax.hold", + " ax.add_collection ax.ignore_existing_data_limits", + " ax.add_line ax.images", + " ax.add_patch ax.imshow", + " ", + " ... etc.", + "", + "Many of the commands in ``plt.`` are nothing but wrappers around axis", + "calls, with machinery to automatically create a figure and add an axis to it if", + "there wasn't one to begin with. The output of most axis actions that draw", + "something is a collection of lines (or other more complex geometric objects)." + ] + }, + { + "cell_type": "markdown", + "source": [ + "Enclosing it all, the figure", + "----------------------------", + "", + "The enclosing object is the ``figure``, that holds all axes::", + "", + " In [17]: f = plt.figure()", + "", + " In [18]: f.add_subplot(211)", + " Out[18]: ", + "", + " In [19]: f.axes", + " Out[19]: []", + "", + " In [20]: f.add_subplot(212)", + " Out[20]: ", + "", + " In [21]: f.axes", + " Out[21]: ", + " [,", + " ]", + "", + "The basic view of matplotlib is: a figure contains one or more axes, axes draw", + "and return collections of one or more geometric objects (lines, patches, etc).", + "", + "For all the gory details on this topic, see the matplotlib [artist tutorial](http://matplotlib.sourceforge.net/users/artists.html)." + ] + }, + { + "cell_type": "markdown", + "source": [ + "Anatomy of a common plot", + "========================", + "", + "Let's make a simple plot that contains a few commonly used decorations" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "f, ax = plt.subplots()", + "", + "# Three simple polyniomials", + "x = np.linspace(-1, 1)", + "y1,y2,y3 = [x**i for i in [1,2,3]]", + "", + "# Plot each with a label (for a legend)", + "ax.plot(x, y1, label='linear')", + "ax.plot(x, y2, label='cuadratic')", + "ax.plot(x, y3, label='cubic')", + "# Make all lines drawn so far thicker", + "plt.setp(ax.lines, linewidth=2)", + "", + "# Add a grid and a legend that doesn't overlap the lines", + "ax.grid(True)", + "ax.legend(loc='lower right')", + "", + "# Add black horizontal and vertical lines through the origin", + "ax.axhline(0, color='black')", + "ax.axvline(0, color='black')", + "", + "# Set main text elements of the plot", + "ax.set_title('Some polynomials')", + "ax.set_xlabel('x')", + "ax.set_ylabel('p(x)')" + ], + "language": "python", + "outputs": [], + "prompt_number": 13 + }, + { + "cell_type": "markdown", + "source": [ + "Common plot types", + "=================", + "", + "Error plots", + "-----------", + "", + "First a very simple error plot" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "# example data", + "x = np.arange(0.1, 4, 0.5)", + "y = np.exp(-x)", + "", + "# example variable error bar values", + "yerr = 0.1 + 0.2*np.sqrt(x)", + "xerr = 0.1 + yerr", + "", + "# First illustrate basic pyplot interface, using defaults where possible.", + "plt.figure()", + "plt.errorbar(x, y, xerr=0.2, yerr=0.4)", + "plt.title(\"Simplest errorbars, 0.2 in x, 0.4 in y\")" + ], + "language": "python", + "outputs": [], + "prompt_number": 14 + }, + { + "cell_type": "markdown", + "source": [ + "Now a more elaborate one, using the OO interface to exercise more features." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "# same data/errors as before", + "x = np.arange(0.1, 4, 0.5)", + "y = np.exp(-x)", + "yerr = 0.1 + 0.2*np.sqrt(x)", + "xerr = 0.1 + yerr", + "", + "fig, axs = plt.subplots(nrows=2, ncols=2)", + "ax = axs[0,0]", + "ax.errorbar(x, y, yerr=yerr, fmt='o')", + "ax.set_title('Vert. symmetric')", + "", + "# With 4 subplots, reduce the number of axis ticks to avoid crowding.", + "ax.locator_params(nbins=4)", + "", + "ax = axs[0,1]", + "ax.errorbar(x, y, xerr=xerr, fmt='o')", + "ax.set_title('Hor. symmetric')", + "", + "ax = axs[1,0]", + "ax.errorbar(x, y, yerr=[yerr, 2*yerr], xerr=[xerr, 2*xerr], fmt='--o')", + "ax.set_title('H, V asymmetric')", + "", + "ax = axs[1,1]", + "ax.set_yscale('log')", + "# Here we have to be careful to keep all y values positive:", + "ylower = np.maximum(1e-2, y - yerr)", + "yerr_lower = y - ylower", + "", + "ax.errorbar(x, y, yerr=[yerr_lower, 2*yerr], xerr=xerr,", + " fmt='o', ecolor='g')", + "ax.set_title('Mixed sym., log y')" + ], + "language": "python", + "outputs": [], + "prompt_number": 15 + }, + { + "cell_type": "markdown", + "source": [ + "Logarithmic plots", + "-----------------", + "", + "A simple log plot" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "x = np.linspace(-5, 5)", + "y = np.exp(-x**2)", + "", + "f, (ax1, ax2) = plt.subplots(2, 1)", + "ax1.plot(x, y)", + "ax2.semilogy(x, y)" + ], + "language": "python", + "outputs": [], + "prompt_number": 16 + }, + { + "cell_type": "markdown", + "source": [ + "A more elaborate log plot using 'symlog', that treats a specified range as", + "linear (thus handling values near zero) and symmetrizes negative values:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "x = np.linspace(-50, 50, 100)", + "y = np.linspace(0, 100, 100)", + "", + "# Create the figure and axes", + "f, (ax1, ax2, ax3) = plt.subplots(3, 1)", + "", + "# Symlog on the x axis", + "ax1.plot(x, y)", + "ax1.set_xscale('symlog')", + "ax1.set_ylabel('symlogx')", + "# Grid for both axes", + "ax1.grid(True)", + "# Minor grid on too for x", + "ax1.xaxis.grid(True, which='minor')", + "", + "# Symlog on the y axis", + "ax2.plot(y, x)", + "ax2.set_yscale('symlog')", + "ax2.set_ylabel('symlogy')", + "", + "# Symlog on both", + "ax3.plot(x, np.sin(x / 3.0))", + "ax3.set_xscale('symlog')", + "ax3.set_yscale('symlog')", + "ax3.grid(True)", + "ax3.set_ylabel('symlog both')" + ], + "language": "python", + "outputs": [], + "prompt_number": 17 + }, + { + "cell_type": "markdown", + "source": [ + "Bar plots", + "---------" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "# a bar plot with errorbars", + "import numpy as np", + "import matplotlib.pyplot as plt", + "", + "N = 5", + "menMeans = (20, 35, 30, 31, 27)", + "menStd = (2, 3, 4, 1, 2)", + "", + "ind = np.arange(N) # the x locations for the groups", + "width = 0.35 # the width of the bars", + "", + "fig = plt.figure()", + "ax = fig.add_subplot(111)", + "rects1 = ax.bar(ind, menMeans, width, color='r', yerr=menStd)", + "", + "womenMeans = (25, 32, 34, 21, 29)", + "womenStd = (3, 5, 2, 3, 3)", + "rects2 = ax.bar(ind+width, womenMeans, width, color='y', yerr=womenStd)", + "", + "# add some", + "ax.set_ylabel('Scores')", + "ax.set_title('Scores by group and gender')", + "ax.set_xticks(ind+width)", + "ax.set_xticklabels( ('G1', 'G2', 'G3', 'G4', 'G5') )", + "", + "ax.legend( (rects1[0], rects2[0]), ('Men', 'Women') )" + ], + "language": "python", + "outputs": [], + "prompt_number": 19 + }, + { + "cell_type": "markdown", + "source": [ + "Scatter plots", + "-------------", + "", + "The ``scatter`` command produces scatter plots with arbitrary markers." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "from matplotlib import cm", + "", + "t = linspace(0.0, 6*pi, 100)", + "y = exp(-0.1*t)*cos(t)", + "phase = t % 2*pi", + "f = plt.figure()", + "ax = f.add_subplot(111)", + "ax.scatter(t, y, s=100*abs(y), c=phase, cmap=cm.jet)", + "ax.set_ylim(-1,1)", + "ax.grid()", + "ax.axhline(0, color='k')" + ], + "language": "python", + "outputs": [], + "prompt_number": 20 + }, + { + "cell_type": "markdown", + "source": [ + "
", + " ", + "Exercise", + "--------", + "", + "Consider you have the following data in a text file (The file `data/stations.txt` contains the full dataset):", + "", + " # Station Lat Long Elev ", + " BIRA 26.4840 87.2670 0.0120", + " BUNG 27.8771 85.8909 1.1910", + " GAIG 26.8380 86.6318 0.1660", + " HILE 27.0482 87.3242 2.0880", + " ... etc.", + " ", + " ", + "These are the names of seismographic stations in the Himalaya, with their coordinates and elevations in Kilometers.", + "", + "1. Make a scatter plot of all of these, using both the size and the color to (redundantly) encode elevation. Label each station by its 4-letter code, and add a colorbar on the right that shows the color-elevation map.", + " ", + "2. If you have the basemap toolkit installed, repeat the same exercise but draw a grid with parallels and meridians, add rivers in cyan and country boundaries in yellow. Also, draw the background using the NASA BlueMarble image of Earth.", + "", + " ", + "**Tips**", + " ", + "* You can check whether you have Basemap installed with:", + " ", + " from mpl_toolkits.basemap import Basemap", + " ", + "* For the basemap part, choose a text label color that provides adequate reading contrast over the image background.", + " ", + "* Create your Basemap with 'i' resolution, otherwise it will take forever to draw." + ] + }, + { + "cell_type": "markdown", + "source": [ + "Histograms", + "----------", + "", + "Matplotlib has a built-in command for histograms." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "mu, sigma = 100, 15", + "x = mu + sigma * np.random.randn(10000)", + "", + "# the histogram of the data", + "n, bins, patches = plt.hist(x, 50, normed=1, facecolor='g', alpha=0.75)", + "", + "plt.xlabel('Smarts')", + "plt.ylabel('Probability')", + "plt.title('Histogram of IQ')", + "plt.text(60, .025, r'$\\mu=100,\\ \\sigma=15$')", + "plt.axis([40, 160, 0, 0.03])", + "plt.grid(True)" + ], + "language": "python", + "outputs": [], + "prompt_number": 21 + }, + { + "cell_type": "markdown", + "source": [ + "Aribitrary text and LaTeX support", + "=================================", + "", + "In matplotlib, text can be added either relative to an individual axis object", + "or to the whole figure.", + "", + "These commands add text to the Axes:", + "", + "- title() - add a title", + "- xlabel() - add an axis label to the x-axis", + "- ylabel() - add an axis label to the y-axis", + "- text() - add text at an arbitrary location", + "- annotate() - add an annotation, with optional arrow", + "", + "And these act on the whole figure:", + "", + "- figtext() - add text at an arbitrary location", + "- suptitle() - add a title", + "", + "And any text field can contain LaTeX expressions for mathematics, as long as", + "they are enclosed in ``$`` signs.", + "", + "This example illustrates all of them:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "fig = plt.figure()", + "fig.suptitle('bold figure suptitle', fontsize=14, fontweight='bold')", + "", + "ax = fig.add_subplot(111)", + "fig.subplots_adjust(top=0.85)", + "ax.set_title('axes title')", + "", + "ax.set_xlabel('xlabel')", + "ax.set_ylabel('ylabel')", + "", + "ax.text(3, 8, 'boxed italics text in data coords', style='italic',", + " bbox={'facecolor':'red', 'alpha':0.5, 'pad':10})", + "", + "ax.text(2, 6, r'an equation: $E=mc^2$', fontsize=15)", + "", + "ax.text(3, 2, unicode('unicode: Institut f\\374r Festk\\366rperphysik',", + " 'latin-1'))", + "", + "ax.text(0.95, 0.01, 'colored text in axes coords',", + " verticalalignment='bottom', horizontalalignment='right',", + " transform=ax.transAxes,", + " color='green', fontsize=15)", + "", + "", + "ax.plot([2], [1], 'o')", + "ax.annotate('annotate', xy=(2, 1), xytext=(3, 4),", + " arrowprops=dict(facecolor='black', shrink=0.05))", + "", + "ax.axis([0, 10, 0, 10])" + ], + "language": "python", + "outputs": [], + "prompt_number": 22 + }, + { + "cell_type": "markdown", + "source": [ + "Axis sharing", + "============", + "", + "The simplest way to share axes is to use the ``subplots`` function. More", + "fine-grained control can be obtained by individually adding subplots and adding", + "share calls to those, but in most cases the functionality from ``subplots`` is sufficient:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "# Simple data to display in various forms", + "x = np.linspace(0, 2*np.pi, 400)", + "y = np.sin(x**2)", + "", + "# Two subplots, the axes array is 1-d", + "f, axarr = plt.subplots(2, sharex=True)", + "f.suptitle('Sharing X axis')", + "axarr[0].plot(x, y)", + "axarr[1].scatter(x, y)", + "", + "# Two subplots, unpack the axes array immediately", + "f, (ax1, ax2) = plt.subplots(1, 2, sharey=True)", + "f.suptitle('Sharing Y axis')", + "ax1.plot(x, y)", + "ax2.scatter(x, y)", + "", + "# Three subplots sharing both x/y axes", + "f, (ax1, ax2, ax3) = plt.subplots(3, sharex=True, sharey=True)", + "f.suptitle('Sharing both axes')", + "ax1.plot(x, y)", + "ax2.scatter(x, y)", + "ax3.scatter(x, 2*y**2-1,color='r')", + "# Fine-tune figure; make subplots close to each other and hide x ticks for", + "# all but bottom plot.", + "f.subplots_adjust(hspace=0)", + "plt.setp([a.get_xticklabels() for a in f.axes[:-1]], visible=False);" + ], + "language": "python", + "outputs": [], + "prompt_number": 24 + }, + { + "cell_type": "markdown", + "source": [ + "Basic event handling", + "====================", + "", + "Matplotlib has a builtin, toolkit-independent event model that is fairly rich.", + "If you want to develop full-fledged applications with very complex and fast", + "interactions, you are likely better off choosing a specific Graphical User", + "Interface (GUI) toolkit and using its specific event model. But for many", + "scientific uses, what matplotlib offers is more than sufficient, and it has the", + "advantage of working identically regardless of the GUI toolkit you choose to", + "run matplotlib under.", + "", + "Here we will cover the bare essentials only, for full details you should", + "consult the `event handling section`_ of the matplotlib user guide.", + "", + ".. _event handling section: http://matplotlib.sourceforge.net/users/event_handling.html", + "", + "The basic idea of *all* event handling is always the same: the windowing", + "environment registers an event (mouse movement, click, keyboard press, etc)", + "produced by the user. In advance, you have registered *event handlers*:", + "functions you define that are meant to be called when specific types of events", + "occur. The registration action is called *connecting* the event handler, and", + "is performed by the ``mpl_connect`` method of the figure canvas attribute (the", + "canvas is the drawing area of the figure object, the entire raw object where", + "events take place).", + "", + "The windowing system will then pass the event (each event has some relevant", + "information that goes with it, such as which key or button was pressed) to your", + "function, which can act on it. These functions are referred to as *callbacks*,", + "because they are meant to be 'called back' not by you, but by the windowing", + "toolkit when the right event goes by.", + "", + "Here is the simplest possible matplotlib event handler::" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "fig, ax = plt.subplots()", + "ax.plot(np.random.rand(10))", + "", + "def onclick(event):", + " print 'button=%d, x=%d, y=%d, xdata=%f, ydata=%f'%(", + " event.button, event.x, event.y, event.xdata, event.ydata)", + "", + "cid = fig.canvas.mpl_connect('button_press_event', onclick)" + ], + "language": "python", + "outputs": [], + "prompt_number": 25 + }, + { + "cell_type": "markdown", + "source": [ + "The ``FigureCanvas`` method ``mpl_connect`` returns a connection id which", + "is simply an integer. When you want to disconnect the callback, just call::", + "", + " fig.canvas.mpl_disconnect(cid)", + "", + "The most commonly used event types are ``KeyEvent`` and ``MouseEvent``, both of", + "which have the following attributes:", + "", + " ``x``", + " x position - pixels from left of canvas", + "", + " ``y``", + " y position - pixels from bottom of canvas", + "", + " ``inaxes``", + " the ``matplotlib.axes.Axes`` instance if mouse is over axes", + "", + " ``xdata``", + " x coord of mouse in data coords", + "", + " ``ydata``", + " y coord of mouse in data coords", + "", + "In addition, ``MouseEvent`` have:", + "", + " ``button``", + " button pressed None, 1, 2, 3, 'up', 'down' (up and down are used for", + " scroll events)", + "", + " ``key``", + " the key pressed: None, any character, 'shift', 'win', or 'control'" + ] + }, + { + "cell_type": "markdown", + "source": [ + "
", + "", + "Exercise", + "--------", + "", + "Extend the scatter plot exercise above with the seismic stations, to print the location (four-letter string) of the station you click on. Use a threshold for distance, and discriminate between a click below threshold (considered to be 'on') vs a miss, in which case you should indicate what the closest station is, its coordinates and the distance to it from the click." + ] + }, + { + "cell_type": "markdown", + "source": [ + "Image display", + "=============", + "", + "The ``imshow`` command can display single or multi-channel images. A simple", + "array of random numbers, plotted in grayscale:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "from matplotlib import cm", + "plt.imshow(np.random.rand(128, 128), cmap=cm.gray, interpolation='nearest')" + ], + "language": "python", + "outputs": [], + "prompt_number": 26 + }, + { + "cell_type": "markdown", + "source": [ + "A real photograph is a multichannel image, `imshow` interprets it correctly:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "img = plt.imread('data/stained_glass_barcelona.png')", + "plt.imshow(img)" + ], + "language": "python", + "outputs": [], + "prompt_number": 27 + }, + { + "cell_type": "markdown", + "source": [ + "
", + " ", + "Exercise", + "--------", + "", + "Write a notebook where you can load an image and then perform the following operations on it:", + " ", + "1. Create a figure with four plots that show both the full-color image and color channel of the image with the right colormap for that color. Ensure that the axes are linked so zooming in one image zooms the same region in the others.", + " ", + "2. Compute a luminosity and per-channel histogram and display all four histograms in one figure, giving each a separate plot (hint: a 4x1 plot works best for this). Link the appropriate axes together.", + " ", + "3. Create a black-and-white (or more precisely, grayscale) version of the image. Compare the results from a naive average of all three channels with that of a model that uses 30% red, 59% green and 11% blue, by displaying all three (full color and both grayscales) side by side with linked axes for zooming.", + " ", + "Hint: look for the matplotlib image tutorial." + ] + }, + { + "cell_type": "markdown", + "source": [ + "Simple 3d plotting with matplotlib", + "==================================", + "", + "Note that you must execute at least once in your session::" + ] + }, + { + "cell_type": "code", + "collapsed": true, + "input": [ + "from mpl_toolkits.mplot3d import Axes3D" + ], + "language": "python", + "outputs": [], + "prompt_number": 28 + }, + { + "cell_type": "markdown", + "source": [ + "One this has been done, you can create 3d axes with the ``projection='3d'`` keyword to ``add_subplot``::", + "", + " fig = plt.figure()", + " fig.add_subplot(, projection='3d')" + ] + }, + { + "cell_type": "markdown", + "source": [ + "A simple surface plot:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "from mpl_toolkits.mplot3d.axes3d import Axes3D", + "from matplotlib import cm", + "", + "fig = plt.figure()", + "ax = fig.add_subplot(1, 1, 1, projection='3d')", + "X = np.arange(-5, 5, 0.25)", + "Y = np.arange(-5, 5, 0.25)", + "X, Y = np.meshgrid(X, Y)", + "R = np.sqrt(X**2 + Y**2)", + "Z = np.sin(R)", + "surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.jet,", + " linewidth=0, antialiased=False)", + "ax.set_zlim3d(-1.01, 1.01)" + ], + "language": "python", + "outputs": [], + "prompt_number": 29 + }, + { + "cell_type": "markdown", + "source": [ + "And a parametric surface specified in cylindrical coordinates:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "matplotlib.rcParams['legend.fontsize'] = 10", + "", + "fig = plt.figure()", + "ax = fig.add_subplot(111, projection='3d')", + "theta = np.linspace(-4*np.pi, 4*np.pi, 100)", + "z = np.linspace(-2, 2, 100)", + "r = z**2 + 1", + "x = r*np.sin(theta)", + "y = r*np.cos(theta)", + "ax.plot(x, y, z, label='parametric curve')", + "ax.legend()" + ], + "language": "python", + "outputs": [], + "prompt_number": 30 + }, + { + "cell_type": "code", + "collapsed": true, + "input": [], + "language": "python", + "outputs": [] + } + ] + } + ] +} \ No newline at end of file diff --git a/mayavi_quicktour.ipynb b/mayavi_quicktour.ipynb new file mode 100644 index 0000000..63cbc2b --- /dev/null +++ b/mayavi_quicktour.ipynb @@ -0,0 +1,305 @@ +{ + "metadata": { + "name": "mayavi_quicktour" + }, + "nbformat": 2, + "worksheets": [ + { + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# A few simple Mayavi examples", + "", + "These are all taken from the excellent [Mayavi documentation](http://github.enthought.com/mayavi/mayavi/auto/examples.html)." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "%pylab wx" + ], + "language": "python", + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "", + "Welcome to pylab, a matplotlib-based Python environment [backend: WXAgg].", + "For more information, type 'help(pylab)'." + ] + } + ], + "prompt_number": 1 + }, + { + "cell_type": "markdown", + "source": [ + "## Line plot" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "import numpy", + "from mayavi.mlab import *", + "", + "def test_plot3d():", + " \"\"\"Generates a pretty set of lines.\"\"\"", + " n_mer, n_long = 6, 11", + " pi = numpy.pi", + " dphi = pi/1000.0", + " phi = numpy.arange(0.0, 2*pi + 0.5*dphi, dphi)", + " mu = phi*n_mer", + " x = numpy.cos(mu)*(1+numpy.cos(n_long*mu/n_mer)*0.5)", + " y = numpy.sin(mu)*(1+numpy.cos(n_long*mu/n_mer)*0.5)", + " z = numpy.sin(n_long*mu/n_mer)*0.5", + "", + " l = plot3d(x, y, z, numpy.sin(mu), tube_radius=0.025, colormap='Spectral')", + " return l", + "", + "test_plot3d()" + ], + "language": "python", + "outputs": [ + { + "output_type": "pyout", + "prompt_number": 19, + "text": [ + "" + ] + } + ], + "prompt_number": 19 + }, + { + "cell_type": "markdown", + "source": [ + "## Point plot" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "import numpy", + "from mayavi.mlab import *", + "", + "def test_points3d():", + " t = numpy.linspace(0, 4*numpy.pi, 20)", + " cos = numpy.cos", + " sin = numpy.sin", + "", + " x = sin(2*t)", + " y = cos(t)", + " z = cos(2*t)", + " s = 2+sin(t)", + "", + " return points3d(x, y, z, s, colormap=\"copper\", scale_factor=.25)", + "", + "test_points3d()" + ], + "language": "python", + "outputs": [ + { + "output_type": "pyout", + "prompt_number": 15, + "text": [ + "" + ] + } + ], + "prompt_number": 15 + }, + { + "cell_type": "markdown", + "source": [ + "## Simple surfaces" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "import numpy", + "from mayavi.mlab import *", + "", + "def test_surf():", + " \"\"\"Test surf on regularly spaced co-ordinates like MayaVi.\"\"\"", + " def f(x, y):", + " sin, cos = numpy.sin, numpy.cos", + " return sin(x+y) + sin(2*x - y) + cos(3*x+4*y)", + "", + " x, y = numpy.mgrid[-7.:7.05:0.1, -5.:5.05:0.05]", + " s = surf(x, y, f)", + " #cs = contour_surf(x, y, f, contour_z=0)", + " return s", + "", + "test_surf()" + ], + "language": "python", + "outputs": [ + { + "output_type": "pyout", + "prompt_number": 17, + "text": [ + "" + ] + } + ], + "prompt_number": 17 + }, + { + "cell_type": "markdown", + "source": [ + "## Images" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "import numpy", + "from mayavi.mlab import *", + "", + "def test_imshow():", + " \"\"\" Use imshow to visualize a 2D 10x10 random array.", + " \"\"\"", + " s = numpy.random.random((10,10))", + " return imshow(s, colormap='gist_earth')", + "", + "test_imshow()" + ], + "language": "python", + "outputs": [ + { + "output_type": "pyout", + "prompt_number": 12, + "text": [ + "" + ] + } + ], + "prompt_number": 12 + }, + { + "cell_type": "markdown", + "source": [ + "## Flow" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "import numpy", + "from mayavi.mlab import *", + "", + "def test_flow():", + " x, y, z = numpy.mgrid[0:5, 0:5, 0:5]", + " r = numpy.sqrt(x**2 + y**2 + z**4)", + " u = y*numpy.sin(r)/r", + " v = -x*numpy.sin(r)/r", + " w = numpy.zeros_like(z)", + " obj = flow(u, v, w)", + " return obj", + "", + "test_flow()" + ], + "language": "python", + "outputs": [ + { + "output_type": "pyout", + "prompt_number": 18, + "text": [ + "" + ] + } + ], + "prompt_number": 18 + }, + { + "cell_type": "markdown", + "source": [ + "### The Lorenz attractor" + ] + }, + { + "cell_type": "code", + "collapsed": true, + "input": [ + "%loadpy http://github.enthought.com/mayavi/mayavi/_downloads/lorenz.py" + ], + "language": "python", + "outputs": [], + "prompt_number": 3 + }, + { + "cell_type": "code", + "collapsed": true, + "input": [ + "\"\"\"", + "An example displaying the trajectories for the Lorenz system of", + "equations along with the z-nullcline.", + "", + "The vector field of the Lorenz system flow is integrated to display", + "trajectories using mlab's flow function:", + ":func:`mayavi.mlab.flow`.", + "", + "The z-nullcline is plotted by extracting the z component of the vector", + "field data source with the ExtractVectorComponent filter, and applying", + "an IsoSurface module on this scalar component.", + "\"\"\"", + "# Author: Prabhu Ramachandran ", + "# Copyright (c) 2008-2009, Enthought, Inc.", + "# License: BSD Style.", + "", + "import numpy", + "from mayavi import mlab", + "", + "def lorenz(x, y, z, s=10.,r=28., b=8./3.):", + " \"\"\"The Lorenz system.\"\"\"", + " u = s*(y-x)", + " v = r*x -y - x*z", + " w = x*y - b*z", + " return u, v, w", + "", + "# Sample the space in an interesting region.", + "x, y, z = numpy.mgrid[-50:50:100j,-50:50:100j,-10:60:70j]", + "u, v, w = lorenz(x, y, z)", + "fig = mlab.figure(size=(400, 300), bgcolor=(0, 0, 0))", + "", + "# Plot the flow of trajectories with suitable parameters.", + "f = mlab.flow(x, y, z, u, v, w, line_width=3, colormap='Paired')", + "f.module_manager.scalar_lut_manager.reverse_lut = True", + "f.stream_tracer.integration_direction = 'both'", + "f.stream_tracer.maximum_propagation = 200", + "# Uncomment the following line if you want to hide the seed:", + "#f.seed.widget.enabled = False", + "", + "# Extract the z-velocity from the vectors and plot the 0 level set", + "# hence producing the z-nullcline.", + "src = f.mlab_source.m_data", + "e = mlab.pipeline.extract_vector_components(src)", + "e.component = 'z-component'", + "zc = mlab.pipeline.iso_surface(e, opacity=0.5, contours=[0,],", + " color=(0.6, 1, 0.2))", + "# When using transparency, hiding 'backface' triangles often gives better", + "# results", + "zc.actor.property.backface_culling = True", + "", + "# A nice view of the plot.", + "mlab.view(140, 120, 113, [0.65, 1.5, 27])", + "mlab.show()" + ], + "language": "python", + "outputs": [], + "prompt_number": 4 + } + ] + } + ] +} \ No newline at end of file diff --git a/understanding_images.ipynb b/understanding_images.ipynb new file mode 100644 index 0000000..a9470cd --- /dev/null +++ b/understanding_images.ipynb @@ -0,0 +1,262 @@ +{ + "metadata": { + "name": "understanding_images" + }, + "nbformat": 2, + "worksheets": [ + { + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# Understanding the structure of digital images", + "", + "" + ] + }, + { + "cell_type": "markdown", + "source": [ + "Start by loading libraries we'll need, and we'll set the default figure size to be a little larger" + ] + }, + { + "cell_type": "code", + "collapsed": true, + "input": [ + "#%pylab inline", + "%pylab", + "from matplotlib import cm", + "#plt.rcParams['figure.figsize'] = (8, 8)" + ], + "language": "python", + "outputs": [], + "prompt_number": 2 + }, + { + "cell_type": "markdown", + "source": [ + "Define a function to load images" + ] + }, + { + "cell_type": "code", + "collapsed": true, + "input": [ + "def image_load(fname, max_size=1200):", + " \"\"\"Load an image, downsampling if needed to keep within requested size.", + " \"\"\"", + " img = plt.imread(fname)", + " shape = np.array(img.shape, dtype=float)", + " sample_fac = int(np.ceil((shape/max_size).max()))", + " if sample_fac > 1:", + " new_img = img[::sample_fac, ::sample_fac, ...]", + " print 'Downsampling %sX:'% sample_fac, img.shape, '->', new_img.shape", + " return new_img", + " else:", + " return img" + ], + "language": "python", + "outputs": [], + "prompt_number": 3 + }, + { + "cell_type": "markdown", + "source": [ + "Now we define the file we're going to load and read it as an image" + ] + }, + { + "cell_type": "code", + "collapsed": true, + "input": [ + "fname = 'data/stained_glass_barcelona.png'", + "#fname = 'data/dessert.png'", + "", + "img = image_load(fname)", + "plt.imshow(img)" + ], + "language": "python", + "outputs": [], + "prompt_number": 4 + }, + { + "cell_type": "markdown", + "source": [ + "We can directly display the original file in the notebook" + ] + }, + { + "cell_type": "code", + "collapsed": true, + "input": [ + "from IPython.core.display import Image", + "Image(filename=fname)" + ], + "language": "python", + "outputs": [], + "prompt_number": 5 + }, + { + "cell_type": "markdown", + "source": [ + "Extract each color channel and create a figure with 4 subplots, one for each", + "channel, so we can see its structure clearly.", + "
", + "Display the full color figure and the color channels" + ] + }, + { + "cell_type": "code", + "collapsed": true, + "input": [ + "red, green, blue = [ img[:,:,i] for i in range(3) ]", + "", + "f, axes = plt.subplots(1, 4, sharex=True, sharey=True)", + "", + "axes[0].imshow(img)", + "axes[1].imshow(red, cmap=cm.Reds_r)", + "axes[2].imshow(green, cmap=cm.Greens_r)", + "axes[3].imshow(blue, cmap=cm.Blues_r)", + "", + "# Turn off tick labels", + "for ax in axes:", + " ax.set_xticks([])", + " ax.set_yticks([])", + " ax.set_aspect('auto')" + ], + "language": "python", + "outputs": [], + "prompt_number": 6 + }, + { + "cell_type": "markdown", + "source": [ + "Make a new figure and display luminosity and per-channel histograms" + ] + }, + { + "cell_type": "markdown", + "source": [ + "PNG images sometimes have a 4th transparency channel, sometimes not. To", + "be safe, we generate a luminosity array consisting of only the first 3", + "channels." + ] + }, + { + "cell_type": "code", + "collapsed": true, + "input": [ + "lumi = img[:,:,:3].mean(axis=2)" + ], + "language": "python", + "outputs": [], + "prompt_number": 7 + }, + { + "cell_type": "markdown", + "source": [ + "Now, display a histogram for each channel. Note that jpeg images come", + "back as integer images with a luminosity range of 0..255 while pngs are", + "read as floating point images in the 0..1 range. So we adjust the", + "histogram range accordingly:" + ] + }, + { + "cell_type": "code", + "collapsed": true, + "input": [ + "hrange = (0.0, 1.0) if lumi.max()<=1.0 else (0.0, 255.0)" + ], + "language": "python", + "outputs": [], + "prompt_number": 8 + }, + { + "cell_type": "markdown", + "source": [ + "Display the luminosity and per-channel histograms:" + ] + }, + { + "cell_type": "code", + "collapsed": true, + "input": [ + "f2, axes2 = plt.subplots(4, 1, sharex=True)", + "", + "axes2[0].hist(lumi.flatten(), 256, range=hrange, facecolor='k', edgecolor='k')", + "axes2[1].hist(red.flatten(), 256, range=hrange, facecolor='r', edgecolor='r')", + "axes2[2].hist(green.flatten(), 256, range=hrange, facecolor='g', edgecolor='g')", + "axes2[3].hist(blue.flatten(), 256, range=hrange, facecolor='b', edgecolor='b');", + "f2.subplots_adjust(hspace=0);", + "", + "# We want the x tick labels to be invisible on all but the bottom figure", + "for ax in axes2[:-1]:", + " for label in ax.get_xticklabels():", + " label.set_visible(False)", + "", + "# Don't show the last y label in plots 2-4:", + "for ax in axes2[1:]:", + " ax.get_yticklabels()[-1].set_visible(False)" + ], + "language": "python", + "outputs": [], + "prompt_number": 9 + }, + { + "cell_type": "code", + "collapsed": true, + "input": [ + "imshow(lumi, cmap=cm.Greys_r);" + ], + "language": "python", + "outputs": [], + "prompt_number": 10 + }, + { + "cell_type": "markdown", + "source": [ + "Let's do a slightly different encoding of the color channels: 30% red, 59% green, 11% blue" + ] + }, + { + "cell_type": "code", + "collapsed": true, + "input": [ + "lumi2 = .3*red + .59*green + 0.11*blue", + "", + "fig, axes = plt.subplots(1, 3, figsize=(12, 8), sharex=True, sharey=True)", + "", + "axes[0].imshow(img); axes[0].set_title('Color')", + "axes[1].imshow(lumi, cmap=cm.Greys_r); axes[1].set_title('Naive gray')", + "axes[2].imshow(lumi2, cmap=cm.Greys_r); axes[2].set_title('Better gray')", + "", + "for ax in axes:", + " ax.set_xticks([])", + " ax.set_yticks([])", + " ax.set_aspect('auto')" + ], + "language": "python", + "outputs": [], + "prompt_number": 11 + }, + { + "cell_type": "code", + "collapsed": true, + "input": [], + "language": "python", + "outputs": [], + "prompt_number": 10 + } + ] + } + ] +} \ No newline at end of file