diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 # Matplotlib
 
-[![Build Status](https://img.shields.io/circleci/project/github/abarbu/matplotlib-haskell.svg)](circleci.com/gh/abarbu/matplotlib-haskell)
+[![Build Status](https://img.shields.io/circleci/project/github/abarbu/matplotlib-haskell.svg)](https://circleci.com/gh/abarbu/matplotlib-haskell)
 [![Hackage](https://img.shields.io/hackage/v/matplotlib.svg)](https://hackage.haskell.org/package/matplotlib)
 
 Haskell bindings to Python's Matplotlib. It's high time that Haskell had a
@@ -37,3 +37,122 @@
 ```bash
 cabal install matplotlib
 ```
+
+### Examples
+
+Click on any of the examples below to go to the corresponding test that
+generates it. Depending on your matplotlib version default colors might be
+different.
+
+[![integral][img_integral]][url_integral]
+[![griddata][img_griddata]][url_griddata]
+[![streamplot][img_streamplot]][url_streamplot]
+[![hist2DLog][img_hist2DLog]][url_hist2DLog]
+[![quadratic][img_quadratic]][url_quadratic]
+[![spines][img_spines]][url_spines]
+[![annotation][img_annotation]][url_annotation]
+[![corr][img_corr]][url_corr]
+[![bivariateNormal][img_bivariateNormal]][url_bivariateNormal]
+[![images][img_images]][url_images]
+[![labelled-histogram][img_labelled-histogram]][url_labelled-histogram]
+[![projections][img_projections]][url_projections]
+[![histogram][img_histogram]][url_histogram]
+[![pcolorlog][img_pcolorlog]][url_pcolorlog]
+[![scatter][img_scatter]][url_scatter]
+[![stacked][img_stacked]][url_stacked]
+[![legend][img_legend]][url_legend]
+[![errorbar][img_errorbar]][url_errorbar]
+[![line-options][img_line-options]][url_line-options]
+[![quiver-fancy][img_quiver-fancy]][url_quiver-fancy]
+[![contour][img_contour]][url_contour]
+[![boxplot][img_boxplot]][url_boxplot]
+[![show-matrix][img_show-matrix]][url_show-matrix]
+[![scatterhist][img_scatterhist]][url_scatterhist]
+[![hinton][img_hinton]][url_hinton]
+[![density][img_density]][url_density]
+[![violinplot][img_violinplot]][url_violinplot]
+[![histMulti][img_histMulti]][url_histMulti]
+[![cumulative][img_cumulative]][url_cumulative]
+[![polar][img_polar]][url_polar]
+[![hists][img_hists]][url_hists]
+[![tex][img_tex]][url_tex]
+[![eventplot][img_eventplot]][url_eventplot]
+[![line-function][img_line-function]][url_line-function]
+[![density-bandwidth][img_density-bandwidth]][url_density-bandwidth]
+[![quiver][img_quiver]][url_quiver]
+[![pie][img_pie]][url_pie]
+
+[img_pcolorlog]: https://i.imgur.com/O8hU7Rl.png "pcolorlog"
+[url_pcolorlog]: https://github.com/abarbu/matplotlib-haskell/blob/master/test/Spec.hs#L495
+[img_griddata]: https://i.imgur.com/Lh2xOPf.png "griddata"
+[url_griddata]: https://github.com/abarbu/matplotlib-haskell/blob/master/test/Spec.hs#L602
+[img_streamplot]: https://i.imgur.com/AveIggT.png "streamplot"
+[url_streamplot]: https://github.com/abarbu/matplotlib-haskell/blob/master/test/Spec.hs#L582
+[img_hist2DLog]: https://i.imgur.com/PnPyJzO.png "hist2DLog"
+[url_hist2DLog]: https://github.com/abarbu/matplotlib-haskell/blob/master/test/Spec.hs#L275
+[img_cumulative]: https://i.imgur.com/W9JinZC.png "cumulative"
+[url_cumulative]: https://github.com/abarbu/matplotlib-haskell/blob/master/test/Spec.hs#L217
+[img_eventplot]: https://i.imgur.com/2chP6qg.png "eventplot"
+[url_eventplot]: https://github.com/abarbu/matplotlib-haskell/blob/master/test/Spec.hs#L280
+[img_quiver]: https://i.imgur.com/7G7r9gu.png "quiver"
+[url_quiver]: https://github.com/abarbu/matplotlib-haskell/blob/master/test/Spec.hs#L423
+[img_labelled-histogram]: https://i.imgur.com/cOCIlpy.png "labelled-histogram"
+[url_labelled-histogram]: https://github.com/abarbu/matplotlib-haskell/blob/master/test/Spec.hs#L226
+[img_line-options]: https://i.imgur.com/0Jr83hl.png "line-options"
+[url_line-options]: https://github.com/abarbu/matplotlib-haskell/blob/master/test/Spec.hs#L249
+[img_violinplot]: https://i.imgur.com/MaWL0BD.png "violinplot"
+[url_violinplot]: https://github.com/abarbu/matplotlib-haskell/blob/master/test/Spec.hs#L298
+[img_density]: https://i.imgur.com/v7GoIno.png "density"
+[url_density]: https://github.com/abarbu/matplotlib-haskell/blob/master/test/Spec.hs#L241
+[img_tex]: https://i.imgur.com/liZci2C.png "tex"
+[url_tex]: https://github.com/abarbu/matplotlib-haskell/blob/master/test/Spec.hs#L259
+[img_scatterhist]: https://i.imgur.com/DG3obq8.png "scatterhist"
+[url_scatterhist]: https://github.com/abarbu/matplotlib-haskell/blob/master/test/Spec.hs#L305
+[img_boxplot]: https://i.imgur.com/aaoMEql.png "boxplot"
+[url_boxplot]: https://github.com/abarbu/matplotlib-haskell/blob/master/test/Spec.hs#L292
+[img_histogram]: https://i.imgur.com/yO6dxEO.png "histogram"
+[url_histogram]: https://github.com/abarbu/matplotlib-haskell/blob/master/test/Spec.hs#L214
+[img_images]: https://i.imgur.com/3ZqQDxR.png "images"
+[url_images]: https://github.com/abarbu/matplotlib-haskell/blob/master/test/Spec.hs#L482
+[img_polar]: https://i.imgur.com/BTXgvqa.png "polar"
+[url_polar]: https://github.com/abarbu/matplotlib-haskell/blob/master/test/Spec.hs#L450
+[img_histMulti]: https://i.imgur.com/hO2CFGQ.png "histMulti"
+[url_histMulti]: https://github.com/abarbu/matplotlib-haskell/blob/master/test/Spec.hs#L334
+[img_annotation]: https://i.imgur.com/cPSB8BX.png "annotation"
+[url_annotation]: https://github.com/abarbu/matplotlib-haskell/blob/master/test/Spec.hs#L539
+[img_corr]: https://i.imgur.com/fh4Bv2X.png "corr"
+[url_corr]: https://github.com/abarbu/matplotlib-haskell/blob/master/test/Spec.hs#L254
+[img_scatter]: https://i.imgur.com/qg7W3oc.png "scatter"
+[url_scatter]: https://github.com/abarbu/matplotlib-haskell/blob/master/test/Spec.hs#L219
+[img_hinton]: https://i.imgur.com/RPkTFIJ.png "hinton"
+[url_hinton]: https://github.com/abarbu/matplotlib-haskell/blob/master/test/Spec.hs#L380
+[img_quiver-fancy]: https://i.imgur.com/VQ5RrfJ.png "quiver-fancy"
+[url_quiver-fancy]: https://github.com/abarbu/matplotlib-haskell/blob/master/test/Spec.hs#L434
+[img_quadratic]: https://i.imgur.com/fs96snF.png "quadratic"
+[url_quadratic]: https://github.com/abarbu/matplotlib-haskell/blob/master/test/Spec.hs#L245
+[img_line-function]: https://i.imgur.com/5REiBVO.png "line-function"
+[url_line-function]: https://github.com/abarbu/matplotlib-haskell/blob/master/test/Spec.hs#L243
+[img_integral]: https://i.imgur.com/OxGr14f.png "integral"
+[url_integral]: https://github.com/abarbu/matplotlib-haskell/blob/master/test/Spec.hs#L396
+[img_contour]: https://i.imgur.com/kMxGGot.png "contour"
+[url_contour]: https://github.com/abarbu/matplotlib-haskell/blob/master/test/Spec.hs#L224
+[img_projections]: https://i.imgur.com/laubT7H.png "projections"
+[url_projections]: https://github.com/abarbu/matplotlib-haskell/blob/master/test/Spec.hs#L247
+[img_legend]: https://i.imgur.com/EmpXjUY.png "legend"
+[url_legend]: https://github.com/abarbu/matplotlib-haskell/blob/master/test/Spec.hs#L270
+[img_spines]: https://i.imgur.com/fc9xwh5.png "spines"
+[url_spines]: https://github.com/abarbu/matplotlib-haskell/blob/master/test/Spec.hs#L352
+[img_density-bandwidth]: https://i.imgur.com/e48WAPS.png "density-bandwidth"
+[url_density-bandwidth]: https://github.com/abarbu/matplotlib-haskell/blob/master/test/Spec.hs#L238
+[img_bivariateNormal]: https://i.imgur.com/ngX1N2R.png "bivariateNormal"
+[url_bivariateNormal]: https://github.com/abarbu/matplotlib-haskell/blob/master/test/Spec.hs#L465
+[img_pie]: https://i.imgur.com/DSRqr14.png "pie"
+[url_pie]: https://github.com/abarbu/matplotlib-haskell/blob/master/test/Spec.hs#L516
+[img_show-matrix]: https://i.imgur.com/bd6x6Es.png "show-matrix"
+[url_show-matrix]: https://github.com/abarbu/matplotlib-haskell/blob/master/test/Spec.hs#L267
+[img_hists]: https://i.imgur.com/hJaxZJt.png "hists"
+[url_hists]: https://github.com/abarbu/matplotlib-haskell/blob/master/test/Spec.hs#L371
+[img_errorbar]: https://i.imgur.com/ooTcL40.png "errorbar"
+[url_errorbar]: https://github.com/abarbu/matplotlib-haskell/blob/master/test/Spec.hs#L287
+[img_stacked]: https://i.imgur.com/TIqlAtR.png "stacked"
+[url_stacked]: https://github.com/abarbu/matplotlib-haskell/blob/master/test/Spec.hs#L523
diff --git a/matplotlib.cabal b/matplotlib.cabal
--- a/matplotlib.cabal
+++ b/matplotlib.cabal
@@ -1,5 +1,5 @@
 name:                matplotlib
-version:             0.4.0
+version:             0.4.1
 synopsis:            Bindings to Matplotlib; a Python plotting library
 description:
     Matplotlib is probably the most full featured plotting library out there.
@@ -48,6 +48,7 @@
                      , random
                      , raw-strings-qq
                      , split
+                     , ad
   ghc-options:         -threaded -rtsopts -with-rtsopts=-N
   default-language:    Haskell2010
 
diff --git a/src/Graphics/Matplotlib.hs b/src/Graphics/Matplotlib.hs
--- a/src/Graphics/Matplotlib.hs
+++ b/src/Graphics/Matplotlib.hs
@@ -57,13 +57,14 @@
 -- in "ax". Plotting commands should use the current axis, never the plot
 -- itself; the two APIs are almost identical. When creating low-level bindings
 -- one must remember to call "plot.sci" to set the current image when plotting a
--- graph. The current spine of the axes that's being manipulated is in "spine".
+-- graph. The current spine of the axes that's being manipulated is in
+-- "spine". The current quiver is in "q"
 -----------------------------------------------------------------------------
 
 module Graphics.Matplotlib
   ( module Graphics.Matplotlib
     -- * Creating custom plots and applying options
-  , Matplotlib(), Option(),(@@), (%), o1, o2, (##), (#), mp, def, readData
+  , Matplotlib(), Option(),(@@), (%), o1, o2, (##), (#), mp, def, readData, readImage
   , str, raw, lit, updateAxes, updateFigure, mapLinear)
 where
 import Data.List
@@ -89,6 +90,7 @@
 -- | Plot the cross-correlation and autocorrelation of several variables. TODO Due to
 -- a limitation in the options mechanism this takes explicit options.
 xacorr xs ys opts = readData (xs, ys)
+  % figure
   % addSubplot 2 1 1
   % xcorr xs ys @@ opts
   % grid True
@@ -111,6 +113,11 @@
 scatter x y = readData (x, y)
   % mp # "plot.sci(ax.scatter(data[0], data[1]" ## "))"
 
+-- | Create a bar at a position with a height
+bar :: (ToJSON t1, ToJSON t) => t1 -> t -> Matplotlib
+bar left height = readData (left, height)
+  % mp # "ax.bar(data[0], data[1]" ## ")"
+
 -- | Plot a line
 line :: (ToJSON t1, ToJSON t) => t1 -> t -> Matplotlib
 line x y = plot x y `def` [o1 "-"]
@@ -171,11 +178,29 @@
 matShow d = readData d
             % (mp # "plot.sci(ax.matshow(data" ## "))")
 
+-- | Plot an image
+imshow :: MplotImage a => a -> Matplotlib
+imshow i = readImage i
+            % (mp # "plot.sci(ax.imshow(img" ## "))")
+
 -- | Plot a matrix
 pcolor :: ToJSON a => a -> Matplotlib
 pcolor d = readData d
             % (mp # "plot.sci(ax.pcolor(np.array(data)" ## "))")
 
+-- | Plot a matrix
+pcolor3 x y z = readData (x,y,z)
+                % (mp # "plot.sci(ax.pcolor(np.array(data[0]),np.array(data[1]),np.array(data[2])" ## "))")
+
+-- | Create a non-uniform image from samples
+nonUniformImage x y z = readData (x,y,z)
+  % mp # "im = mpimg.NonUniformImage(ax" ## ")"
+  % mp # "im.set_data(data[0], data[1], data[2])"
+
+-- | Create a pie chart
+pie l = readData l
+  % mp # "plot.pie(" # l ## ")"
+
 -- | Plot a KDE of the given functions; a good bandwith will be chosen automatically
 density :: [Double] -> Maybe (Double, Double) -> Matplotlib
 density l maybeStartEnd =
@@ -186,6 +211,9 @@
 
 -- * Matplotlib configuration
 
+-- | Set an rc parameter
+rc s = mp # "plot.rc(" # str s ## ")"
+
 -- | Set an rcParams key-value
 setParameter k v = mp # "matplotlib.rcParams["# str k #"] = " # v
 
@@ -207,6 +235,9 @@
 plot :: (ToJSON t, ToJSON t1) => t1 -> t -> Matplotlib
 plot x y = readData (x, y) % dataPlot 0 1
 
+streamplot x y u v = readData (x, y, u, v)
+  % mp # "ax.streamplot(np.asarray(data[0]), np.asarray(data[1]), np.asarray(data[2]), np.asarray(data[3])" ## ")"
+
 -- | Plot x against y where x is a date.
 --   xunit is something like 'weeks', yearStart, monthStart, dayStart are an offset to x.
 -- TODO This isn't general enough; it's missing some settings about the format. The call is also a mess.
@@ -310,11 +341,24 @@
 -- | Plot auto-correlation
 acorr x = readData x % mp # "ax.acorr(data" ## ")"
 
+-- | A quiver plot; color is optional and can be nothing
+quiver x y u v Nothing = readData(x,y,u,v)
+  % mp # "q = ax.quiver(data[0], data[1], data[2], data[3]" ## ")"
+quiver x y u v (Just c) = readData(x,y,u,v,c)
+  % mp # "q = ax.quiver(data[0], data[1], data[2], data[3], data[4]" ## ")"
+
+-- | A key of a given size with a label for a quiver plot
+quiverKey x y u label = mp # "ax.quiverkey(q, "#x#", "#y#", "#u#", "#label##")"
+
 -- | Plot text at a specified location
 text x y s = mp # "ax.text(" # x # "," # y # "," # raw s ## ")"
 
+-- | Add a text to a figure instead of a particular plot
 figText x y s = mp # "plot.figtext(" # x # "," # y # "," # raw s ## ")"
 
+-- | Add an annotation
+annotate s = mp # "ax.annotate(" # str s ## ")"
+
 -- * Layout, axes, and legends
 
 -- | Square up the aspect ratio of a plot.
@@ -386,16 +430,16 @@
   % mp # "ax.set_zlim3d(" # minimum2 zs # ", " # maximum2 zs # ")"
 
 -- | Add a label to the x axis
-xLabel :: String -> Matplotlib
-xLabel label = mp # "ax.set_xlabel(" # raw label ## ")"
+xlabel :: String -> Matplotlib
+xlabel label = mp # "ax.set_xlabel(" # raw label ## ")"
 
 -- | Add a label to the y axis
-yLabel :: String -> Matplotlib
-yLabel label = mp # "ax.set_ylabel(" # raw label ## ")"
+ylabel :: String -> Matplotlib
+ylabel label = mp # "ax.set_ylabel(" # raw label ## ")"
 
 -- | Add a label to the z axis
-zLabel :: String -> Matplotlib
-zLabel label = mp # "ax.set_zlabel(" # raw label ## ")"
+zlabel :: String -> Matplotlib
+zlabel label = mp # "ax.set_zlabel(" # raw label ## ")"
 
 setSizeInches w h = mp # "fig.set_size_inches(" # w # "," # h # ", forward=True)"
 
@@ -461,9 +505,12 @@
 -- | Access a subplot
 setSubplot s = mp # "ax = axes[" # s # "]" % setAx
 
--- | Add axes to a figure
+-- | Add axes to a plot
 axes = mp # "ax = plot.axes(" ## ")" % updateAxes % setAx
 
+-- | Add axes to a figure
+addAxes = mp # "ax = fig.add_axes(" ## ")" % updateAxes % setAx
+
 -- | Creates a new figure with the given id. If the Id is already in use it
 -- switches to that figure.
-figure id = mp # "plot.figure(" # id ## ")" % updateFigure
+figure = mp # "plot.figure(" ## ")" % updateFigure
diff --git a/src/Graphics/Matplotlib/Internal.hs b/src/Graphics/Matplotlib/Internal.hs
--- a/src/Graphics/Matplotlib/Internal.hs
+++ b/src/Graphics/Matplotlib/Internal.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE FlexibleInstances, ScopedTypeVariables, FlexibleContexts, ExtendedDefaultRules #-}
+{-# LANGUAGE FlexibleInstances, ScopedTypeVariables, FlexibleContexts, ExtendedDefaultRules, ExistentialQuantification #-}
 -- |
 -- Internal representations of the Matplotlib data. These are not API-stable
 -- and may change. You can easily extend the provided bindings without relying
@@ -33,10 +33,10 @@
 -- | A maplotlib command, right now we have a very shallow embedding essentially
 -- dealing in strings containing python code as well as the ability to load
 -- data. The loaded data should be a json object.
-data MplotCommand
-  = LoadData B.ByteString
+data MplotCommand =
+  LoadData B.ByteString
+  | forall x. MplotImage x => LoadImage x
   | Exec { es :: String }
-  deriving (Show, Eq, Ord)
 
 -- | Throughout the API we need to accept options in order to expose
 -- matplotlib's many configuration options.
@@ -50,6 +50,7 @@
 -- | Convert an 'MplotCommand' to python code, doesn't do much right now
 toPy :: MplotCommand -> String
 toPy (LoadData _) = error "withMplot needed to load data"
+toPy (LoadImage _) = error "withMplot needed to load images"
 toPy (Exec str)   = str
 
 -- | Resolve the pending command with no options provided.
@@ -75,6 +76,12 @@
                 B.hPutStr dataHandle obj
                 hClose dataHandle
                 preload l $ ((map Exec $ pyReadData dataFile) ++ cmds))
+    preload ((LoadImage img):l) cmds = do
+      withSystemTempFile "data.json" $
+        (\dataFile dataHandle -> do
+            hClose dataHandle
+            obj <- saveHaskellImage img dataFile
+            preload l $ ([Exec $ "img = " ++ (loadPythonImage img obj dataFile)] ++ cmds))
     preload (c:l) cmds = preload l (c:cmds)
 
 -- | Create a plot that executes the string as python code
@@ -85,10 +92,14 @@
 mp :: Matplotlib
 mp = Matplotlib S.empty Nothing S.empty
 
--- | Load the given data into the 'data' array
+-- | Load the given data into the python "data" array
 readData :: ToJSON a => a -> Matplotlib
 readData d = Matplotlib (S.singleton $ LoadData $ encode d) Nothing S.empty
 
+-- | Load the given image into python "img" variable
+readImage :: MplotImage i => i -> Matplotlib
+readImage i = Matplotlib (S.singleton $ LoadImage i) Nothing S.empty
+
 infixl 5 %
 -- | Combine two matplotlib commands
 (%) :: Matplotlib -> Matplotlib -> Matplotlib
@@ -187,9 +198,28 @@
 instance MplotValue x => MplotValue (Maybe x) where
   toPython Nothing  = "None"
   toPython (Just x) = toPython x
+instance MplotValue [[Double]] where
+  toPython s = "np.asarray([" ++ f s ++ "])"
+    where f [] = ""
+          f (x:xs) = toPython x ++ "," ++ f xs
 
 default (Integer, Int, Double)
 
+-- | The class of Haskell images or references to imagese which can be
+-- transferred to matplotlib.
+class MplotImage a where
+  saveHaskellImage :: a -> FilePath -> IO String
+  loadPythonImage :: a -> String -> FilePath -> String
+
+-- | An image that is a string is a file path.
+instance MplotImage String where
+  saveHaskellImage _ _ = return ""
+  loadPythonImage s _ _ = "mpimg.imread('" ++ toPython s ++ "')"
+
+instance ToJSON a => MplotImage [[a]] where
+  saveHaskellImage d fp = (B.writeFile fp $ encode d) >> return ""
+  loadPythonImage s _ fp = unlines $ pyReadData fp
+
 -- $ Options
 
 -- | Add an option to the last matplotlib command. Commands can have only one option!
@@ -249,6 +279,7 @@
 def :: Matplotlib -> [Option] -> Matplotlib
 def m os = optionFn (defFn os) m
 
+-- | Merge two sets of options
 defFn :: [Option] -> [Option] -> [Option]
 defFn os os' = merge ps' ps ++ (nub $ ks' ++ ks)
            where isK (K _ _) = True
@@ -285,10 +316,11 @@
                      ,"import matplotlib.patches as mpatches"
                      ,"import matplotlib.pyplot as plot"
                      ,"import matplotlib.mlab as mlab"
+                     ,"import matplotlib.cm as cm"
                      ,"import matplotlib.colors as mcolors"
                      ,"import matplotlib.collections as mcollections"
                      ,"import matplotlib.ticker as mticker"
-                     ,"from matplotlib import cm"
+                     ,"import matplotlib.image as mpimg"
                      ,"from mpl_toolkits.mplot3d import axes3d"
                      ,"import numpy as np"
                      ,"import os"
@@ -303,6 +335,10 @@
 -- | The python command that reads external data into the python data array
 pyReadData :: [Char] -> [[Char]]
 pyReadData filename = ["data = json.loads(open('" ++ filename ++ "').read())"]
+
+-- | The python command that reads an image into the img variable
+pyReadImage :: [Char] -> [[Char]]
+pyReadImage filename = ["img = mpimg.imread('" ++ filename ++ "')"]
 
 -- | Detach python so we don't block (TODO This isn't working reliably)
 pyDetach :: [[Char]]
diff --git a/test/Spec.hs b/test/Spec.hs
--- a/test/Spec.hs
+++ b/test/Spec.hs
@@ -16,6 +16,7 @@
 import qualified Data.ByteString as BS
 import System.Process
 import System.IO
+import Numeric.AD
 
 -- * Random values for testing
 
@@ -93,6 +94,11 @@
 -- deviation).
 normals' (mean, sigma) g = map (\x -> x * sigma + mean) $ normals
 
+pdfBivariateNormal x y sigmax sigmay mux muy sigmaxy =
+  1/(2*pi*sigmax*sigmay*(sqrt(1-rho^2)))*exp(-z/(2*(1-rho^2)))
+  where rho = sigmaxy/(sigmax*sigmay)
+        z = (x-mux)^2/sigmax^2-(2*rho*(x-mux)*(y-muy))/(sigmax*sigmay)+(y-muy)^2/sigmay^2
+
 -- * Tests
 
 main = defaultMain $ tests "All tests" testPlot
@@ -153,17 +159,17 @@
           file ("/tmp/imgs/" ++ name ++ ".png") fn
 
 basicTests f = testGroup "Basic tests"
-  [ f "histogram" m1
-  , f "cumulative" m2
-  , f "scatter" m3
-  , f "contour" m4
-  , f "labelled-histogram" m5
-  , f "density-bandwidth" m7
-  , f "density" m8
-  , f "line-function" m9
-  , f "quadratic" m10
-  , f "projections" m11
-  , f "line-options" m12
+  [ f "histogram" mhistogram
+  , f "cumulative" mcumulative
+  , f "scatter" mscatter
+  , f "contour" mcontour
+  , f "labelled-histogram" mlabelledHistogram
+  , f "density-bandwidth" mdensityBandwidth
+  , f "density" mdensity
+  , f "line-function" mlineFunction
+  , f "quadratic" mQuadratic
+  , f "projections" mProjections
+  , f "line-options" mlineOptions
   , f "corr" mxcorr
   , f "show-matrix" mmat
   , f "legend" mlegend
@@ -176,61 +182,72 @@
   , f "hists" mhists
   , f "hinton" mhinton
   , f "integral" mintegral
+  , f "quiver" mquiver
+  , f "quiver-fancy" mquiverFancy
+  , f "polar" mpolar
+  , f "bivariateNormal" mbivariateNormal
+  , f "images" mimages
+  , f "pcolorlog" mpcolorlog
+  , f "pie" mpie
+  , f "stacked" mstacked
+  , f "annotation" mannotation
+  , f "streamplot" mstreamplot
   ]
 
 fragileTests f = testGroup "Fragile tests"
-  [ -- TODO Fails on circle ci (with latex)
-    f "tex" mtex
+  [ f "tex" mtex -- TODO Fails on circle ci (with latex)
     -- TODO Fails on circle ci (labels is not valid; matplotlib too old)
   , f "boxplot" mboxplot
     -- TODO Fails on circle ci (no violin plots; matplotlib too old)
   , f "violinplot" mviolinplot
+    -- TODO Needs a fairly recent matplotlib; too old for circleci
+  , f "griddata" mgriddata
   ]
 
 failingTests f = testGroup "Failing tests"
   [
     -- TODO This test case is broken
-    f "sub-bars" m6
+    f "sub-bars" msubBars
   ]
 
 -- * These tests are fully-reproducible, the output must be identical every time
 
-m1 :: Matplotlib
-m1 = histogram xs 8
+mhistogram :: Matplotlib
+mhistogram = histogram xs 8
 
-m2 :: Matplotlib
-m2 = histogram xs 8 @@ [o2 "cumulative" True]
+mcumulative = histogram xs 8 @@ [o2 "cumulative" True]
 
-m3 = scatter xs ys
+mscatter = scatter xs ys
 
 degreesRadians a = a * pi / 180.0
 radiansDegrees a = a * 180.0 / pi
 
-m4 = contourF (\a b -> sin (degreesRadians a) + cos (degreesRadians b)) (-100) 100 (-200) 200 10
+mcontour = contourF (\a b -> sin (degreesRadians a) + cos (degreesRadians b)) (-100) 100 (-200) 200 10
 
-m5 = histogram xs 7
-   % yLabel "number of queries"
-   % xLabel "true positives"
+mlabelledHistogram = histogram xs 7
+   % ylabel "number of queries"
+   % xlabel "true positives"
 
-m6 = subplotBarsLabelled
+-- TODO Broken test
+msubBars = subplotBarsLabelled
        [[40, 50, 20, 50], [10, 20, 30, 40], [40, 50, 20, 50]]
        ["a", "b", "c", "d"] []
       % title "Wee a title"
-      % xLabel "X"
-      % yLabel "Y"
+      % xlabel "X"
+      % ylabel "Y"
 
-m7 = densityBandwidth [2.1, 1.3, 0.4, 1.9, 5.1, 6.2] 1.5 (Just (-6, 11))
+mdensityBandwidth = densityBandwidth [2.1, 1.3, 0.4, 1.9, 5.1, 6.2] 1.5 (Just (-6, 11))
   % ylim 0 0.2
 
-m8 = density [2.1, 1.3, 0.4, 1.9, 5.1, 6.2] (Just (-6, 11))
+mdensity = density [2.1, 1.3, 0.4, 1.9, 5.1, 6.2] (Just (-6, 11))
 
-m9 = lineF (\x -> x**2) [0,0.01..1]
+mlineFunction = lineF (\x -> x**2) [0,0.01..1]
 
-m10 = plotMapLinear (\x -> x**2) (-2) 2 100 @@ [o1 "."] % title "Quadratic function"
+mQuadratic = plotMapLinear (\x -> x**2) (-2) 2 100 @@ [o1 "."] % title "Quadratic function"
 
-m11 = projectionsF (\a b -> cos (degreesRadians a) + sin (degreesRadians b)) (-100) 100 (-200) 200 10
+mProjections = projectionsF (\a b -> cos (degreesRadians a) + sin (degreesRadians b)) (-100) 100 (-200) 200 10
 
-m12 = plot [1,2,3,4,5,6] [1,3,2,5,2,4] @@ [o1 "go-", o2 "linewidth" 2]
+mlineOptions = plot [1,2,3,4,5,6] [1,3,2,5,2,4] @@ [o1 "go-", o2 "linewidth" 2]
 
 -- * These tests can be random and may not be exactly the same every time
 
@@ -243,8 +260,8 @@
 mtex = plotMapLinear cos 0 1 100
   % setTeX True
   % setUnicode True
-  % xLabel [r|\textbf{time (s)}|]
-  % yLabel [r|\textit{Velocity (\u00B0/sec)}|] @@ [o2 "fontsize" 16]
+  % xlabel [r|\textbf{time (s)}|]
+  % ylabel [r|\textit{Velocity (\u00B0/sec)}|] @@ [o2 "fontsize" 16]
   % title [r|\TeX\ is Number $\displaystyle\sum_{n=1}^\infty\frac{-e^{i\pi}}{2^n}$!"|] @@ [o2 "fontsize" 16, o2 "color" "r"]
   % grid True
 
@@ -286,7 +303,7 @@
   % violinplot (take 3 $ chunksOf 100 $ map (* 2) $ normals) @@ [o2 "showmeans" True, o2 "showmedians" True, o2 "vert" False]
 
 -- | http://matplotlib.org/examples/pylab_examples/scatter_hist.html
-mscatterHist = figure 0
+mscatterHist = figure @@ [o1 0]
   % setSizeInches 8 8
   -- The scatter plot
   % axes @@ [o1 ([left, bottom', width, height] :: [Double])]
@@ -403,3 +420,198 @@
         -- shaded region
         (ix :: [Double]) = mapLinear (\x -> x) a b 100
         iy = map func ix
+
+mquiver = quiver x y u v (Nothing :: Maybe [Double]) @@ [o2 "units" "width"]
+  % quiverKey 0.9 0.93 2 (raw [r|$2 \frac{m}{s}$|])
+    @@ [o2 "labelpos" "E", o2 "coordinates" "figure"]
+  % xlim (-0.2) 6.4
+  % ylim (-0.2) 6.4
+  where m = [ (x,y,cos x,sin y) | x <- [0,0.2..2*pi], y <- [0,0.2..2*pi] ]
+        x = map (\(x,_,_,_) -> x) m
+        y = map (\(_,x,_,_) -> x) m
+        u = map (\(_,_,x,_) -> x) m
+        v = map (\(_,_,_,x) -> x) m
+
+mquiverFancy = quiver x y u v (Just mag) @@ [o2 "units" "x"
+                                            ,o2 "pivot" "tip"
+                                            ,o2 "width" 0.022
+                                            ,o2 "scale" (1 / 0.15)]
+  % quiverKey 0.9 0.93 1 (raw [r|$2 \frac{m}{s}$|])
+    @@ [o2 "labelpos" "E", o2 "coordinates" "figure"]
+  % scatter x y @@ [o2 "color" "k", o2 "s" 5]
+  % xlim (-0.2) 6.4
+  % ylim (-0.2) 6.4
+  where m = [ (x,y,cos x,sin y) | x <- [0,0.2..2*pi], y <- [0,0.2..2*pi] ]
+        x = map (\(x,_,_,_) -> x) m
+        y = map (\(_,x,_,_) -> x) m
+        u = map (\(_,_,x,_) -> x) m
+        v = map (\(_,_,_,x) -> x) m
+        mag = zipWith (\x x' -> sqrt(x**2 + x'**2)) u v
+
+mpolar = rc "grid" @@ [o2 "color" "#316931", o2 "linewidth" 1, o2 "linestyle" "-"]
+  % rc "xtick" @@ [o2 "labelsize" 15]
+  % rc "ytick" @@ [o2 "labelsize" 15]
+  % figure @@ [o2 "figsize" (8::Int,8::Int)]
+  % addAxes @@ [o1 [0.1, 0.1, 0.8, 0.8::Double], o2 "projection" "polar"
+               -- TODO My matplotlib doesn't seem to have this property
+               -- , o2 "facecolor" "#d5de9c"
+               ]
+  % plot theta r @@ [o2 "color" "#ee8d18", o2 "lw" 3, o2 "label" "a line"]
+  % plot (map (\x -> 0.5*x) theta) r
+         @@ [o2 "color" "blue", o2 "ls" "--", o2 "lw" 3, o2 "label" "another line"]
+  % legend
+  where r = [0,0.01..3.0]
+        theta = map (\x -> 2*pi*x) r
+
+mbivariateNormal =
+  imshow vs @@ [o2 "interpolation" "bilinear"
+               ,o2 "cmap" $ raw "RdYlGn"
+               ,o2 "origin" "lower"
+               ,o2 "extent" [-3::Double, 3, -3, 3]
+               ,o2 "vmin" $ (0-) $ maximum $ map abs vs'
+               ,o2 "vmax" $ maximum $ map abs vs']
+  where delta = 0.025::Double
+        xs = [-3.0,-3.0+delta..3.0]
+        ys = [-3.0,-3.0+delta..3.0]
+        vs = [[pdfBivariateNormal x y 1.5 0.5 1.0 1.0 0.0
+               - pdfBivariateNormal x y 1.0 1.0 0.0 0.0 0.0
+              | x <- xs]
+              | y <- ys]
+        vs' = foldl' (++) [] vs
+
+-- TODO This is subtly broken
+mimages = -- figure @@ [o2 "figsize" (10::Int,10::Int)]
+  -- %
+  subplots @@ [o2 "nrows" 1, o2 "ncols" 2]
+  % setSubplot 0
+  % imshow "data/heightmap.png" @@ [o2 "interpolation" "nearest"]
+  % setSubplot 1
+  % mp # "ls = mcolors.LightSource(azdeg=315, altdeg=45)"
+  % mp # "ax.imshow(ls.shade(img, cmap=cm.gist_earth))"
+  -- TODO This doesn't work on my matplab version
+  -- vert_exag=0.05,
+  --, blend_mode='overlay'
+  % xlabel "overlay blend mode"
+
+mpcolorlog = figure
+  % addSubplot 2 1 1
+  % pcolor3 xs' ys' vs @@ [o2 "cmap" $ raw "PuBu_r"]
+  % colorbar
+  % addSubplot 2 1 2
+  % pcolor3 xs' ys' vs @@ [o2 "norm"
+                            (lit $ "mcolors.LogNorm(vmin="++(show $ minimum vs')++
+                              ", vmax="++(show $ maximum vs')++")")
+                          ,o2 "cmap" $ raw "PuBu_r"]
+  % colorbar
+  where delta = 0.1::Double
+        xs = [-3.0,-3.0+delta..3.0]
+        ys = [-3.0,-3.0+delta..3.0]
+        vs = [[pdfBivariateNormal x y 0.1 0.2 1.0 1.0 0.0
+               + 0.1 * pdfBivariateNormal x y 1.0 1.0 0.0 0.0 0.0
+              | x <- xs]
+              | y <- ys]
+        xs' = [[ x | x <- xs]| y <- ys]
+        ys' = [[ y | x <- xs]| y <- ys]
+        vs' = foldl' (++) [] vs
+
+mpie = pie [15, 30, 45, 10 :: Double]
+  @@ [o2 "explode" [0, 0.05, 0, 0 :: Double]
+     ,o2 "labels" ["Frogs", "Hogs", "Dogs", "Logs"]
+     ,o2 "autopct" "%.0f%%"
+     ,o2 "shadow" True]
+
+-- | http://matplotlib.org/examples/pylab_examples/bar_stacked.html
+mstacked =
+  -- TODO The locations of the bars is off
+    bar [0..4] ms @@ [o1 width, o2 "color" "#d62728", o2 "yerr" mStd, o2 "label" "ms"]
+  % bar [0..4] ws @@ [o1 width, o2 "bottom" ms,       o2 "yerr" wStd, o2 "label" "ws"]
+  % xticks [0..4 :: Int]
+  % xtickLabels "['G1', 'G2', 'G3', 'G4', 'G5']"
+  % title "Scores"
+  % ylabel "Score"
+  % yticks [0,10..80 :: Int]
+  % legend
+  where ms    = [20 :: Double, 35, 30, 35, 27]
+        ws    = [25 :: Double, 32, 34, 20, 25]
+        mStd  = [2 :: Double, 3, 4, 1, 2]
+        wStd  = [3 :: Double, 5, 2, 3, 3]
+        width = 0.35 :: Double
+
+mannotation = -- figure @@ [o2 "figsize" (10::Int,10::Int)]
+  -- TODO This is subtly broken
+  -- TODO Dictionaries
+    plot t s @@ [o2 "lw" 3]
+  % xlim (-1) 5
+  % ylim (-4) 3
+  % annotate "straight" @@ [o2 "xy" [0, 1::Double], o2 "xycoords" "data", o2 "xytext" [-50, 30 :: Double]
+                           ,o2 "textcoords" "offset points", o2 "arrowprops" (lit "dict(arrowstyle='->')")]
+  % annotate "arc3,\\nrad 0.2" @@ [o2 "xy" [0.5, -1::Double], o2 "xycoords" "data", o2 "xytext" [-80, -60 :: Double]
+                                 ,o2 "textcoords" "offset points"
+                                 ,o2 "arrowprops" (lit "dict(arrowstyle='->', connectionstyle='arc3,rad=.2')")]
+  % annotate "arc,\\nangle 50" @@ [o2 "xy" [1, 1::Double], o2 "xycoords" "data", o2 "xytext" [-90, 50 :: Double]
+                                  ,o2 "textcoords" "offset points"
+                                  ,o2 "arrowprops" (lit "dict(arrowstyle='->', connectionstyle='arc,angleA=0,armA=50,rad=10')")]
+  % annotate "arc,\\narms" @@ [o2 "xy" [1.5, -1::Double], o2 "xycoords" "data", o2 "xytext" [-80, -60 :: Double]
+                              ,o2 "textcoords" "offset points"
+                              ,o2 "arrowprops" (lit "dict(arrowstyle='->', connectionstyle='arc,angleA=0,armA=40,angleB=-90,armB=30,rad=7')")]
+  % annotate "angle,\\nangle 90" @@ [o2 "xy" [2, 1::Double], o2 "xycoords" "data", o2 "xytext" [-70, 30 :: Double]
+                   ,o2 "textcoords" "offset points"
+                   ,o2 "arrowprops" (lit "dict(arrowstyle='->', connectionstyle='angle,angleA=0,angleB=90,rad=10')")]
+  % annotate "angle3,\\nangle -90" @@ [o2 "xy" [2.5, -1::Double], o2 "xycoords" "data", o2 "xytext" [-80, -60 :: Double]
+                   ,o2 "textcoords" "offset points"
+                   ,o2 "arrowprops" (lit "dict(arrowstyle='->', connectionstyle='angle3,angleA=0,angleB=-90')")]
+  % annotate "angle,\\nround" @@ [o2 "xy" [3, 1::Double], o2 "xycoords" "data", o2 "xytext" [-60, 30 :: Double]
+                   ,o2 "textcoords" "offset points"
+                   ,o2 "bbox" (lit "dict(boxstyle='round', fc='0.8')")
+                   ,o2 "arrowprops" (lit "dict(arrowstyle='->', connectionstyle='angle,angleA=0,angleB=90,rad=10')")]
+  % annotate "angle,\\nround4" @@ [o2 "xy" [3.5, -1::Double], o2 "xycoords" "data", o2 "xytext" [-70, -80 :: Double]
+                   ,o2 "textcoords" "offset points"
+                   ,o2 "bbox" (lit "dict(boxstyle='round4,pad=.5', fc='0.8')")
+                   ,o2 "size" 20
+                   ,o2 "arrowprops" (lit "dict(arrowstyle='->', connectionstyle='angle,angleA=0,angleB=-90,rad=10')")]
+  % annotate "angle,\\nshrink" @@ [o2 "xy" [4, 1::Double], o2 "xycoords" "data", o2 "xytext" [-60, 30 :: Double]
+                   ,o2 "textcoords" "offset points"
+                   ,o2 "bbox" (lit "dict(boxstyle='round', fc='0.8')")
+                   ,o2 "arrowprops" (lit "dict(arrowstyle='->', connectionstyle='angle,angleA=0,angleB=90,rad=10')")]
+  -- TODO This annotation doesn't render correctly on my matplotlib version
+  % annotate "" @@ [o2 "xy" [4, 1::Double], o2 "xycoords" "data", o2 "xytext" [4.5, -1 :: Double]
+                   ,o2 "textcoords" "offset points"
+                   ,o2 "arrowprops" (lit "dict(arrowstyle='<->', connectionstyle='bar', ec='k', shrinkA=5, shrinkB=5)")]
+  where t = [0, 0.01 .. 5.0 :: Double]
+        s = map (\x -> cos $ 2*pi*x) t
+
+mstreamplot = streamplot xs ys xs' ys' @@ [o2 "linewidth" mag']
+  -- useful for seeing the energy landscape
+  -- pcolor3 xmat ymat vs
+  where delta = 0.05::Double
+        xs = [-3.0,-3.0+delta..3.0]
+        ys = [-3.0,-3.0+delta..3.0]
+        xmat = [[ x | x <- xs]| y <- ys]
+        ymat = [[ y | x <- xs]| y <- ys]
+        ms = [[grad' (\[xv,yv] ->
+                         pdfBivariateNormal xv yv 0.4 0.7 1.0 1.0 0.0
+                         + pdfBivariateNormal xv yv 1.0 1.0 (-1.0) (-1.0) 0.0)
+                [x,y]
+              | x <- xs]
+             | y <- ys] :: [[(Double, [Double])]]
+        vs  = map2 (\(v, _)      -> v) ms
+        xs' = map2 (\(_, [x, _]) -> x) ms
+        ys' = map2 (\(_, [_, y]) -> y) ms
+        mag' = zipWith (\lx ly -> zipWith (\x y -> 5 * (log $ 1 + (sqrt $ x*x + y*y))) lx ly) xs' ys'
+        map2 f l = map (\r -> map f r) l
+
+mgriddata = readData (x, y, z, xi, yi)
+  -- TODO This requires a lot of manual indexing. Next big API change will be to
+  -- have references to loaded data.
+  % mp # "data.append(mlab.griddata(data[0], data[1], data[2], data[3], data[4], interp='linear'))"
+  % mp # "plot.sci(ax.contour(data[3], data[4], data[5], 15, linewidths=0.5, colors='k'))"
+  % mp # "plot.sci(ax.contourf(data[3], data[4], data[5], 15, vmax=abs(data[5]).max(), vmin=-abs(data[5]).max()))"
+  % colorbar
+  % scatter x y @@ [o2 "marker" "o", o2 "s" 5, o2 "zorder" 10]
+  % xlim (-2) 2
+  % ylim (-2) 2
+  % title "Grid interpolation"
+  where [x, y] = take 2 $ chunksOf 200 $ map (\x -> 4 * (x - 0.5)) $ uniforms
+        z = zipWith (\x y -> x*(exp $ -(x**2) - y**2)) x y
+        xi = mapLinear (\x -> x) (-2.1) 2.1 300
+        yi = mapLinear (\x -> x) (-2.1) 2.1 300
