diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Author name here (c) 2017
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Author name here nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,16 @@
+# Matplotlib
+
+[![Build Status](http://circleci-badges-max.herokuapp.com/img/abarbu/matplotlib-haskell/master?token=468e8942459ca5f34089fb5c29a478ffb6d531af)](https://circleci.com/gh/abarbu/matplotlib-haskell/tree/master)
+
+Haskell bindings to Python's Matplotlib. It's high time that Haskell had a
+fully-fledged plotting library!
+
+![matplotlib contour plot](https://github.com/abarbu/matplotlib-haskell/raw/master/contour.png)
+
+More info and docs forthcoming.
+
+```haskell
+import Matplotlib
+
+onscreen $ contourF (\a b -> sin (degreesRadians a) + cos (degreesRadians b)) (-100) 100 (-200) 200 10
+```
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/contour.png b/contour.png
new file mode 100644
Binary files /dev/null and b/contour.png differ
diff --git a/matplotlib.cabal b/matplotlib.cabal
new file mode 100644
--- /dev/null
+++ b/matplotlib.cabal
@@ -0,0 +1,40 @@
+name:                matplotlib
+version:             0.1.0.0
+synopsis:            Bindings to Matplotlib; a Python plotting library
+description:         Matplotlib is probably the most full featured plotting library out there. These bindings provide a quick, easy, and extensible way to use it in Haskell. Type-safety is largely non-existent and sacrificed for maximum extensibility.
+homepage:            https://github.com/abarbu/matplotlib-haskell
+license:             BSD3
+license-file:        LICENSE
+author:              Andrei Barbu
+maintainer:          andrei@0xab.com
+copyright:           2017 Andrei Barbu
+category:            Graphics
+build-type:          Simple
+extra-source-files:  README.md contour.png
+cabal-version:       >=1.10
+
+library
+  hs-source-dirs:      src
+  exposed-modules:     Graphics.Matplotlib
+  build-depends:       base >= 4.7 && < 5
+                     , process
+                     , bytestring
+                     , aeson
+                     , temporary
+  default-language:    Haskell2010
+
+test-suite matplotlib-test
+  type:                exitcode-stdio-1.0
+  hs-source-dirs:      test
+  main-is:             Spec.hs
+  build-depends:       base
+                     , matplotlib
+                     , tasty
+                     , tasty-hunit
+                     , temporary
+  ghc-options:         -threaded -rtsopts -with-rtsopts=-N
+  default-language:    Haskell2010
+
+source-repository head
+  type:     git
+  location: https://github.com/abarbu/matplotlib-haskell
diff --git a/src/Graphics/Matplotlib.hs b/src/Graphics/Matplotlib.hs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/Matplotlib.hs
@@ -0,0 +1,408 @@
+{-# LANGUAGE DeriveGeneric, TypeSynonymInstances, FlexibleInstances, ScopedTypeVariables, FlexibleContexts, OverlappingInstances #-}
+
+-- Matplotlib bindings and an interface to easily bind to new portions of the
+-- API. The most essential parts of Matplotlib are wrapped and exposed to
+-- Haskell through an interface that allows extenisbility. Code is generated on
+-- the fly and python is called.
+--
+-- This is not a very Haskell-ish library. Type safety is non-existent, it's
+-- easy to generate incorrect Python code, in exchange for being able to bind to
+-- arbitrary matplotlib APIs with ease, so it's also easy to generate correct
+-- python code.
+--
+-- The generated code follows a few simple conventions.  data is always loaded
+-- into a data variable that is a python array. Data is transffered via
+-- json. This data variable is indexed by various rendering commands.
+--
+-- Many functions take an optional argument list.
+--
+-- Functions which start with the word data operate on the data array, arguments
+-- are python code that should access that array. Most other functions take
+-- haskell objects and load them into python.
+
+module Graphics.Matplotlib where
+import System.IO.Temp
+import System.Process
+import GHC.Generics
+import Data.Aeson
+import Control.Monad
+import System.IO
+import qualified Data.ByteString.Lazy as B
+import Data.List
+import Control.Exception
+
+-- | A handle internal function
+mapLinear :: (Double -> b) -> Double -> Double -> Double -> [b]
+mapLinear f s e n = map (\v -> f $ s + (v * (e - s) / n)) [0..n]
+
+-- | The wrapper type for a matplotlib computation. This is opaque.
+data Matplotlib = Matplotlib [MplotCommand]
+
+-- | A maplotlib command, right now we have a very shallow embedding essentially
+-- dealing in opaque strings containing python code as well as the ability to
+-- load data. The loaded should be a json object.
+data MplotCommand
+  = LoadData B.ByteString
+  | Exec String
+  deriving (Show, Eq, Ord)
+
+-- | Throughout the API we need to accept options in order to expose
+-- matplotlib's many configuration options.
+data Option = K String String -- | results in a=b
+            | B String        -- | just inserts the option verbatim as an argument at the end of the function
+
+toPy (LoadData _) = error "withMplot needed to load data"
+toPy (Exec str)   = str
+
+-- | The io action is given a list of python commands to execute (note that
+-- these are commands in the sense of lines of python code; each inidivudal line
+-- may not be parseable on its own
+withMplot :: Matplotlib -> ([String] -> IO a) -> IO a
+withMplot (Matplotlib cs) f = preload cs []
+  where
+    preload [] cmds = f $ map toPy $ reverse cmds
+    preload ((LoadData obj):cs) cmds =
+          withSystemTempFile "data.json"
+            (\dataFile dataHandle -> do
+                B.hPutStr dataHandle obj
+                hClose dataHandle
+                preload cs $ ((map Exec $ pyReadData dataFile) ++ cmds))
+    preload (c:cs) cmds = preload cs (c:cmds)
+  
+--- Python operations
+
+-- | Run python given a code string.
+python codeStr =
+  catch (withSystemTempFile "code.py"
+         (\codeFile codeHandle -> do
+             forM_ codeStr (hPutStrLn codeHandle)
+             hClose codeHandle
+             Right <$> readProcess "/usr/bin/python3" [codeFile] ""))
+         (\e -> return $ Left $ show (e :: IOException))
+
+pyIncludes = ["import matplotlib"
+             -- TODO Provide a way to set the render backend
+             -- ,"matplotlib.use('GtkAgg')"
+             ,"import matplotlib.path as mpath"
+             ,"import matplotlib.patches as mpatches"
+             ,"import matplotlib.pyplot as plot"
+             ,"import matplotlib.mlab as mlab"
+             ,"from matplotlib import cm"
+             ,"from mpl_toolkits.mplot3d import axes3d"
+             ,"import numpy as np"
+             ,"import os"
+             ,"import sys"
+             ,"import json"
+             ,"import random, datetime"
+             ,"from matplotlib.dates import DateFormatter, WeekdayLocator"]
+
+pyReadData filename = ["data = json.loads(open('" ++ filename ++ "').read())"]
+
+pyDetach = ["pid = os.fork()"
+           ,"if(pid != 0):"
+           ,"  exit(0)"]
+
+pyOnscreen = ["plot.draw()"
+             ,"plot.show()"]
+
+pyFigure output = ["plot.savefig('" ++ output ++ "')"]
+
+--- Running a plot
+
+-- | Show a plot, blocks until the figure is closed
+onscreen m = withMplot m (\str -> python $ pyIncludes ++ str ++ pyDetach ++ pyOnscreen)
+
+-- | Print the python code that would be executed
+code m = withMplot m (\str -> return $ Right $ unlines $ pyIncludes ++ str ++ pyDetach ++ pyOnscreen)
+
+-- | Save to a file
+figure filename m = withMplot m (\str -> python $ pyIncludes ++ str ++ pyFigure filename)
+
+-- Creating matplotlib computations
+
+mplot s = Matplotlib [Exec s]
+
+infixl 5 %
+-- | combine two matplotlib commands
+(%) :: Matplotlib -> Matplotlib -> Matplotlib
+(Matplotlib a) % (Matplotlib b) = Matplotlib (a ++ b)
+
+infixl 6 #
+-- | Values which can be combined together to form a matplotlib command. Right
+-- now matplotlib commands are strings and this is just a helper to construct
+-- them.
+class MplotValue val where
+  (#) :: String -> val -> String
+instance MplotValue String where
+  s # b = s ++ b
+instance MplotValue [String] where
+  m # [] = m
+  m # (x:xs) = m # x # "," # xs
+instance MplotValue Double where
+  s # b = s ++ show b
+instance MplotValue Int where
+  s # b = s ++ show b
+instance MplotValue (String, String) where
+  m # (n, v) = m # n # "=" # v
+instance (MplotValue x) => MplotValue (x, x) where
+  m # (n, v) = m # n # "=" # v
+instance (MplotValue (x, y)) => MplotValue [(x, y)] where
+  m # [] = m
+  m # (x:xs) = m # x # "," # xs
+instance MplotValue Option where
+  m # (B a) = m # a
+  m # (K a b) = m # a # "=" # b
+instance MplotValue [Option] where
+  m # [] = m
+  m # (x:xs) = m # x # "," # xs
+
+--- Convenience & Data
+
+-- | Plot the 'a' and 'b' entries of the data object
+dataPlot :: (MplotValue val, MplotValue val1) => val1 -> val -> [Option] -> Matplotlib
+dataPlot a b opts =
+  mplot $ "p = plot.plot(data[" # a # "], data[" # b # "]" # options opts # ")"
+
+-- | Plot the Haskell objects 'x' and 'y' as a line
+plot :: (ToJSON t, ToJSON t1) => t1 -> t -> [Option] -> Matplotlib
+plot x y opt =
+  readData (x, y) % dataPlot (0::Int) (1::Int) opt
+
+-- | Plot & show onscreen
+showPlot :: (ToJSON t, ToJSON t1) => t1 -> t -> [Option] -> IO (Either String String)
+showPlot x y opt = onscreen (plot x y opt)
+
+-- | Load the given data into the 'data' array
+readData :: ToJSON a => a -> Matplotlib
+readData d = Matplotlib [LoadData $ encode d]
+
+-- ;;; Options
+
+-- | An internal helper to convert a list of options to the python code that
+-- applies those options in a call.
+options :: [Option] -> String
+options [] = ""
+options xs = "," # xs
+
+def o [] = [o]
+def o l@((B _):_) = l
+def o (x:xs) = x : def o xs
+
+-- | Show grid lines
+gridLines = mplot "ax.grid(True)"
+
+-- | 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.
+dateLine :: (ToJSON t1, ToJSON t2) => t1 -> t2 -> String -> (Int, Int, Int) -> Matplotlib
+dateLine x y xunit (yearStart, monthStart, dayStart) =
+    readData (x, y)
+  % mplot ("data[0] = [datetime.timedelta("#xunit#"=i) + datetime.datetime("#yearStart#","#monthStart#","#dayStart#") for i in data[0]]")
+  % dataPlot (0::Int) (1::Int) [B "-"]
+  % mplot "ax.xaxis.set_major_formatter(DateFormatter('%B'))"
+  % mplot "ax.xaxis.set_minor_locator(WeekdayLocator(byweekday=6))"
+  
+-- | Add a label to the x axis
+xLabel label = mplot $ "plot.xlabel('" # label # "')"
+
+-- | Add a label to the y axis
+yLabel label = mplot $ "plot.ylabel('" # label # "')"
+
+-- | Add a label to the z axis
+zLabel label = mplot $ "plot.zlabel('" # label # "')"
+
+-- | Create a histogram for the 'a' entry of the data array
+dataHistogram a bins opts = mplot $ "plot.hist(data[" # a # "]," # bins # options opts # ")"
+
+-- | Plot a histogram for the given values with 'bins'
+histogram values bins opts = readData [values] % dataHistogram (0::Int) bins opts
+
+-- | Plot & show the histogram
+showHistogram values bins opts = onscreen $ histogram values bins opts
+
+-- | Create a scatter plot accessing the given fields of the data array
+dataScatter a b opts = dataPlot a b $ def (B "'.'") opts
+
+-- | Plot the given values as a scatter plot
+scatter x y opts = plot x y $ def (B "'.'") opts
+
+-- | Plot and show a scatter plot
+showScatter x y opts = showPlot x y $ def (B "'.'") opts
+
+-- | Create a line accessing the given entires of the data array
+dataLine a b opts = dataPlot a b $ def (B "'-'") opts
+
+-- | Plot a line
+line x y opts = plot x y $ def (B "'-'") opts
+
+-- | Plot a line given a function that will be executed for each element of
+-- given list. The list provides the x values, the function the y values.
+lineF f l opts = plot l (map f l) $ def (B "'-'") opts
+
+-- | Plot and show a line
+showLine x y opts = showPlot x y $ def (B "'-'") opts
+
+-- | Create a 3D contour
+contour xs ys zs =
+  readData (xs, ys, zs)
+  % axis3DProjection
+  % surface (0::Int) (1::Int) (2::Int)
+  % contourRaw (0::Int) (1::Int) (2::Int) (maximum2 xs) (maximum2 ys) (minimum2 zs)
+  % axis3DLabels xs ys zs
+
+-- | Create a 3D projection
+projections xs ys zs =
+  readData (xs, ys, zs)
+  % axis3DProjection
+  % contourRaw (0::Int) (1::Int) (2::Int) (maximum2 xs) (maximum2 ys) (minimum2 zs)
+  % axis3DLabels xs ys zs
+
+-- | Given a grid of x and y values and a number of steps call the given
+-- function and plot the 3D contour
+contourF f xStart xEnd yStart yEnd steps = contour xs ys zs
+  where xs = mapLinear (\x -> (mapLinear (\y -> x) yStart yEnd steps)) xStart xEnd steps
+        ys = mapLinear (\x -> (mapLinear (\y -> y) yStart yEnd steps)) xStart xEnd steps
+        zs = mapLinear (\x -> (mapLinear (\y -> f x y) yStart yEnd steps)) xStart xEnd steps
+
+-- | Given a grid of x and y values and a number of steps call the given
+-- function and plot the 3D projection
+projectionsF f xStart xEnd yStart yEnd steps = projections xs ys zs
+  where xs = mapLinear (\x -> (mapLinear (\y -> x) yStart yEnd steps)) xStart xEnd steps
+        ys = mapLinear (\x -> (mapLinear (\y -> y) yStart yEnd steps)) xStart xEnd steps
+        zs = mapLinear (\x -> (mapLinear (\y -> f x y) yStart yEnd steps)) xStart xEnd steps
+
+-- | Enable 3D projection
+axis3DProjection = mplot $ "ax = plot.figure().gca(projection='3d')"
+
+-- | Plot a 3D wireframe accessing the given elements of the data array
+wireframe a b c = mplot $ "ax.plot_wireframe(np.array(data[" # a # "]), np.array(data[" # b # "]), np.array(data[" # c # "]), rstride=1, cstride=1)"
+
+-- | Plot a 3D surface accessing the given elements of the data array
+surface a b c = mplot $ "ax.plot_surface(np.array(data[" # a # "]), np.array(data[" # b # "]), np.array(data[" # c # "]), rstride=1, cstride=1, cmap=cm.Blues, alpha=0.3)"
+
+-- | Plot a contour accessing the given elements of the data array
+contourRaw a b c maxA maxB minC =
+  mplot ("ax.contour(data[" # a # "], data[" # b # "], data[" # c # "], zdir='z', offset=" # minC # ")")
+  % mplot ("ax.contour(data[" # a # "], data[" # b # "], data[" # c # "], zdir='x', offset=-" # maxA # ")")
+  % mplot ("ax.contour(data[" # a # "], data[" # b # "], data[" # c # "], zdir='y', offset=" # maxB #")")
+
+-- | Smallest element of a list of lists
+minimum2 l = minimum $ minimum l
+-- | Largest element of a list of lists
+maximum2 l = maximum $ maximum l
+
+-- | Label and set limits of a set of 3D axis
+-- TODO This is a mess, does both more and less than it claims.
+axis3DLabels xs ys zs =
+  mplot "ax.set_xlabel('X')"
+  % mplot ("ax.set_xlim3d(" # minimum2 xs # ", " # maximum2 xs # ")")
+  % mplot "ax.set_ylabel('Y')"
+  % mplot ("ax.set_ylim3d(" # minimum2 ys # ", " # maximum2 ys # ")")
+  % mplot "ax.set_zlabel('Z')"
+  % mplot ("ax.set_zlim3d(" # minimum2 zs # ", " # maximum2 zs # ")")
+
+-- | Draw a bag graph in a subplot
+-- TODO Why do we need this?
+subplotDataBar a width offset opts =
+  mplot $ "ax.bar(np.arange(len(data[" # a # "]))+" # offset # ", data[" # a # "], " # width # options opts # ")"
+
+-- | Create a subplot with the coordinates (r,c,f)
+addSubplot r c f opts = mplot $ "ax = plot.figure().add_subplot(" # r # c # f # options opts # ")"
+
+-- | Access a subplot with the coordinates (r,c,f)
+mplotSubplot r c f opts = mplot $ "ax = plot.subplot(" # r # "," # c # "," # f # options opts # ")"
+
+-- | The default bar with
+barDefaultWidth nr = 1.0 / (fromIntegral nr + 1)
+
+-- | Create a set of labelled bars of a given height
+subplotBarsLabelled valuesList labels optsList =
+  subplotBars valuesList optsList
+  % axisXTickSpacing (length $ head $ valuesList) ((1.0 - barDefaultWidth (length valuesList) / 2.0) :: Double) []
+  % axisXTickLabels labels []
+
+-- | Create a subplot and a set of labelled bars
+-- TODO This is a mess..
+subplotBars valuesList optsList =
+  readData valuesList
+  % addSubplot (1::Int) (1::Int) (1::Int) []
+  % (let (width :: Double) = barDefaultWidth (length valuesList) in
+       foldl1 (%) (zipWith3 (\vs opts i -> subplotDataBar i width (width * i) opts) valuesList optsList [0..]))
+
+-- | Add a title
+addTitle s opts = mplot $ "plot.title('" # s # options opts # "')"
+
+-- | Set the spacing of ticks on the x axis
+axisXTickSpacing nr width opts = mplot $ "ax.set_xticks(np.arange(" # nr # ")+" # width # options opts # ")"
+
+-- | Set the labels on the x axis
+axisXTickLabels labels opts = mplot $ "ax.set_xticklabels( (" # labels # ") " # options opts # " )"
+
+-- | Update the data array to linearly interpolate between array entries
+interpolate a b n =
+  (mplot $ "data[" # b # "] = mlab.stineman_interp(np.linspace(data[" # a # "][0],data[" # a # "][-1]," # n # "),data[" # a # "],data[" # b # "],None)")
+  % (mplot $ "data[" # a # "] = np.linspace(data[" # a # "][0],data[" # a # "][-1]," # n # ")")
+
+-- | Plot x against y interpolating with n steps
+plotInterpolated x y n opts =
+  readData (x, y)
+  % interpolate (0::Int) (1::Int) n
+  % (dataPlot (0::Int) (1::Int) $ def (B "-") opts)
+
+-- | Square up the aspect ratio of a plot.
+squareAxes = mplot "plot.axes().set_aspect('equal')"
+
+-- | Set the rotation of the labels on the x axis to the given number of degrees
+roateAxesLabels degrees = mplot "labels = plot.axes().get_xticklabels()"
+   % mplot "for label in labels:"
+   % mplot ("    label.set_rotation("#degrees#")")
+
+-- | Set the x labels to be vertical
+verticalAxes = mplot "labels = plot.axes().get_xticklabels()"
+   % mplot "for label in labels:"
+   % mplot "    label.set_rotation('vertical')"
+
+-- | Set the x scale to be logarithmic
+logX = mplot "plot.axes().set_xscale('log')"
+
+-- | Set the y scale to be logarithmic
+logY = mplot "plot.axes().set_yscale('log')"
+
+-- | Set limits on the x axis
+xlim l u = mplot $ "plot.xlim([" # l # "," # u # "])"
+
+-- | Set limits on the y axis
+ylim l u = mplot $ "plot.ylim([" # l # "," # u # "])"
+
+-- | A handy function to plot a line between two points give a function and a number o steps
+plotMapLinear f s e n opts = line xs ys opts
+  where xs = mapLinear (\x -> x) s e n
+        ys = mapLinear (\x -> f x) s e n
+
+-- | Plot a line between 0 and the length of the array with the given y values
+line1 y opts = line [0..length y] y opts
+
+matShow d opts =
+  readData d
+  % (mplot $ "plot.matshow(data" # options opts # ")")
+
+-- | Plot a KDE of the given functions with an optional start/end and a bandwidth h
+densityBandwidth l h maybeStartEnd =
+  plotMapLinear f (case maybeStartEnd of
+                    Nothing -> minimum l
+                    (Just (start, _)) -> start)
+                  (case maybeStartEnd of
+                    Nothing -> maximum l
+                    (Just (_, end)) -> end)
+                  100
+                  []
+  where f x = sum (map (\xi -> gaussianPdf x xi h) l) / ((fromIntegral $ length l) * h)
+        gaussianPdf x mu sigma = exp (- sqr (x - mu) / (2 * sigma)) / sqrt (2 * pi * sigma)
+        sqr x = x * x
+
+-- | Plot a KDE of the given functions; a good bandwith will be chosen automatically
+density l maybeStartEnd =
+  densityBandwidth l (((4 * (variance ** 5)) / (fromIntegral $ 3 * length l)) ** (1 / 5) / 3) maybeStartEnd
+  where mean = foldl' (+) 0 l / (fromIntegral $ length l)
+        variance = foldl' (+) 0 (map (\x -> sqr (x - mean)) l) / (fromIntegral $ length l)
+        sqr x = x * x
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,56 @@
+import Test.Tasty
+import Test.Tasty.HUnit
+import System.IO.Unsafe
+import Graphics.Matplotlib
+import System.IO.Temp
+
+main = defaultMain tests
+
+tests :: TestTree
+tests = testGroup "Tests" [unitTests]
+
+tryit m = unsafePerformIO $ withSystemTempFile "a.png" (\file _ -> figure file m)
+
+unitTests = testGroup "Unit tests"
+  [ testCase "m1" $ tryit m1 @?= Right ""
+  , testCase "m2" $ tryit m2 @?= Right ""
+  , testCase "m3" $ tryit m3 @?= Right ""
+  , testCase "m4" $ tryit m4 @?= Right ""
+  , testCase "m5" $ tryit m5 @?= Right ""
+  -- TODO This test case is broken
+  -- , testCase "m6" $ tryit m6 @?= Right ""
+  , testCase "m7" $ tryit m7 @?= Right ""
+  ]
+
+
+-- 
+
+m1 :: Matplotlib
+m1 = do
+  let l = [7, 5, 0, 8, 2, 9, 1, 8, 2, 7, 5, 7, 3, 9, 1, 3, 3, 7, 0, 7, 0, 7, 1, 9, 1, 0, 5, 4, 8, 0, 7, 4, 1, 9, 4, 2, 5, 7, 3, 1, 9, 1, 2, 2, 3, 7, 0, 0, 3, 8, 0, 3, 1, 1, 9, 7, 2, 3, 4, 2, 3, 5, 9, 8, 0, 8, 6, 7, 0, 4, 0, 0, 2, 2, 4, 1, 7, 6, 9, 3, 1, 0, 6, 4, 1, 7, 4, 8, 7, 1, 3, 2, 7, 9, 4, 3, 8, 5, 3]
+  histogram (l :: [Int]) (4 :: Int) []
+
+m2 :: Matplotlib
+m2 = do
+  let l = [7, 5, 0, 8, 2, 9, 1, 8, 2, 7, 5, 7, 3, 9, 1, 3, 3, 7, 0, 7, 0, 7, 1, 9, 1, 0, 5, 4, 8, 0, 7, 4, 1, 9, 4, 2, 5, 7, 3, 1, 9, 1, 2, 2, 3, 7, 0, 0, 3, 8, 0, 3, 1, 1, 9, 7, 2, 3, 4, 2, 3, 5, 9, 8, 0, 8, 6, 7, 0, 4, 0, 0, 2, 2, 4, 1, 7, 6, 9, 3, 1, 0, 6, 4, 1, 7, 4, 8, 7, 1, 3, 2, 7, 9, 4, 3, 8, 5, 3]
+  histogram (l :: [Int]) (4 :: Int) [K "cumulative" "True"]
+
+m3 = scatter [1::Int, 2, 3, 4] [3::Int, 4, 5, 6] []
+
+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
+
+m5 = histogram [(4 :: Double), 4, 2, 4, 3, 4, 4, 2, 2, 3, 2, 0, 1, 1, 0, 4, 2, 3, 5, 4, 3, 1, 0, 1, 3, 2, 1, 3, 1, 1, 1, 1, 0, 2, 2, 1, 3, 3, 1, 4, 2, 0, 2, 0, 3, 1, 1, 0, 1, 1, 0, 2, 1, 1, 7, 3, 1, 4, 1, 3, 5, 2, 2, 5, 2, 3, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] (7 :: Int) []
+   % yLabel "number of queries"
+   % xLabel "true positives"
+
+m6 = subplotBarsLabelled
+       [[(40 :: Double), 50, 20, 50], [10, 20, 30, 40], [40, 50, 20, 50]]
+       ["a", "b", "c", "d"] []
+      % addTitle "Wee a title" []
+      % xLabel "X"
+      % yLabel "Y"
+
+m7 = densityBandwidth [-2.1, -1.3, -0.4, 1.9, 5.1, 6.2] 2.25 (Just (-6, 11))
