diff --git a/Changes.md b/Changes.md
new file mode 100644
--- /dev/null
+++ b/Changes.md
@@ -0,0 +1,15 @@
+# Change log for the `gnuplot` Haskell binding
+
+## 0.5.7:
+
+ * `Gnuplot.Terminal.QT`
+
+ * `Gnuplot.Execute`:
+   Do longer call `pgnuplot` on Windows.
+   It is gone in gnuplot-5.0 in January 2015.
+
+## 0.5.5:
+
+ * `Gnuplot.Utility.quote` bugfix:
+   Do not escape printable non-ASCII characters
+   because gnuplot has no universal escaping support for Unicode codepoints.
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -1,14 +1,26 @@
 ghci:	ghci-tmp
 
 ghci-tmp:
-	ghci -Wall -i:src:execute/tmp src/Graphics/Gnuplot/Simple.hs
+	ghci -Wall -i:src:dist/build/autogen:execute/tmp src/Graphics/Gnuplot/Simple.hs
 
 ghci-pipe:
-	ghci -Wall -i:src:execute/pipe src/Graphics/Gnuplot/Simple.hs
+	ghci -Wall -i:src:dist/build/autogen:execute/pipe src/Graphics/Gnuplot/Simple.hs
 
 ghci-shell:
-	ghci -Wall -i:src:execute/shell src/Graphics/Gnuplot/Simple.hs
+	ghci -Wall -i:src:dist/build/autogen:execute/shell src/Graphics/Gnuplot/Simple.hs
 
 ghci-demo:
-	ghci -Wall -i:src:execute/tmp src/Demo.hs
+	ghci -Wall -i:src:dist/build/autogen:execute/tmp src/Demo.hs
 
+testbuild:
+	runhaskell Setup configure --user -f buildExamples
+	runhaskell Setup build
+	runhaskell Setup haddock
+
+	runhaskell Setup clean
+	runhaskell Setup configure --user -f executePipe
+	runhaskell Setup build
+
+	runhaskell Setup clean
+	runhaskell Setup configure --user -f executeShell
+	runhaskell Setup build
diff --git a/data/runtime.data b/data/runtime.data
new file mode 100644
--- /dev/null
+++ b/data/runtime.data
@@ -0,0 +1,52 @@
+#description: runtimes over input size
+1		6.355182636689504e-5
+100		1.0948364162371856e-2
+199		2.2883437011933076e-2
+298		3.6984818514001545e-2
+397		5.278430392525412e-2
+496		6.556876441607734e-2
+595		8.094012753488622e-2
+694		9.764933499422945e-2
+793		0.11376420890800729
+892		0.1303682446197088
+991		0.1494559487429532
+1090		0.16847618759261968
+1189		0.1870789716535227
+1288		0.20706133347400274
+1387		0.22577923641544467
+1486		0.24842725050880543
+1585		0.2687356359522487
+1684		0.29853175822408823
+1783		0.30569358846083045
+1882		0.34811570598277525
+1981		0.37377121156830634
+2080		0.3976917936986544
+2179		0.4248938615564355
+2278		0.4563135662584595
+2377		0.4827751635322885
+2476		0.5078150705665049
+2575		0.5308599307954707
+2674		0.5731755964461464
+2773		0.5953289658030824
+2872		0.6123024067073677
+2971		0.5644368814660525
+3070		0.6892736894713817
+3169		0.7198984790477585
+3268		0.75820146082337
+3367		0.7922666002868061
+3466		0.8332174605827827
+3565		0.8727248373231685
+3664		0.9070082204645331
+3763		0.941051246582755
+3862		0.9763012261824174
+3961		1.0146614115691386
+4060		1.053540654379474
+4159		1.1035736989768552
+4258		1.1434341162864607
+4357		1.1855544921484864
+4456		0.935738517553156
+4555		1.2367099547145342
+4654		1.2909424329951484
+4753		1.3264400538531225
+4852		1.3685529705611144
+4951		1.4105760332671073
diff --git a/execute/shell/Graphics/Gnuplot/Execute.hs b/execute/shell/Graphics/Gnuplot/Execute.hs
--- a/execute/shell/Graphics/Gnuplot/Execute.hs
+++ b/execute/shell/Graphics/Gnuplot/Execute.hs
@@ -1,9 +1,10 @@
 module Graphics.Gnuplot.Execute where
 
+import Graphics.Gnuplot.Utility (semiColonConcat, )
+
+import Shell.Utility.Quote as Quote
 import System.Exit (ExitCode, )
 import System.Cmd (system, )
-import Graphics.Gnuplot.Utility
-   (quote, semiColonConcat, )
 
 
 simple ::
@@ -12,7 +13,7 @@
    -> IO ExitCode
 simple program options =
    let cmd =
-          "sh -c 'echo " ++ quote (semiColonConcat program) ++
+          "sh -c 'echo " ++ Quote.minimal (semiColonConcat program) ++
                  " | gnuplot " ++ unwords options ++ "'"
    in  do --putStrLn cmd
           system cmd
diff --git a/execute/tmp/Graphics/Gnuplot/Execute.hs b/execute/tmp/Graphics/Gnuplot/Execute.hs
--- a/execute/tmp/Graphics/Gnuplot/Execute.hs
+++ b/execute/tmp/Graphics/Gnuplot/Execute.hs
@@ -1,7 +1,9 @@
 module Graphics.Gnuplot.Execute where
 
+import qualified System.IO as IO
+import System.IO.Temp (withSystemTempFile, )
 import System.Exit (ExitCode, )
-import System.Cmd (rawSystem, )
+import System.Process (readProcessWithExitCode, )
 
 
 tmpScript :: FilePath
@@ -12,6 +14,12 @@
    -> [String] {-^ Options for gnuplot -}
    -> IO ExitCode
 simple program options =
-   do writeFile tmpScript (unlines program)
-      -- putStrLn cmd
-      rawSystem "gnuplot" $ options ++ [tmpScript]
+   withSystemTempFile tmpScript $ \path handle -> do
+      IO.hPutStr handle (unlines program)
+      IO.hClose handle
+      -- putStrLn $ showCommandForUser "gnuplot" (options ++ [path])
+      (exitCode, _out, _err) <-
+         readProcessWithExitCode "gnuplot" (options ++ [path]) []
+      -- putStr out
+      -- putStr err
+      return exitCode
diff --git a/gnuplot.cabal b/gnuplot.cabal
--- a/gnuplot.cabal
+++ b/gnuplot.cabal
@@ -1,6 +1,7 @@
+Cabal-Version:    2.2
 Name:             gnuplot
-Version:          0.3.4
-License:          BSD3
+Version:          0.5.7
+License:          BSD-3-Clause
 License-File:     LICENSE
 Author:           Henning Thielemann <haskell@henning-thielemann.de>
 Maintainer:       Henning Thielemann <haskell@henning-thielemann.de>
@@ -12,8 +13,9 @@
    This is a wrapper to gnuplot
    which lets you create 2D and 3D plots.
    .
-   Start a simple session with @make ghci@.
-   This loads the module "Graphics.Gnuplot.Simple"
+   Start a simple session with @cabal repl@.
+   If not already loaded, call @:module Graphics.Gnuplot.Simple@
+   in order to load "Graphics.Gnuplot.Simple"
    which is ready for use in GHCi.
    It does not address all fancy gnuplot features
    in order to stay simple.
@@ -22,27 +24,36 @@
    I recommend "Graphics.Gnuplot.Advanced".
    This module contains also an overview
    of the hierarchy of objects.
+   .
    Examples for using this interface can be found in the "Demo" module.
+   In order to compile this and install an example data file,
+   use the Cabal flag @buildExamples@:
    .
+   > $ cabal install -fbuildExamples gnuplot
+   .
    With the Cabal flags executePipe and executeShell
    you can switch to more convenient
    but probably less portable ways
    of feeding gnuplot with a script.
-Tested-With:       GHC==6.8.2
-Cabal-Version:     >=1.2
+   .
+   Alternative packages: @plot@, @HPlot@, @Chart@, @textPlot@, @easyplot@
+Tested-With:       GHC==7.4.2, GHC==7.6.3, GHC==7.8.4, GHC==7.10.3
+Tested-With:       GHC==8.2.1, GHC==8.6.5
 Build-Type:        Simple
 Extra-Source-Files:
   Makefile
-  execute/tmp/Graphics/Gnuplot/Execute.hs
-  execute/pipe/Graphics/Gnuplot/Execute.hs
-  execute/shell/Graphics/Gnuplot/Execute.hs
+  Changes.md
+Data-Files:
+  data/runtime.data
 
-Flag splitBase
-  description: Choose the new smaller, split-up base package.
+Source-Repository this
+  Tag:         0.5.7
+  Type:        darcs
+  Location:    http://code.haskell.org/gnuplot/
 
-Flag buildTests
-  description: Build test executables
-  default:     False
+Source-Repository head
+  Type:        darcs
+  Location:    http://code.haskell.org/gnuplot/
 
 Flag buildExamples
   description: Build example executables
@@ -58,20 +69,21 @@
 
 Library
   Build-Depends:
-    array >= 0.1 && <0.4,
-    containers >= 0.1 && <0.4,
-    utility-ht >= 0.0.1 && < 0.1,
-    monoid-transformer >= 0.0.2 && <0.1
-  If flag(splitBase)
-    Build-Depends:
-      base >= 2 && <6,
-      process >= 1.0 && < 1.1,
-      time >= 1.1 && < 1.2,
-      old-locale >= 1.0 && < 1.1
-  Else
-    Build-Depends:
-      base >= 1.0 && < 2
+    filepath >=1.1 && <1.5,
+    temporary >=1.1 && <1.4,
+    array >=0.1 && <0.6,
+    containers >=0.1 && <0.7,
+    utility-ht >=0.0.12 && <0.1,
+    data-accessor-transformers >=0.2.1 && <0.3,
+    data-accessor >=0.2.2 && <0.3,
+    transformers >=0.3 && <0.7,
+    semigroups >=0.1 && <1.0,
+    deepseq >=1.0 && <1.5,
+    process >=1.0 && <1.7,
+    time >=1.5 && <1.14,
+    base >=2 && <5
 
+  Default-Language: Haskell98
   GHC-Options: -Wall
 
   Hs-Source-Dirs: src
@@ -80,6 +92,7 @@
   Else
     If flag(executeShell)
       Hs-Source-Dirs: execute/shell
+      Build-Depends: shell-utility >=0.0 && <0.2
     Else
       Hs-Source-Dirs: execute/tmp
 
@@ -87,38 +100,68 @@
     Graphics.Gnuplot.Simple
     Graphics.Gnuplot.Time
     Graphics.Gnuplot.Advanced
+    Graphics.Gnuplot.Display
+    Graphics.Gnuplot.File
+    Graphics.Gnuplot.Terminal
+    Graphics.Gnuplot.Terminal.Default
     Graphics.Gnuplot.Terminal.PostScript
     Graphics.Gnuplot.Terminal.PNG
     Graphics.Gnuplot.Terminal.SVG
+    Graphics.Gnuplot.Terminal.WXT
+    Graphics.Gnuplot.Terminal.QT
     Graphics.Gnuplot.Terminal.X11
+    Graphics.Gnuplot.Encoding
     Graphics.Gnuplot.Frame
     Graphics.Gnuplot.Frame.Option
     Graphics.Gnuplot.Frame.OptionSet
+    Graphics.Gnuplot.Frame.OptionSet.Style
+    Graphics.Gnuplot.Frame.OptionSet.Histogram
+    Graphics.Gnuplot.Plot
     Graphics.Gnuplot.Plot.TwoDimensional
     Graphics.Gnuplot.Plot.ThreeDimensional
+    Graphics.Gnuplot.Graph
     Graphics.Gnuplot.Graph.TwoDimensional
     Graphics.Gnuplot.Graph.ThreeDimensional
     Graphics.Gnuplot.LineSpecification
+    Graphics.Gnuplot.ColorSpecification
     Graphics.Gnuplot.MultiPlot
+    Graphics.Gnuplot.Value.Atom
+    Graphics.Gnuplot.Value.Tuple
+    Graphics.Gnuplot.Value.ColumnSet
   Other-Modules:
     Graphics.Gnuplot.Private.LineSpecification
+    Graphics.Gnuplot.Private.ColorSpecification
     Graphics.Gnuplot.Private.Plot
     Graphics.Gnuplot.Private.Frame
     Graphics.Gnuplot.Private.FrameOption
     Graphics.Gnuplot.Private.FrameOptionSet
-    Graphics.Gnuplot.Private.GraphType
     Graphics.Gnuplot.Private.Graph
     Graphics.Gnuplot.Private.Graph2D
     Graphics.Gnuplot.Private.Graph3D
+    Graphics.Gnuplot.Private.Graph2DType
+    Graphics.Gnuplot.Private.Graph3DType
     Graphics.Gnuplot.Private.GraphEmpty
+    Graphics.Gnuplot.Private.Terminal
+    Graphics.Gnuplot.Private.Encoding
+    Graphics.Gnuplot.Private.Display
+    Graphics.Gnuplot.Private.File
+    Graphics.Gnuplot.Private.Command
     Graphics.Gnuplot.Utility
     Graphics.Gnuplot.Execute
-    Graphics.Gnuplot.Display
-    Graphics.Gnuplot.Terminal
 
 Executable gnuplot-demo
-  If !flag(buildExamples)
+  If flag(buildExamples)
+    Build-Depends:
+      gnuplot,
+      time,
+      array,
+      filepath,
+      utility-ht,
+      base
+  Else
     Buildable: False
+  Default-Language: Haskell98
   GHC-Options: -Wall
-  Hs-Source-Dirs: src, execute/tmp
-  Main-Is: Demo.hs
+  Main-Is: src/Demo.hs
+  Other-Modules: Paths_gnuplot
+  Autogen-Modules: Paths_gnuplot
diff --git a/src/Demo.hs b/src/Demo.hs
--- a/src/Demo.hs
+++ b/src/Demo.hs
@@ -1,81 +1,225 @@
 module Main where
 
-import qualified Graphics.Gnuplot.Advanced as Plot
-import qualified Graphics.Gnuplot.Terminal.X11 as X11
+import qualified Graphics.Gnuplot.Advanced as GP
 
 import qualified Graphics.Gnuplot.MultiPlot as MultiPlot
 
 import qualified Graphics.Gnuplot.Frame as Frame
-import qualified Graphics.Gnuplot.Frame.Option as Opt
 import qualified Graphics.Gnuplot.Frame.OptionSet as Opts
+import qualified Graphics.Gnuplot.Frame.OptionSet.Style as OptsStyle
+import qualified Graphics.Gnuplot.Frame.OptionSet.Histogram as Histogram
 
+import qualified Graphics.Gnuplot.Graph as Graph
+
 import qualified Graphics.Gnuplot.Plot.ThreeDimensional as Plot3D
+import qualified Graphics.Gnuplot.Graph.ThreeDimensional as Graph3D
 
 import qualified Graphics.Gnuplot.Plot.TwoDimensional as Plot2D
 import qualified Graphics.Gnuplot.Graph.TwoDimensional as Graph2D
 import Graphics.Gnuplot.Plot.TwoDimensional (linearScale, )
 
+import qualified Graphics.Gnuplot.LineSpecification as LineSpec
+import Graphics.Gnuplot.Value.Tuple (Label(Label))
+
+import qualified Data.Time as Time
+
+import qualified Paths_gnuplot as Path
+import System.FilePath ((</>), )
+
+import Control.Monad (liftM2, )
 import Data.Array (listArray, )
-import Data.Monoid (mappend, )
+import Data.Foldable (foldMap, )
+import Data.Monoid (mappend, mconcat, )
+import Data.Tuple.HT (mapFst)
 
 
-simple2d :: Plot2D.T
+simple2d :: Plot2D.T Double Double
 simple2d =
-   Plot2D.function (linearScale 100 (-10,10::Double)) sin
+   Plot2D.function Graph2D.lines
+      (linearScale 100 (-10,10)) sin
 
-circle2d :: Plot2D.T
+circle2d :: Plot2D.T Double Double
 circle2d =
-   fmap
-      (Graph2D.typ Graph2D.points)
-      (Plot2D.parameterFunction
-         (linearScale 24 (-pi,pi::Double))
-         (\t -> (cos t, sin t)))
+   Plot2D.parameterFunction Graph2D.lines
+      (linearScale 24 (-pi,pi))
+      (\t -> (cos t, sin t))
 
-overlay2d :: Frame.T Graph2D.T
+list2d :: Plot2D.T Int Integer
+list2d =
+   Plot2D.list Graph2D.listPoints [0,1,1,2,3,5,8,13]
+
+labels2d :: Plot2D.T Double Double
+labels2d =
+   Plot2D.list Graph2D.labels $
+   flip map [1..12] $
+   \t -> (let w = fromInteger t*2*pi/12 in (sin w, cos w), Label $ show t)
+
+candle2d :: Plot2D.T Time.Day Double
+candle2d =
+   Plot2D.list Graph2D.candleSticks $
+   zip [(Time.fromGregorian 2008 01 01) ..] $
+   flip map (linearScale 32 (0,2*pi)) $
+   \t -> (-sin t, -2*sin t, 2*sin t, sin t)
+
+image2d :: Plot2D.T Double Double
+image2d =
+   case linearScale 300 (-20,20) of
+      xs ->
+         Plot2D.function Graph2D.image (liftM2 (,) xs xs) $
+            \(x,y) -> cos (sqrt (x*x+x*y+y*y))
+
+overlay2d :: Frame.T (Graph2D.T Double Double)
 overlay2d =
-   Frame.cons (Opts.size 1 0.4 $ Opts.remove Opt.key $ Opts.deflt) $
-   Plot2D.function (linearScale 100 (-pi,pi::Double)) cos
+   Frame.cons (Opts.size 1 0.4 $ defltOpts) $
+   Plot2D.function Graph2D.lines (linearScale 100 (-pi,pi)) cos
    `mappend`
    circle2d
 
-multiplot2d :: MultiPlot.T
-multiplot2d =
-   let opts :: Opts.T graph
-       opts =
-          Opts.remove Opt.key $
+histogram2d :: Frame.T (Graph2D.T Int Double)
+histogram2d =
+   Frame.cons (
+      Opts.title "Comparison of how well software revisions perform on each hardware version" $
+      Histogram.clusteredGap 2 $
+      Opts.boxwidthAbsolute 0.9 $
+      OptsStyle.fillBorderLineType (-1) $
+      OptsStyle.fillSolid $
+      Opts.keyOutside $
+      Opts.xTicks2d
+         [("220", 0), ("320", 1), ("420", 2), ("520", 3), ("620", 4), ("720", 5)] $
+      Opts.deflt) $
+   foldMap (\(title,dat) ->
+      fmap (Graph2D.lineSpec (LineSpec.title title LineSpec.deflt)) $
+      Plot2D.list Graph2D.histograms dat) $
+   ("1.0011", [102, 213, 378, 408, 840,  920]) :
+   ("1.0012", [152, 233, 388, 433, 850, 1200]) :
+   ("1.0013", [172, 263, 408, 463, 860, 1500]) :
+   ("1.0014", [192, 293, 458, 483, 890, 2000]) :
+   []
+
+names2d :: Frame.T (Graph2D.T Double Double)
+names2d =
+   let domain = (-10,10)
+       frameOpts =
+          Opts.xRange2d domain $
+          Opts.yRange2d (-1.5,1.5) $
           Opts.deflt
-       (prefix,suffix) =
+   in  Frame.cons frameOpts $
+       Plot2D.functionsWithLineSpec Graph2D.lines (linearScale 100 domain) $
+       map (mapFst (flip LineSpec.title LineSpec.deflt)) $
+       ("sin", sin) :
+       ("cos", cos) :
+       ("tan", tan) :
+       []
+
+filled2d :: Frame.T (Graph2D.T Double Double)
+filled2d =
+   let scale = linearScale 100 (-10,10)
+       wave style (lower,upper) =
+          Plot2D.function style scale $
+          (\y -> (lower*y, upper*y)) . sin
+   in  Frame.cons (Opts.key False Opts.deflt) $ mconcat $
+       wave Graph2D.filledStripeAbove (1.0, 1.3) :
+       wave Graph2D.filledStripeBelow (1.0, 1.3) :
+       wave Graph2D.filledStripe      (0.7, 1.0) :
+       []
+
+file2d :: FilePath -> FilePath -> Frame.T (Graph2D.T Int Double)
+file2d path file =
+   let lineSpec =
+          Graph2D.lineSpec $
+          LineSpec.title "runtimes" $
+          LineSpec.lineWidth 2.5 $
+          LineSpec.deflt
+       frameOpts =
+          Opts.xLabel "input size" $
+          Opts.yLabel "runtime (ms)" $
+          Opts.title ("Graph from " ++ file) $
+          Opts.deflt
+   in  Frame.cons frameOpts $ fmap lineSpec $
+       Plot2D.pathFromFile Graph2D.lines (path </> file) 1 2
+
+mixed2d :: MultiPlot.T
+mixed2d =
+   MultiPlot.simpleFromPartArray $
+   listArray ((0,0), (0,2)::(Int,Int)) $
+   MultiPlot.partFromPlot circle2d :
+   MultiPlot.partFromFrame
+      (Frame.cons (Opts.sizeSquare $ Opts.xFormat "%m-%d" $ defltOpts) $
+       candle2d) :
+   MultiPlot.partFromPlot list2d :
+   []
+
+{-
+The size settings of overlay2d interfer badly with the other plots,
+because 'unset' does not restore the size to the multiplot settings.
+-}
+size2d :: MultiPlot.T
+size2d =
+   MultiPlot.simpleFromPartArray $
+   listArray ((0,0), (0,2)::(Int,Int)) $
+   MultiPlot.partFromPlot candle2d :
+   MultiPlot.partFromFrame
+      (Frame.cons (Opts.yLabel "Fibonacci" $ defltOpts) list2d) :
+   MultiPlot.partFromPlot candle2d :
+   []
+
+defltOpts :: Graph.C graph => Opts.T graph
+defltOpts = Opts.key False $ Opts.deflt
+
+wave3d :: Frame.T (Graph3D.T Double Double Double)
+wave3d =
+   let meshNodes = linearScale 20 (-2,2)
+   in  Frame.cons
+          (Opts.grid True $
+           Opts.view 42 17 1 1 $
+           Opts.xRange3d (-2.5,2.5) $
+           Opts.yRange3d (-2.5,2.5) $
+           defltOpts) $
+       Plot3D.surface meshNodes meshNodes (\x y -> cos(x*x+y*y))
+
+lissajous3d :: Frame.T (Graph3D.T Double Double Double)
+lissajous3d =
+   let t = linearScale 300 (-pi, pi)
+       f n = map (sin . (*) n) t
+   in  Frame.cons defltOpts $
+       Plot3D.cloud Graph3D.lines $
+       zip3 (f 3) (f 4) (f 9)
+
+multiplot :: MultiPlot.T
+multiplot =
+   let (prefix,suffix) =
           splitAt 7 $
           map MultiPlot.partFromFrame $
           map (\k ->
-             Frame.cons (Opts.xRange (-1,1) opts) $
-             Plot2D.parameterFunction
+             Frame.cons (Opts.xRange2d (-1,1) defltOpts) $
+             Plot2D.parameterFunction Graph2D.lines
                 (linearScale 48 (-pi,pi::Double))
                 (\t -> (cos (t + pi/7*fromInteger k), sin (2*t)))) $
           [0..13]
-       meshNodes = linearScale 20 (-2,2::Double)
-{-
-       center =
-          MultiPlot.partFromFrame $
-          Frame.empty
--}
-       center =
-          MultiPlot.partFromFrame $
-          Frame.cons
-             (Opts.xRange (-2.5,2.5) $
-              Opts.yRange (-2.5,2.5) $
-              opts) $
-          (Plot3D.function
-             meshNodes meshNodes
-             (\x y -> cos(x*x+y*y)))
-   in  MultiPlot.simpleFromPartArray $
-       listArray ((0::Int,0::Int), (2,4)) $
+--       center = MultiPlot.partFromFrame Frame.empty
+       center = MultiPlot.partFromFrame wave3d
+   in  MultiPlot.title "multiplot of 2d and 3d graphics" $
+       MultiPlot.simpleFromPartArray $
+       listArray ((0,0), (2,4)::(Int,Int)) $
        prefix ++ center : suffix
 
 
 main :: IO ()
-main =
-   do Plot.plot X11.cons simple2d
-      Plot.plot X11.cons overlay2d
-      Plot.plot X11.cons multiplot2d
-      return ()
+main = sequence_ $
+   GP.plotDefault simple2d :
+   GP.plotDefault list2d :
+   GP.plotDefault labels2d :
+   GP.plotDefault candle2d :
+   GP.plotDefault image2d :
+   GP.plotDefault histogram2d :
+   GP.plotDefault names2d :
+   GP.plotDefault filled2d :
+   GP.plotDefault overlay2d :
+   (GP.plotDefault . flip file2d "runtime.data"
+      =<< fmap (</> "data") Path.getDataDir) :
+   GP.plotDefault mixed2d :
+   GP.plotDefault size2d :
+   GP.plotDefault wave3d :
+   GP.plotDefault lissajous3d :
+   GP.plotDefault multiplot :
+   []
diff --git a/src/Graphics/Gnuplot/Advanced.hs b/src/Graphics/Gnuplot/Advanced.hs
--- a/src/Graphics/Gnuplot/Advanced.hs
+++ b/src/Graphics/Gnuplot/Advanced.hs
@@ -34,7 +34,7 @@
 of learning gnuplot script syntax,
 it happens frequently that people ask,
 how to express a certain gnuplot script using this package.
-Thus let's annotate the gnuplot script generated by @Demo.multiplot2d@
+Thus let's annotate the gnuplot script generated by @Demo.multiplot@
 in order to show, what belongs to where:
 
 > # the terminal selection is part of the 'plot' command of this module
@@ -71,20 +71,29 @@
 -}
 module Graphics.Gnuplot.Advanced (
     plot,
+    plotDefault,
+    plotSync,
+    plotAsync,
+    fileContents,
   ) where
 
 import qualified Graphics.Gnuplot.Private.FrameOptionSet as OptionSet
-import qualified Graphics.Gnuplot.Display as Display
-
-import qualified Graphics.Gnuplot.Terminal as Terminal
-import qualified Graphics.Gnuplot.Execute as Exec
+import qualified Graphics.Gnuplot.Private.Display as Display
+import qualified Graphics.Gnuplot.Private.Terminal as Terminal
+import qualified Graphics.Gnuplot.Terminal.Default as DefaultTerm
+import qualified Graphics.Gnuplot.File as File
 
+import qualified Graphics.Gnuplot.Private.Command as Cmd
+import Control.Concurrent (ThreadId, forkIO, )
 import System.Exit (ExitCode, )
-import Data.Monoid (Monoid, ) -- for Haddock
-import qualified Data.Monoid.State as State
-import Data.List (intersperse, )
 
+import qualified Control.Monad.Trans.Reader as MR
+import qualified Control.Monad.Trans.State as MS
+import Data.Monoid (Monoid, mempty, )
+import Control.Functor.HT (void, )
+import Data.Tuple.HT (mapFst, )
 
+
 -- * User front-end
 
 
@@ -95,24 +104,86 @@
 For interactive sessions,
 better use "Graphics.Gnuplot.Simple".
 @gfx@ must be one of the types @Plot@, @Frame@, @MultiPlot@.
+
+This function runs gnuplot asynchronously
+for interactive terminals (X11, WX)
+and synchronously for file terminals (PostScript, PNG, etc.).
+This emulates the behaviour of @gnuplot --persist@.
+However, when running asynchronous
+we cannot obtain a real 'ExitCode'.
+Thus, in this case we will always return 'ExitSuccess'.
 -}
 plot ::
    (Terminal.C terminal, Display.C gfx) =>
    terminal -> gfx -> IO ExitCode
 plot term gfx =
+   case Terminal.canonical term of
+      cterm ->
+         Cmd.asyncIfInteractive
+            (Terminal.interactive cterm)
+            (plotCore cterm gfx)
+
+plotAsync ::
+   (Terminal.C terminal, Display.C gfx) =>
+   terminal -> gfx -> IO ThreadId
+plotAsync term gfx = forkIO $ void $ plotSync term gfx
+
+plotSync ::
+   (Terminal.C terminal, Display.C gfx) =>
+   terminal -> gfx -> IO ExitCode
+plotSync = plotCore . Terminal.canonical
+
+plotCore ::
+   (Display.C gfx) =>
+   Terminal.T -> gfx -> IO ExitCode
+plotCore term gfx =
+   Cmd.run $ render term gfx
+
+{- |
+Return the gnuplot script and the curve files
+corresponding to your plot data.
+The first parameter is the directory where the curve files are located.
+This directory is baked into the gnuplot script
+and the paths of the curve files.
+
+Don't make any assumptions about the structure of the files.
+Feeding the files to gnuplot, archiving them or study them
+are the intended uses of them.
+-}
+fileContents ::
+   (Terminal.C terminal, Display.C gfx) =>
+   FilePath -> terminal -> gfx -> (String, [File.T])
+fileContents dir term gfx =
+   mapFst unlines $ render (Terminal.canonical term) gfx dir
+
+render ::
+   Display.C gfx =>
+   Terminal.T -> gfx -> FilePath -> ([String], [File.T])
+render term gfx dir =
    let body =
-          State.evaluate (0, OptionSet.decons OptionSet.deflt) $
+          flip MR.runReader dir $
+          flip MS.evalStateT (0, OptionSet.initial) $
           Display.runScript $
           Display.toScript gfx
-   in  do mapM_ Display.writeData (Display.files body)
-          Exec.simple
-             (formatTerminal term : Display.commands body)
-             ["-persist"]
+   in  (Terminal.format term ++ Display.commands body,
+        Display.files body)
 
-formatTerminal ::
-   (Terminal.C terminal) =>
-   terminal -> String
-formatTerminal term =
-   let (Terminal.Cons options commands) = Terminal.canonical term
-   in  concat $ intersperse "; " $
-          ("set terminal " ++ unwords options) : commands
+
+{- |
+Plot using the default gnuplot terminal.
+-}
+plotDefault ::
+   (Display.C gfx) =>
+   gfx -> IO ExitCode
+plotDefault =
+   plot DefaultTerm.cons
+
+{-
+In the module introduction we refer to Monoid.
+That is we must import Monoid module in order to make Haddock happy.
+On the other hand we do not use Monoid in the module body,
+thus GHC emits a warning.
+This dummy declaration makes both GHC and Haddock happy.
+-}
+_haddockDummy :: Monoid a => a
+_haddockDummy = mempty
diff --git a/src/Graphics/Gnuplot/ColorSpecification.hs b/src/Graphics/Gnuplot/ColorSpecification.hs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/Gnuplot/ColorSpecification.hs
@@ -0,0 +1,307 @@
+module Graphics.Gnuplot.ColorSpecification (
+   T,
+   rgb,
+   rgb8,
+   name,
+   paletteFrac,
+
+   white,
+   black,
+   gray0,
+   grey0,
+   gray10,
+   grey10,
+   gray20,
+   grey20,
+   gray30,
+   grey30,
+   gray40,
+   grey40,
+   gray50,
+   grey50,
+   gray60,
+   grey60,
+   gray70,
+   grey70,
+   gray80,
+   grey80,
+   gray90,
+   grey90,
+   gray100,
+   grey100,
+   gray,
+   grey,
+   lightGray,
+   lightGrey,
+   darkGray,
+   darkGrey,
+   red,
+   lightRed,
+   darkRed,
+   yellow,
+   lightYellow,
+   darkYellow,
+   green,
+   lightGreen,
+   darkGreen,
+   springGreen,
+   forestGreen,
+   seaGreen,
+   blue,
+   lightBlue,
+   darkBlue,
+   midnightBlue,
+   navy,
+   mediumBlue,
+   royalblue,
+   skyblue,
+   cyan,
+   lightCyan,
+   darkCyan,
+   magenta,
+   lightMagenta,
+   darkMagenta,
+   turquoise,
+   lightTurquoise,
+   darkTurquoise,
+   pink,
+   lightPink,
+   darkPink,
+   coral,
+   lightCoral,
+   orangeRed,
+   salmon,
+   lightSalmon,
+   darkSalmon,
+   aquamarine,
+   khaki,
+   darkKhaki,
+   goldenrod,
+   lightGoldenrod,
+   darkGoldenrod,
+   gold,
+   beige,
+   brown,
+   orange,
+   darkOrange,
+   violet,
+   darkViolet,
+   plum,
+   purple,
+
+   ) where
+
+import qualified Graphics.Gnuplot.Private.ColorSpecification as Color
+import Graphics.Gnuplot.Private.ColorSpecification (T, )
+import Data.Ord.HT (limit, )
+import Data.Word (Word8, )
+
+
+{- |
+Color components for Red, Green, Blue, must be in the range @[0,1]@.
+-}
+rgb :: Double -> Double -> Double -> T
+rgb r g b =
+   rgb8 (word8FromDouble r) (word8FromDouble g) (word8FromDouble b)
+
+word8FromDouble :: Double -> Word8
+word8FromDouble c =
+   round (limit (0,1) c * 255)
+
+rgb8 :: Word8 -> Word8 -> Word8 -> T
+rgb8 = Color.RGB8
+
+paletteFrac :: Double -> T
+paletteFrac = Color.PaletteFrac
+
+{- |
+Specify a color by name.
+You are responsible for choosing an existing name in gnuplot.
+If your color is available as Haskell variable in this module,
+then prefer this one.
+-}
+name :: String -> T
+name = Color.Name
+
+
+{-
+This function chooses how we represent below colors in gnuplot.
+If we use RGB values then we stay independent from the available color names
+in the current gnuplot version.
+If we use color names, then the generated gnuplot scripts are more readable.
+-}
+makeColor :: String -> Int -> Word8 -> Word8 -> Word8 -> T
+makeColor str _ _ _ _ = name str
+
+
+white,
+ black,
+ gray0,
+ grey0,
+ gray10,
+ grey10,
+ gray20,
+ grey20,
+ gray30,
+ grey30,
+ gray40,
+ grey40,
+ gray50,
+ grey50,
+ gray60,
+ grey60,
+ gray70,
+ grey70,
+ gray80,
+ grey80,
+ gray90,
+ grey90,
+ gray100,
+ grey100,
+ gray,
+ grey,
+ lightGray,
+ lightGrey,
+ darkGray,
+ darkGrey,
+ red,
+ lightRed,
+ darkRed,
+ yellow,
+ lightYellow,
+ darkYellow,
+ green,
+ lightGreen,
+ darkGreen,
+ springGreen,
+ forestGreen,
+ seaGreen,
+ blue,
+ lightBlue,
+ darkBlue,
+ midnightBlue,
+ navy,
+ mediumBlue,
+ royalblue,
+ skyblue,
+ cyan,
+ lightCyan,
+ darkCyan,
+ magenta,
+ lightMagenta,
+ darkMagenta,
+ turquoise,
+ lightTurquoise,
+ darkTurquoise,
+ pink,
+ lightPink,
+ darkPink,
+ coral,
+ lightCoral,
+ orangeRed,
+ salmon,
+ lightSalmon,
+ darkSalmon,
+ aquamarine,
+ khaki,
+ darkKhaki,
+ goldenrod,
+ lightGoldenrod,
+ darkGoldenrod,
+ gold,
+ beige,
+ brown,
+ orange,
+ darkOrange,
+ violet,
+ darkViolet,
+ plum,
+ purple :: T
+
+{-
+gnuplot> show colornames
+-}
+
+white             = makeColor "white"              0xffffff 255 255 255
+black             = makeColor "black"              0x000000   0   0   0
+gray0             = makeColor "gray0"              0x000000   0   0   0
+grey0             = makeColor "grey0"              0x000000   0   0   0
+gray10            = makeColor "gray10"             0x1a1a1a  26  26  26
+grey10            = makeColor "grey10"             0x1a1a1a  26  26  26
+gray20            = makeColor "gray20"             0x333333  51  51  51
+grey20            = makeColor "grey20"             0x333333  51  51  51
+gray30            = makeColor "gray30"             0x4d4d4d  77  77  77
+grey30            = makeColor "grey30"             0x4d4d4d  77  77  77
+gray40            = makeColor "gray40"             0x666666 102 102 102
+grey40            = makeColor "grey40"             0x666666 102 102 102
+gray50            = makeColor "gray50"             0x7f7f7f 127 127 127
+grey50            = makeColor "grey50"             0x7f7f7f 127 127 127
+gray60            = makeColor "gray60"             0x999999 153 153 153
+grey60            = makeColor "grey60"             0x999999 153 153 153
+gray70            = makeColor "gray70"             0xb3b3b3 179 179 179
+grey70            = makeColor "grey70"             0xb3b3b3 179 179 179
+gray80            = makeColor "gray80"             0xcccccc 204 204 204
+grey80            = makeColor "grey80"             0xcccccc 204 204 204
+gray90            = makeColor "gray90"             0xe5e5e5 229 229 229
+grey90            = makeColor "grey90"             0xe5e5e5 229 229 229
+gray100           = makeColor "gray100"            0xffffff 255 255 255
+grey100           = makeColor "grey100"            0xffffff 255 255 255
+gray              = makeColor "gray"               0xbebebe 190 190 190
+grey              = makeColor "grey"               0xbebebe 190 190 190
+lightGray         = makeColor "light-gray"         0xd3d3d3 211 211 211
+lightGrey         = makeColor "light-grey"         0xd3d3d3 211 211 211
+darkGray          = makeColor "dark-gray"          0xa9a9a9 169 169 169
+darkGrey          = makeColor "dark-grey"          0xa9a9a9 169 169 169
+red               = makeColor "red"                0xff0000 255   0   0
+lightRed          = makeColor "light-red"          0xf03232 240  50  50
+darkRed           = makeColor "dark-red"           0x8b0000 139   0   0
+yellow            = makeColor "yellow"             0xffff00 255 255   0
+lightYellow       = makeColor "light-yellow"       0xffffe0 255 255 224
+darkYellow        = makeColor "dark-yellow"        0xc8c800 200 200   0
+green             = makeColor "green"              0x00ff00   0 255   0
+lightGreen        = makeColor "light-green"        0x90ee90 144 238 144
+darkGreen         = makeColor "dark-green"         0x006400   0 100   0
+springGreen       = makeColor "spring-green"       0x00ff7f   0 255 127
+forestGreen       = makeColor "forest-green"       0x228b22  34 139  34
+seaGreen          = makeColor "sea-green"          0x2e8b57  46 139  87
+blue              = makeColor "blue"               0x0000ff   0   0 255
+lightBlue         = makeColor "light-blue"         0xadd8e6 173 216 230
+darkBlue          = makeColor "dark-blue"          0x00008b   0   0 139
+midnightBlue      = makeColor "midnight-blue"      0x191970  25  25 112
+navy              = makeColor "navy"               0x000080   0   0 128
+mediumBlue        = makeColor "medium-blue"        0x0000cd   0   0 205
+royalblue         = makeColor "royalblue"          0x4169e1  65 105 225
+skyblue           = makeColor "skyblue"            0x87ceeb 135 206 235
+cyan              = makeColor "cyan"               0x00ffff   0 255 255
+lightCyan         = makeColor "light-cyan"         0xe0ffff 224 255 255
+darkCyan          = makeColor "dark-cyan"          0x008b8b   0 139 139
+magenta           = makeColor "magenta"            0xff00ff 255   0 255
+lightMagenta      = makeColor "light-magenta"      0xf055f0 240  85 240
+darkMagenta       = makeColor "dark-magenta"       0x8b008b 139   0 139
+turquoise         = makeColor "turquoise"          0x40e0d0  64 224 208
+lightTurquoise    = makeColor "light-turquoise"    0xafeeee 175 238 238
+darkTurquoise     = makeColor "dark-turquoise"     0x00ced1   0 206 209
+pink              = makeColor "pink"               0xffc0cb 255 192 203
+lightPink         = makeColor "light-pink"         0xffb6c1 255 182 193
+darkPink          = makeColor "dark-pink"          0xff1493 255  20 147
+coral             = makeColor "coral"              0xff7f50 255 127  80
+lightCoral        = makeColor "light-coral"        0xf08080 240 128 128
+orangeRed         = makeColor "orange-red"         0xff4500 255  69   0
+salmon            = makeColor "salmon"             0xfa8072 250 128 114
+lightSalmon       = makeColor "light-salmon"       0xffa07a 255 160 122
+darkSalmon        = makeColor "dark-salmon"        0xe9967a 233 150 122
+aquamarine        = makeColor "aquamarine"         0x7fffd4 127 255 212
+khaki             = makeColor "khaki"              0xf0e68c 240 230 140
+darkKhaki         = makeColor "dark-khaki"         0xbdb76b 189 183 107
+goldenrod         = makeColor "goldenrod"          0xdaa520 218 165  32
+lightGoldenrod    = makeColor "light-goldenrod"    0xeedd82 238 221 130
+darkGoldenrod     = makeColor "dark-goldenrod"     0xb8860b 184 134  11
+gold              = makeColor "gold"               0xffd700 255 215   0
+beige             = makeColor "beige"              0xf5f5dc 245 245 220
+brown             = makeColor "brown"              0xa52a2a 165  42  42
+orange            = makeColor "orange"             0xffa500 255 165   0
+darkOrange        = makeColor "dark-orange"        0xff8c00 255 140   0
+violet            = makeColor "violet"             0xee82ee 238 130 238
+darkViolet        = makeColor "dark-violet"        0x9400d3 148   0 211
+plum              = makeColor "plum"               0xdda0dd 221 160 221
+purple            = makeColor "purple"             0xa020f0 160  32 240
diff --git a/src/Graphics/Gnuplot/Display.hs b/src/Graphics/Gnuplot/Display.hs
--- a/src/Graphics/Gnuplot/Display.hs
+++ b/src/Graphics/Gnuplot/Display.hs
@@ -1,59 +1,7 @@
 {- |
-This class allows gives a uniform interface to plotting
+This class gives a uniform interface to plotting
 @Plot@, @Frame@ and @MultiPlot@.
 -}
-module Graphics.Gnuplot.Display where
-
-import qualified Graphics.Gnuplot.Private.FrameOption as Option
-
-import qualified Data.Map as Map
-import qualified Data.Monoid.State as State
-import Data.Monoid (Monoid, mempty, mappend, )
-
-
--- * User front-end
-
-newtype Script =
-   Script {
-      runScript :: State.T (Int, OptionSet) Body
-   }
-
-data Body =
-   Body {
-      files :: [File],
-      commands :: [String]
-   }
-
-type OptionSet = Map.Map Option.T [String]
-
-data File =
-   File {
-      filename :: FilePath,
-      content :: String
-   }
-
-writeData :: File -> IO ()
-writeData (File fn cont) =
-   writeFile fn cont
-
-
-{-
-Could also be implemented with Control.Monad.Trans.State:
-mappend = liftA2 mappend
--}
-instance Monoid Script where
-   mempty = Script mempty
-   mappend (Script b0) (Script b1) =
-      Script (mappend b0 b1)
-
-{-
-Could also be implemented with Control.Monad.Trans.State:
-mappend = liftA2 mappend
--}
-instance Monoid Body where
-   mempty = Body mempty mempty
-   mappend (Body f0 c0) (Body f1 c1) =
-      Body (mappend f0 f1) (mappend c0 c1)
+module Graphics.Gnuplot.Display (C, ) where
 
-class C gfx where
-   toScript :: gfx -> Script
+import Graphics.Gnuplot.Private.Display
diff --git a/src/Graphics/Gnuplot/Encoding.hs b/src/Graphics/Gnuplot/Encoding.hs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/Gnuplot/Encoding.hs
@@ -0,0 +1,53 @@
+{- |
+Support for special characters
+
+Gnuplot has no universal Unicode escaping mechanism,
+you can only work with encodings.
+However, not all terminals support all encodings,
+not all terminals even support utf-8.
+Some terminals seem to support only one encoding.
+E.g. WX seems to support only UTF-8,
+X11 seems to support only Latin-1.
+Postscript, SVG, PNG seem to support both UTF-8 and Latin-1.
+
+The @gnuplot@ Haskell bindings
+always write using the system-wide default encoding.
+Thus it is better not to set an encoding other than 'locale' explicitly.
+However, if you write the files yourself in a certain encoding
+you should use the @encoding@ option of the according terminal.
+-}
+module Graphics.Gnuplot.Encoding (
+   T,
+   locale, deflt,
+   iso_8859_1, iso_8859_15, iso_8859_2, iso_8859_9,
+   koi8r, koi8u,
+   cp437, cp850, cp852, cp950, cp1250, cp1251, cp1254,
+   sjis, utf8,
+   ) where
+
+import Graphics.Gnuplot.Private.Encoding (T(Cons))
+
+
+locale, deflt,
+   iso_8859_1, iso_8859_15, iso_8859_2, iso_8859_9,
+   koi8r, koi8u,
+   cp437, cp850, cp852, cp950, cp1250, cp1251, cp1254,
+   sjis, utf8 :: T
+
+locale      = Cons "locale"
+deflt       = Cons "default"
+iso_8859_1  = Cons "iso_8859_1"
+iso_8859_15 = Cons "iso_8859_15"
+iso_8859_2  = Cons "iso_8859_2"
+iso_8859_9  = Cons "iso_8859_9"
+koi8r       = Cons "koi8r"
+koi8u       = Cons "koi8u"
+cp437       = Cons "cp437"
+cp850       = Cons "cp850"
+cp852       = Cons "cp852"
+cp950       = Cons "cp950"
+cp1250      = Cons "cp1250"
+cp1251      = Cons "cp1251"
+cp1254      = Cons "cp1254"
+sjis        = Cons "sjis"
+utf8        = Cons "utf8"
diff --git a/src/Graphics/Gnuplot/File.hs b/src/Graphics/Gnuplot/File.hs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/Gnuplot/File.hs
@@ -0,0 +1,17 @@
+module Graphics.Gnuplot.File (T(Cons, name, content), write) where
+
+import qualified Graphics.Gnuplot.Private.File as File
+
+data T =
+   Cons {
+      name :: FilePath,
+      content :: String
+   }
+   deriving (Show, Eq)
+
+
+write :: T -> IO ()
+write (Cons fn cont) = writeFile fn cont
+
+instance File.C T where
+   write = write
diff --git a/src/Graphics/Gnuplot/Frame.hs b/src/Graphics/Gnuplot/Frame.hs
--- a/src/Graphics/Gnuplot/Frame.hs
+++ b/src/Graphics/Gnuplot/Frame.hs
@@ -3,20 +3,18 @@
    cons, simple, empty,
    ) where
 
+import qualified Graphics.Gnuplot.Frame.OptionSet as OptionSet
 import qualified Graphics.Gnuplot.Private.Frame as Frame
 import qualified Graphics.Gnuplot.Private.Plot as Plot
-import qualified Graphics.Gnuplot.Private.FrameOptionSet as Option
 import qualified Graphics.Gnuplot.Private.GraphEmpty as Empty
-
-import qualified Data.Monoid.State as State
+import qualified Graphics.Gnuplot.Private.Graph as Graph
 
 
-cons :: Option.T graph -> Plot.T graph -> Frame.T graph
+cons :: OptionSet.T graph -> Plot.T graph -> Frame.T graph
 cons = Frame.Cons
 
-simple :: Plot.T graph -> Frame.T graph
-simple = cons Option.deflt
+simple :: Graph.C graph => Plot.T graph -> Frame.T graph
+simple = cons OptionSet.deflt
 
 empty :: Frame.T Empty.T
-empty =
-   simple (Plot.Cons (State.pure []))
+empty = simple $ Plot.pure []
diff --git a/src/Graphics/Gnuplot/Frame/Option.hs b/src/Graphics/Gnuplot/Frame/Option.hs
--- a/src/Graphics/Gnuplot/Frame/Option.hs
+++ b/src/Graphics/Gnuplot/Frame/Option.hs
@@ -1,9 +1,42 @@
 module Graphics.Gnuplot.Frame.Option (
-   Option.T,
-   module Graphics.Gnuplot.Private.FrameOption,
+   -- hide Cons constructor
+   T,
+
+   custom,
+
+   title,
+   grid,
+   size,
+   key,
+   border,
+   pm3d,
+   view,
+
+   xRange,
+   yRange,
+   zRange,
+
+   xLabel,
+   yLabel,
+   zLabel,
+
+   xTicks,
+   yTicks,
+   zTicks,
+
+   xLogScale,
+   yLogScale,
+   zLogScale,
+
+   xData,
+   yData,
+   zData,
+
+   xFormat,
+   yFormat,
+   zFormat,
+
+   timeFmt,
    ) where
 
--- exclude Cons constructor
--- this does not work, Cons is exported anyway
-import Graphics.Gnuplot.Private.FrameOption hiding (T)
-import qualified Graphics.Gnuplot.Private.FrameOption as Option
+import Graphics.Gnuplot.Private.FrameOption
diff --git a/src/Graphics/Gnuplot/Frame/OptionSet.hs b/src/Graphics/Gnuplot/Frame/OptionSet.hs
--- a/src/Graphics/Gnuplot/Frame/OptionSet.hs
+++ b/src/Graphics/Gnuplot/Frame/OptionSet.hs
@@ -1,73 +1,185 @@
 module Graphics.Gnuplot.Frame.OptionSet (
    OptionSet.T,
-   OptionSet.deflt,
+   deflt,
 
    OptionSet.add,
    OptionSet.remove,
+   OptionSet.boolean,
+   OptionSet.addBool,
 
    size,
+   sizeRatio,
+   sizeSquare,
    title,
-   xRange,
-   yRange,
-   zRange,
+   key,
+   keyInside,
+   keyOutside,
+   xRange2d,
+   yRange2d,
+   xRange3d,
+   yRange3d,
+   zRange3d,
    xLabel,
    yLabel,
    zLabel,
+   xTicks2d,
+   yTicks2d,
+   xTicks3d,
+   yTicks3d,
+   zTicks3d,
+   xLogScale,
+   yLogScale,
+   zLogScale,
+   grid,
+   gridXTicks,
+   gridYTicks,
+   gridZTicks,
+   xFormat,
+   yFormat,
+   zFormat,
 
    view,
    viewMap,
+
+   boxwidthRelative,
+   boxwidthAbsolute,
    ) where
 
 
 import qualified Graphics.Gnuplot.Graph.ThreeDimensional as Graph3D
+import qualified Graphics.Gnuplot.Graph.TwoDimensional as Graph2D
 
 import qualified Graphics.Gnuplot.Private.FrameOptionSet as OptionSet
 import qualified Graphics.Gnuplot.Private.FrameOption as Option
 import qualified Graphics.Gnuplot.Private.Graph as Graph
 
+import qualified Graphics.Gnuplot.Value.Atom as Atom
+import qualified Graphics.Gnuplot.Value.Tuple as Tuple
+
 import Graphics.Gnuplot.Private.FrameOptionSet (T, )
 
-import Graphics.Gnuplot.Utility
-   (quote, )
+import Graphics.Gnuplot.Utility (quote, commaConcat, )
 
+import qualified Data.List as List
 
+
+deflt :: Graph.C graph => T graph
+deflt = Graph.defltOptions
+
+
 size :: Graph.C graph => Double -> Double -> T graph -> T graph
 size x y =
-   OptionSet.add Option.size [show x ++ ", " ++ show y]
+   OptionSet.add Option.sizeScale [show x ++ ", " ++ show y]
 
+sizeRatio :: Graph.C graph => Double -> T graph -> T graph
+sizeRatio r =
+   OptionSet.add Option.sizeRatio ["ratio", show r]
+
+sizeSquare :: Graph.C graph => T graph -> T graph
+sizeSquare =
+   OptionSet.add Option.sizeRatio ["square"]
+
 title :: Graph.C graph => String -> T graph -> T graph
 title text =
    OptionSet.add Option.title [quote text]
 
+key :: Graph.C graph => Bool -> T graph -> T graph
+key = OptionSet.boolean Option.keyShow
 
+keyInside :: Graph.C graph => T graph -> T graph
+keyInside = OptionSet.add Option.keyPosition ["inside"]
+
+keyOutside :: Graph.C graph => T graph -> T graph
+keyOutside = OptionSet.add Option.keyPosition ["outside"]
+
+{-
 xRange :: Graph.C graph => (Double, Double) -> T graph -> T graph
 xRange = range Option.xRange
 
 yRange :: Graph.C graph => (Double, Double) -> T graph -> T graph
 yRange = range Option.yRange
 
-zRange :: (Double, Double) -> T Graph3D.T -> T Graph3D.T
+zRange :: (Double, Double) -> T (Graph3D.T x y z) -> T (Graph3D.T x y z)
 zRange = range Option.zRange
+-}
 
-range :: Graph.C graph => Option.T -> (Double, Double) -> T graph -> T graph
+xRange2d ::
+   (Atom.C x, Atom.C y, Tuple.C x) =>
+   (x, x) -> T (Graph2D.T x y) -> T (Graph2D.T x y)
+xRange2d = range Option.xRangeBounds
+
+yRange2d ::
+   (Atom.C x, Atom.C y, Tuple.C y) =>
+   (y, y) -> T (Graph2D.T x y) -> T (Graph2D.T x y)
+yRange2d = range Option.yRangeBounds
+
+
+xRange3d ::
+   (Atom.C x, Atom.C y, Atom.C z, Tuple.C x) =>
+   (x, x) -> T (Graph3D.T x y z) -> T (Graph3D.T x y z)
+xRange3d = range Option.xRangeBounds
+
+yRange3d ::
+   (Atom.C x, Atom.C y, Atom.C z, Tuple.C y) =>
+   (y, y) -> T (Graph3D.T x y z) -> T (Graph3D.T x y z)
+yRange3d = range Option.yRangeBounds
+
+zRange3d ::
+   (Atom.C x, Atom.C y, Atom.C z, Tuple.C z) =>
+   (z, z) -> T (Graph3D.T x y z) -> T (Graph3D.T x y z)
+zRange3d = range Option.zRangeBounds
+
+
+range ::
+   (Atom.C a, Tuple.C a, Graph.C graph) =>
+   Option.T -> (a, a) -> T graph -> T graph
 range opt (x,y) =
-   OptionSet.add opt ["[" ++ show x ++ ":" ++ show y ++ "]"]
+   OptionSet.add opt
+      [showString "[" . atomText x .
+       showString ":" . atomText y $
+       "]"]
 
+atomText ::
+   (Atom.C a, Tuple.C a) =>
+   a -> ShowS
+atomText x =
+   case Tuple.text x of
+      [s] -> s
+      _ -> error "OptionSet.fromSingleton: types of Atom class must generate single representation texts"
 
+
 xLabel :: Graph.C graph => String -> T graph -> T graph
-xLabel = label Option.xLabel
+xLabel = label Option.xLabelText
 
 yLabel :: Graph.C graph => String -> T graph -> T graph
-yLabel = label Option.yLabel
+yLabel = label Option.yLabelText
 
-zLabel :: String -> T Graph3D.T -> T Graph3D.T
-zLabel = label Option.zLabel
+zLabel ::
+   (Atom.C x, Atom.C y, Atom.C z) =>
+   String -> T (Graph3D.T x y z) -> T (Graph3D.T x y z)
+zLabel = label Option.zLabelText
 
 label :: Graph.C graph => Option.T -> String -> T graph -> T graph
 label opt x =
    OptionSet.add opt [quote x]
 
 
+xFormat :: Graph.C graph => String -> T graph -> T graph
+xFormat = format Option.xFormat
+
+yFormat :: Graph.C graph => String -> T graph -> T graph
+yFormat = format Option.yFormat
+
+zFormat ::
+   (Atom.C x, Atom.C y, Atom.C z) =>
+   String -> T (Graph3D.T x y z) -> T (Graph3D.T x y z)
+zFormat = format Option.zFormat
+
+format :: Graph.C graph => Option.T -> String -> T graph -> T graph
+format opt x =
+   OptionSet.add opt [quote x]
+
+
 {- |
 Set parameters of viewing a surface graph.
 See <info:gnuplot/view>
@@ -77,34 +189,105 @@
    Double {- ^ rotateZ -} ->
    Double {- ^ scale -} ->
    Double {- ^ scaleZ -} ->
-   T Graph3D.T -> T Graph3D.T
+   T (Graph3D.T x y z) -> T (Graph3D.T x y z)
 view rotateX rotateZ scale scaleZ =
-   OptionSet.add Option.view [show rotateX, show rotateZ, show scale, show scaleZ]
+   OptionSet.add Option.view
+      [commaConcat [show rotateX, show rotateZ, show scale, show scaleZ]]
 
 {- |
 Show flat pixel map.
 -}
-viewMap :: T Graph3D.T -> T Graph3D.T
+viewMap :: T (Graph3D.T x y z) -> T (Graph3D.T x y z)
 viewMap =
    OptionSet.add Option.view ["map"]
 
-{-
-xTicks :: Graph.C graph => Double -> Double -> T graph -> T graph
-xTicks = ticks Option.xTicks
 
-yTicks :: Graph.C graph => Double -> Double -> T graph -> T graph
-yTicks = ticks Option.yTicks
+xTicks2d ::
+   (Atom.C x, Atom.C y, Tuple.C x) =>
+   [(String, x)] -> T (Graph2D.T x y) -> T (Graph2D.T x y)
+xTicks2d = ticks Option.xTickLabels
 
-zTicks :: Double -> Double -> T Graph3D.T -> T Graph3D.T
-zTicks = ticks Option.zTicks
+yTicks2d ::
+   (Atom.C x, Atom.C y, Tuple.C y) =>
+   [(String, y)] -> T (Graph2D.T x y) -> T (Graph2D.T x y)
+yTicks2d = ticks Option.yTickLabels
 
-ticks :: Graph.C graph => Option.T -> Double -> Double -> T graph -> T graph
-ticks opt x y =
-   OptionSet.add opt [show x ++ ":" ++ show y]
--}
 
+xTicks3d ::
+   (Atom.C x, Atom.C y, Atom.C z, Tuple.C x) =>
+   [(String, x)] -> T (Graph3D.T x y z) -> T (Graph3D.T x y z)
+xTicks3d = ticks Option.xTickLabels
+
+yTicks3d ::
+   (Atom.C x, Atom.C y, Atom.C z, Tuple.C y) =>
+   [(String, y)] -> T (Graph3D.T x y z) -> T (Graph3D.T x y z)
+yTicks3d = ticks Option.yTickLabels
+
+zTicks3d ::
+   (Atom.C x, Atom.C y, Atom.C z, Tuple.C z) =>
+   [(String, z)] -> T (Graph3D.T x y z) -> T (Graph3D.T x y z)
+zTicks3d = ticks Option.zTickLabels
+
+
+ticks ::
+   (Atom.C a, Tuple.C a, Graph.C graph) =>
+   Option.T -> [(String, a)] -> T graph -> T graph
+ticks opt labels =
+   OptionSet.add opt
+      [('(' :) $ foldr ($) ")" $
+       List.intersperse (showString ", ") $
+       map
+          (\(lab,pos) ->
+             showString (quote lab) .
+             showString " " .
+             atomText pos)
+          labels]
+
+
+xLogScale :: Graph.C graph => T graph -> T graph
+xLogScale = OptionSet.add Option.xLogScale []
+
+yLogScale :: Graph.C graph => T graph -> T graph
+yLogScale = OptionSet.add Option.yLogScale []
+
+zLogScale ::
+   (Atom.C x, Atom.C y, Atom.C z) =>
+   T (Graph3D.T x y z) -> T (Graph3D.T x y z)
+zLogScale = OptionSet.add Option.zLogScale []
+
+
+grid :: Graph.C graph => Bool -> T graph -> T graph
+grid b =
+   OptionSet.addBool Option.gridXTicks b .
+   OptionSet.addBool Option.gridYTicks b .
+   OptionSet.addBool Option.gridZTicks b
+
+gridXTicks :: Graph.C graph => Bool -> T graph -> T graph
+gridXTicks = OptionSet.addBool Option.gridXTicks
+
+gridYTicks :: Graph.C graph => Bool -> T graph -> T graph
+gridYTicks = OptionSet.addBool Option.gridYTicks
+
+gridZTicks ::
+   (Atom.C x, Atom.C y, Atom.C z) =>
+   Bool -> T (Graph3D.T x y z) -> T (Graph3D.T x y z)
+gridZTicks = OptionSet.addBool Option.gridZTicks
+
+
+boxwidthRelative ::
+   (Graph.C graph) =>
+   Double -> T graph -> T graph
+boxwidthRelative width =
+   OptionSet.add Option.boxwidth [show width, "relative"]
+
+boxwidthAbsolute ::
+   (Graph.C graph) =>
+   Double -> T graph -> T graph
+boxwidthAbsolute width =
+   OptionSet.add Option.boxwidth [show width, "absolute"]
+
 {-
-cornerToColor :: CornersToColor -> T Graph3D.T -> T Graph3D.T
+cornerToColor :: CornersToColor -> T (Graph3D.T x y z) -> T (Graph3D.T x y z)
 
-type3d :: Plot3dType -> T Graph3D.T -> T Graph3D.T
+type3d :: Plot3dType -> T (Graph3D.T x y z) -> T (Graph3D.T x y z)
 -}
diff --git a/src/Graphics/Gnuplot/Frame/OptionSet/Histogram.hs b/src/Graphics/Gnuplot/Frame/OptionSet/Histogram.hs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/Gnuplot/Frame/OptionSet/Histogram.hs
@@ -0,0 +1,61 @@
+module Graphics.Gnuplot.Frame.OptionSet.Histogram (
+   clustered,
+   clusteredGap,
+   errorbars,
+   errorbarsGap,
+   errorbarsGapLineWidth,
+   rowstacked,
+   columnstacked,
+   ) where
+
+import qualified Graphics.Gnuplot.Graph.TwoDimensional as Graph2D
+
+import qualified Graphics.Gnuplot.Private.FrameOptionSet as OptionSet
+import qualified Graphics.Gnuplot.Private.FrameOption as Option
+
+import qualified Graphics.Gnuplot.Value.Atom as Atom
+
+import Graphics.Gnuplot.Private.FrameOptionSet (T, )
+
+
+clustered ::
+   (Atom.C x, Atom.C y) =>
+   T (Graph2D.T x y) -> T (Graph2D.T x y)
+clustered =
+   OptionSet.add Option.styleHistogram ["clustered"]
+
+clusteredGap ::
+   (Atom.C x, Atom.C y) =>
+   Double -> T (Graph2D.T x y) -> T (Graph2D.T x y)
+clusteredGap gapSize =
+   OptionSet.add Option.styleHistogram ["clustered", "gap", show gapSize]
+
+errorbars ::
+   (Atom.C x, Atom.C y) =>
+   T (Graph2D.T x y) -> T (Graph2D.T x y)
+errorbars =
+   OptionSet.add Option.styleHistogram ["errorbars"]
+
+errorbarsGap ::
+   (Atom.C x, Atom.C y) =>
+   Double -> T (Graph2D.T x y) -> T (Graph2D.T x y)
+errorbarsGap gapSize =
+   OptionSet.add Option.styleHistogram ["errorbars", "gap", show gapSize]
+
+errorbarsGapLineWidth ::
+   (Atom.C x, Atom.C y) =>
+   Double -> Double -> T (Graph2D.T x y) -> T (Graph2D.T x y)
+errorbarsGapLineWidth gapSize width =
+   OptionSet.add Option.styleHistogram ["errorbars", "gap", show gapSize, show width]
+
+rowstacked ::
+   (Atom.C x, Atom.C y) =>
+   T (Graph2D.T x y) -> T (Graph2D.T x y)
+rowstacked =
+   OptionSet.add Option.styleHistogram ["rowstacked"]
+
+columnstacked ::
+   (Atom.C x, Atom.C y) =>
+   T (Graph2D.T x y) -> T (Graph2D.T x y)
+columnstacked =
+   OptionSet.add Option.styleHistogram ["columnstacked"]
diff --git a/src/Graphics/Gnuplot/Frame/OptionSet/Style.hs b/src/Graphics/Gnuplot/Frame/OptionSet/Style.hs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/Gnuplot/Frame/OptionSet/Style.hs
@@ -0,0 +1,26 @@
+module Graphics.Gnuplot.Frame.OptionSet.Style (
+   fillSolid,
+   fillBorder,
+   fillBorderLineType,
+   ) where
+
+import qualified Graphics.Gnuplot.Private.FrameOptionSet as OptionSet
+import qualified Graphics.Gnuplot.Private.FrameOption as Option
+import qualified Graphics.Gnuplot.Private.Graph as Graph
+
+import Graphics.Gnuplot.Private.FrameOptionSet (T, )
+
+-- import Graphics.Gnuplot.Utility (quote, )
+
+
+fillSolid :: Graph.C graph => T graph -> T graph
+fillSolid =
+   OptionSet.addBool Option.styleFillSolid True
+
+fillBorder :: Graph.C graph => Bool -> T graph -> T graph
+fillBorder =
+   OptionSet.addBool Option.styleFillBorder
+
+fillBorderLineType :: Graph.C graph => Int -> T graph -> T graph
+fillBorderLineType n =
+   OptionSet.add Option.styleFillBorder ["border", show n]
diff --git a/src/Graphics/Gnuplot/Graph.hs b/src/Graphics/Gnuplot/Graph.hs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/Gnuplot/Graph.hs
@@ -0,0 +1,3 @@
+module Graphics.Gnuplot.Graph (Graph.C) where
+
+import qualified Graphics.Gnuplot.Private.Graph as Graph
diff --git a/src/Graphics/Gnuplot/Graph/ThreeDimensional.hs b/src/Graphics/Gnuplot/Graph/ThreeDimensional.hs
--- a/src/Graphics/Gnuplot/Graph/ThreeDimensional.hs
+++ b/src/Graphics/Gnuplot/Graph/ThreeDimensional.hs
@@ -2,39 +2,17 @@
    T,
    Type,
 
-   defaultType,
-   deflt,
+--   deflt,
 
-   typ,
    lineSpec,
 
-   lines,
-   points,
-   linesPoints,
    impulses,
-   dots,
-   steps,
-   fSteps,
-   hiSteps,
-   errorBars,
-   xErrorBars,
-   yErrorBars,
-   xyErrorBars,
-   errorLines,
-   xErrorLines,
-   yErrorLines,
-   xyErrorLines,
-   boxes,
-   filledCurves,
-   boxErrorBars,
-   boxXYErrorBars,
-   financeBars,
-   candleSticks,
    vectors,
-   pm3d,
+   Graph3DType.pm3d,
+
+   Graph3DType.lines,
+   points,
    ) where
 
 import Graphics.Gnuplot.Private.Graph3D
-import Graphics.Gnuplot.Private.GraphType hiding (T, )
-
-import Prelude hiding (lines, )
+import Graphics.Gnuplot.Private.Graph3DType as Graph3DType hiding (T, )
diff --git a/src/Graphics/Gnuplot/Graph/TwoDimensional.hs b/src/Graphics/Gnuplot/Graph/TwoDimensional.hs
--- a/src/Graphics/Gnuplot/Graph/TwoDimensional.hs
+++ b/src/Graphics/Gnuplot/Graph/TwoDimensional.hs
@@ -2,13 +2,32 @@
    T,
    Type,
 
-   defaultType,
-   deflt,
+--   deflt,
 
-   typ,
    lineSpec,
 
-   lines,
+   listLines,
+   listPoints,
+   listLinesPoints,
+   listImpulses,
+   listDots,
+   histograms,
+
+   xErrorBarsRelative,
+   yErrorBarsRelative,
+   xyErrorBarsRelative,
+   xErrorBarsAbsolute,
+   yErrorBarsAbsolute,
+   xyErrorBarsAbsolute,
+
+   xErrorLinesRelative,
+   yErrorLinesRelative,
+   xyErrorLinesRelative,
+   xErrorLinesAbsolute,
+   yErrorLinesAbsolute,
+   xyErrorLinesAbsolute,
+
+   Graph2DType.lines,
    points,
    linesPoints,
    impulses,
@@ -17,24 +36,24 @@
    fSteps,
    hiSteps,
    errorBars,
-   xErrorBars,
-   yErrorBars,
-   xyErrorBars,
    errorLines,
-   xErrorLines,
-   yErrorLines,
-   xyErrorLines,
    boxes,
    filledCurves,
+{-
    boxErrorBars,
    boxXYErrorBars,
+-}
    financeBars,
    candleSticks,
    vectors,
-   -- pm3d,
+   image,
+
+   filledStripe,
+   filledStripeAbove,
+   filledStripeBelow,
+
+   labels,
    ) where
 
 import Graphics.Gnuplot.Private.Graph2D
-import Graphics.Gnuplot.Private.GraphType hiding (T, )
-
-import Prelude hiding (lines, )
+import Graphics.Gnuplot.Private.Graph2DType as Graph2DType hiding (T, )
diff --git a/src/Graphics/Gnuplot/LineSpecification.hs b/src/Graphics/Gnuplot/LineSpecification.hs
--- a/src/Graphics/Gnuplot/LineSpecification.hs
+++ b/src/Graphics/Gnuplot/LineSpecification.hs
@@ -6,6 +6,7 @@
    lineStyle,
    lineType,
    lineWidth,
+   lineColor,
    pointType,
    pointSize,
    title,
diff --git a/src/Graphics/Gnuplot/MultiPlot.hs b/src/Graphics/Gnuplot/MultiPlot.hs
--- a/src/Graphics/Gnuplot/MultiPlot.hs
+++ b/src/Graphics/Gnuplot/MultiPlot.hs
@@ -5,24 +5,27 @@
    partFromPlot,
    simpleFromFrameArray,
    simpleFromPartArray,
+   title,
    ) where
 
 import qualified Graphics.Gnuplot.Private.Frame as Frame
 import qualified Graphics.Gnuplot.Private.Plot as Plot
 
-import qualified Graphics.Gnuplot.Display as Display
+import qualified Graphics.Gnuplot.Private.Display as Display
 import qualified Graphics.Gnuplot.Private.Graph as Graph
 
-import qualified Data.Monoid.State as State
 import Data.Monoid (mconcat, )
+import Data.Foldable (foldMap, )
 
 import Data.Array (Array, elems, bounds, )
 import Data.Ix (Ix, rangeSize, )
 
+import Graphics.Gnuplot.Utility (quote, )
 
+
 data T =
    Cons {
-      _option :: (),  -- to be extended by multiplot options
+      title_ :: Maybe String,
       numRows, numColumns :: Int,
       parts :: [Part]
    }
@@ -60,20 +63,26 @@
    Array (i,j) Part -> T
 simpleFromPartArray arr =
    let ((r0,c0), (r1,c1)) = bounds arr
-   in  Cons ()
+   in  Cons Nothing
           (rangeSize (r0,r1))
           (rangeSize (c0,c1))
           (elems arr)
 
 
+title :: String -> T -> T
+title str mp =
+   mp {title_ = Just str}
+
+
 instance Display.C T where
    toScript mp =
       mconcat $
-      (Display.Script $ State.pure $
-         Display.Body [] ["set multiplot layout " ++
-                      show (numRows mp) ++ ", " ++
-                      show (numColumns mp)]) :
+      (Display.pure $
+         Display.Body []
+            ["set multiplot layout " ++
+             show (numRows mp) ++ ", " ++ show (numColumns mp) ++
+             foldMap ((" title " ++) . quote) (title_ mp)]) :
       (map scriptFromPart $ parts mp) ++
-      (Display.Script $ State.pure $
+      (Display.pure $
          Display.Body [] ["unset multiplot"]) :
       []
diff --git a/src/Graphics/Gnuplot/Plot.hs b/src/Graphics/Gnuplot/Plot.hs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/Gnuplot/Plot.hs
@@ -0,0 +1,3 @@
+module Graphics.Gnuplot.Plot (T) where
+
+import Graphics.Gnuplot.Private.Plot (T)
diff --git a/src/Graphics/Gnuplot/Plot/ThreeDimensional.hs b/src/Graphics/Gnuplot/Plot/ThreeDimensional.hs
--- a/src/Graphics/Gnuplot/Plot/ThreeDimensional.hs
+++ b/src/Graphics/Gnuplot/Plot/ThreeDimensional.hs
@@ -1,35 +1,67 @@
 module Graphics.Gnuplot.Plot.ThreeDimensional (
+   T,
+   cloud,
+--   function,
+   mesh,
+   surface,
+
    linearScale,
-   module Graphics.Gnuplot.Plot.ThreeDimensional,
+   functionToGraph,
    ) where
 
+import qualified Graphics.Gnuplot.Private.Graph3DType as Type
 import qualified Graphics.Gnuplot.Private.Graph3D as Graph
 import qualified Graphics.Gnuplot.Private.Plot    as Plot
+-- import qualified Graphics.Gnuplot.Value.ColumnSet as Col
+import qualified Graphics.Gnuplot.Value.Tuple as Tuple
+import qualified Graphics.Gnuplot.Value.Atom  as Atom
 
 import Graphics.Gnuplot.Utility
-   (showTriplet, linearScale, )
+   (functionToGraph, linearScale, assembleCells, )
 
 import Data.List.HT (outerProduct, )
 
 
 {- |
-Plots can be assembled using 'mappend' or 'mconcat'.
+Plots can be assembled using 'mappend' or 'mconcat'
+or several functions from "Data.Foldable".
 -}
-type T = Plot.T Graph.T
+type T x y z = Plot.T (Graph.T x y z)
 
 
 -- * computed plots
 
-mesh ::
-   (Show a, Show b, Show c) =>
-   [[(a,b,c)]] -> T
-mesh dat =
+cloud ::
+   (Atom.C x, Atom.C y, Atom.C z,
+    Tuple.C a) =>
+   Type.T x y z a -> [a] -> T x y z
+cloud typ ps =
    Plot.withUniqueFile
-      (unlines (map (unlines . map showTriplet) dat))
-      [Graph.deflt (Graph.Dim3 1 2 3)]
+      (assembleCells (map Tuple.text ps))
+      [Graph.deflt typ
+         [1 .. case Type.tupleSize typ of Tuple.ColumnCount n -> n]]
 
+{-
 function ::
-   (Show a, Show b, Show c) =>
-   [b] -> [c] -> (b -> c -> a) -> T
+   (Atom.C x, Atom.C y, Atom.C z) =>
+   Type.T (x,y,z) -> [x] -> [y] -> (x -> y -> z) -> T
 function xArgs yArgs f =
+   cloud (liftM2 (\x y -> (x, y, f x y)) xArgs yArgs)
+-}
+
+
+mesh ::
+   (Atom.C x, Atom.C y, Atom.C z,
+    Tuple.C x, Tuple.C y, Tuple.C z) =>
+   [[(x,y,z)]] -> T x y z
+mesh pss =
+   Plot.withUniqueFile
+      (assembleCells (concatMap (\ps -> map Tuple.text ps ++ [[]]) pss))
+      [Graph.pm3d]
+
+surface ::
+   (Atom.C x, Atom.C y, Atom.C z,
+    Tuple.C x, Tuple.C y, Tuple.C z) =>
+   [x] -> [y] -> (x -> y -> z) -> T x y z
+surface xArgs yArgs f =
    mesh (outerProduct (\x y -> (x, y, f x y)) xArgs yArgs)
diff --git a/src/Graphics/Gnuplot/Plot/TwoDimensional.hs b/src/Graphics/Gnuplot/Plot/TwoDimensional.hs
--- a/src/Graphics/Gnuplot/Plot/TwoDimensional.hs
+++ b/src/Graphics/Gnuplot/Plot/TwoDimensional.hs
@@ -1,73 +1,129 @@
 -- shall this also export Graph.Type, set plotType and so on?
 module Graphics.Gnuplot.Plot.TwoDimensional (
+   T,
+
+   list,
+   function,
+   functions,
+   functionsWithLineSpec,
+   parameterFunction,
+
+   listFromFile,
+   pathFromFile,
+
    linearScale,
-   module Graphics.Gnuplot.Plot.TwoDimensional,
+   functionToGraph,
    ) where
 
+import qualified Graphics.Gnuplot.Private.Graph2DType as Type
 import qualified Graphics.Gnuplot.Private.Graph2D as Graph
 import qualified Graphics.Gnuplot.Private.Plot    as Plot
+import qualified Graphics.Gnuplot.Private.LineSpecification as LineSpec
+import qualified Graphics.Gnuplot.Value.ColumnSet as Col
+import qualified Graphics.Gnuplot.Value.Tuple as Tuple
+import qualified Graphics.Gnuplot.Value.Atom  as Atom
 
 import Graphics.Gnuplot.Utility
-   (functionToGraph, commaConcat, linearScale, )
+   (functionToGraph, linearScale, assembleCells, )
 
 import qualified Data.List.Match as Match
+import qualified Data.List.HT as ListHT
 
 
 {- |
 Plots can be assembled using 'mappend' or 'mconcat'.
+You can alter attributes of embedded graphs using 'fmap'.
 -}
-type T = Plot.T Graph.T
+type T x y = Plot.T (Graph.T x y)
 
 
 -- * computed plots
 
 {- |
-> list (take 30 (let fibs = 0 : 1 : zipWith (+) fibs (tail fibs) in fibs))
+> list Type.listLines (take 30 (let fibs = 0 : 1 : zipWith (+) fibs (tail fibs) in fibs))
+> list Type.lines (take 30 (let fibs0 = 0 : fibs1; fibs1 = 1 : zipWith (+) fibs0 fibs1 in zip fibs0 fibs1))
 -}
-list :: Show a => [a] -> T
-list dat =
+list ::
+   (Atom.C x, Atom.C y, Tuple.C a) =>
+   Type.T x y a -> [a] -> T x y
+list typ ps =
    Plot.withUniqueFile
-      (unlines (map show dat))
-      ([Graph.deflt (Graph.Dim1 1)])
+      (assembleCells (map Tuple.text ps))
+      [Graph.deflt typ
+         [1 .. case Type.tupleSize typ of Tuple.ColumnCount n -> n]]
 
 {- |
-> function (linearScale 1000 (-10,10)) sin
+> function Type.line (linearScale 1000 (-10,10)) sin
 -}
-function :: Show a => [a] -> (a -> a) -> T
-function args f =
-   path (functionToGraph args f)
+function ::
+   (Atom.C x, Atom.C y,
+    Tuple.C a, Tuple.C b) =>
+   Type.T x y (a,b) -> [a] -> (a -> b) -> T x y
+function typ args f =
+   list typ (functionToGraph args f)
 
 {- |
-> functions (linearScale 1000 (-10,10)) [sin, cos]
+> functions Type.line (linearScale 1000 (-10,10)) [sin, cos]
 -}
-functions :: Show a => [a] -> [a -> a] -> T
-functions args fs =
-   let dat = map (\x -> (x, map ($ x) fs)) args
+functions ::
+   (Atom.C x, Atom.C y,
+    Tuple.C a, Tuple.C b) =>
+   Type.T x y (a,b) -> [a] -> [a -> b] -> T x y
+functions typ args =
+   functionsWithLineSpec typ args . map ((,) LineSpec.deflt)
+
+{- |
+> functionsWithLineSpec Type.line (linearScale 1000 (-10,10)) $
+>    map (mapFst (flip LineSpec.title LineSpec.deflt)) [("sin", sin), ("cos", cos)]
+-}
+functionsWithLineSpec ::
+   (Atom.C x, Atom.C y,
+    Tuple.C a, Tuple.C b) =>
+   Type.T x y (a,b) -> [a] -> [(LineSpec.T, a -> b)] -> T x y
+functionsWithLineSpec typ args fs =
+   let dat = map (\x -> (x, map (($ x) . snd) fs)) args
+       mapType :: (a -> b) -> Type.T x y a -> Type.T x y b
+       mapType _ (Type.Cons str) = Type.Cons str
+       Tuple.ColumnCount na = Type.tupleSize $ mapType fst typ
+       Tuple.ColumnCount nb = Type.tupleSize $ mapType snd typ
    in  Plot.withUniqueFile
-          (unlines (map (commaConcat . map show . uncurry (:)) dat))
+          (assembleCells
+              (map (\(a,b) -> Tuple.text a ++ concatMap Tuple.text b) dat))
           (Match.take fs $
-           map (Graph.deflt . Graph.Dim2 1) [2..])
+           zipWith
+              (\(lineSpec,_f) ns ->
+                 Graph.lineSpec lineSpec $ Graph.deflt typ ([1..na] ++ ns))
+              fs $
+           ListHT.sliceVertical nb [(na+1)..])
 
-path :: Show a => [(a,a)] -> T
-path dat =
-   Plot.withUniqueFile
-      (unlines (map (\(x,y) -> show x ++ ", " ++ show y) dat))
-      ([Graph.deflt (Graph.Dim2 1 2)])
 
 {- |
-> parameterFunction (linearScale 1000 (0,2*pi)) (\t -> (sin (2*t), cos t))
+> parameterFunction Type.line (linearScale 1000 (0,2*pi)) (\t -> (sin (2*t), cos t))
 -}
-parameterFunction :: Show a => [a] -> (a -> (a,a)) -> T
-parameterFunction args f = path (map f args)
+parameterFunction ::
+   (Atom.C x, Atom.C y,
+    Tuple.C a) =>
+   Type.T x y a -> [t] -> (t -> a) -> T x y
+parameterFunction typ args f = list typ (map f args)
 
 
 
 -- * plot stored data
 
-listFromFile :: FilePath -> Int -> T
-listFromFile filename column =
-   Plot.fromGraphs filename [Graph.deflt (Graph.Dim1 column)]
+fromFile ::
+   (Atom.C x, Atom.C y) =>
+   Type.T x y a -> FilePath -> Col.T a -> T x y
+fromFile typ filename (Col.Cons cs) =
+   Plot.fromGraphs filename [Graph.deflt typ cs]
 
-pathFromFile :: FilePath -> Int -> Int -> T
-pathFromFile filename columnX columnY =
-   Plot.fromGraphs filename [Graph.deflt (Graph.Dim2 columnX columnY)]
+listFromFile ::
+   (Atom.C i, Atom.C y) =>
+   Type.T i y y -> FilePath -> Int -> T i y
+listFromFile typ filename column =
+   fromFile typ filename (Col.atom column)
+
+pathFromFile ::
+   (Atom.C x, Atom.C y) =>
+   Type.T x y (x,y) -> FilePath -> Int -> Int -> T x y
+pathFromFile typ filename columnX columnY =
+   fromFile typ filename (Col.pair (Col.atom columnX) (Col.atom columnY))
diff --git a/src/Graphics/Gnuplot/Private/ColorSpecification.hs b/src/Graphics/Gnuplot/Private/ColorSpecification.hs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/Gnuplot/Private/ColorSpecification.hs
@@ -0,0 +1,22 @@
+module Graphics.Gnuplot.Private.ColorSpecification where
+
+import Graphics.Gnuplot.Utility (quote, )
+import Data.List.HT (padLeft, )
+import Data.Word (Word8, )
+import Numeric (showHex, )
+
+
+data T =
+     Name String
+   | RGB8 {red, green, blue :: Word8}
+   | PaletteFrac Double
+
+
+toString :: T -> String
+toString c =
+   case c of
+      Name name -> "rgbcolor " ++ quote name
+      RGB8 r g b ->
+         "rgbcolor #" ++
+         concatMap (padLeft '0' 2 . flip showHex "") [r,g,b]
+      PaletteFrac frac -> "palette frac " ++ show frac
diff --git a/src/Graphics/Gnuplot/Private/Command.hs b/src/Graphics/Gnuplot/Private/Command.hs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/Gnuplot/Private/Command.hs
@@ -0,0 +1,28 @@
+module Graphics.Gnuplot.Private.Command where
+
+import qualified Graphics.Gnuplot.Private.File as File
+import qualified Graphics.Gnuplot.Execute as Exec
+import System.Exit (ExitCode(ExitSuccess), )
+import Control.Concurrent (forkIO, )
+
+import System.IO.Temp (withSystemTempDirectory, )
+
+import Control.DeepSeq (deepseq, )
+import Control.Functor.HT (void, )
+
+
+run ::
+   (File.C file) =>
+   (FilePath -> ([String], [file])) -> IO ExitCode
+run render =
+   withSystemTempDirectory "gnuplot" $ \dir ->
+   case render dir of
+      (cmds, files) -> deepseq cmds $ do
+         mapM_ File.write files
+         Exec.simple (cmds ++ ["pause mouse close"]) []
+
+asyncIfInteractive :: Bool -> IO ExitCode -> IO ExitCode
+asyncIfInteractive interactive act =
+   if interactive
+     then fmap (const ExitSuccess) $ forkIO $ void act
+     else act
diff --git a/src/Graphics/Gnuplot/Private/Display.hs b/src/Graphics/Gnuplot/Private/Display.hs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/Gnuplot/Private/Display.hs
@@ -0,0 +1,56 @@
+module Graphics.Gnuplot.Private.Display where
+
+import qualified Graphics.Gnuplot.Private.FrameOption as Option
+import qualified Graphics.Gnuplot.File as File
+
+import qualified Data.Map as Map
+import qualified Control.Monad.Trans.Reader as MR
+import qualified Control.Monad.Trans.State as MS
+import Control.Monad (liftM2, return, )
+import Data.Monoid (Monoid, mempty, mappend, )
+import Data.Semigroup (Semigroup, (<>), )
+
+import Prelude (FilePath, String, Int, ($), (.), )
+
+
+newtype Script =
+   Script {
+      runScript :: MS.StateT (Int, OptionSet) (MR.Reader FilePath) Body
+   }
+
+pure :: Body -> Script
+pure = Script . return
+
+data Body =
+   Body {
+      files :: [File.T],
+      commands :: [String]
+   }
+
+type OptionSet = Map.Map Option.T [String]
+
+
+instance Semigroup Script where
+   Script b0 <> Script b1 = Script (liftM2 (<>) b0 b1)
+
+{-
+Could also be implemented with Control.Monad.Trans.State:
+mappend = liftA2 mappend
+-}
+instance Monoid Script where
+   mempty = Script $ return mempty
+   mappend = (<>)
+
+instance Semigroup Body where
+   Body f0 c0 <> Body f1 c1 = Body (f0 <> f1) (c0 <> c1)
+
+{-
+Could also be implemented with Control.Monad.Trans.State:
+mappend = liftA2 mappend
+-}
+instance Monoid Body where
+   mempty = Body mempty mempty
+   mappend = (<>)
+
+class C gfx where
+   toScript :: gfx -> Script
diff --git a/src/Graphics/Gnuplot/Private/Encoding.hs b/src/Graphics/Gnuplot/Private/Encoding.hs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/Gnuplot/Private/Encoding.hs
@@ -0,0 +1,11 @@
+module Graphics.Gnuplot.Private.Encoding where
+
+import Graphics.Gnuplot.Utility (listFromMaybeWith)
+
+newtype T = Cons String
+
+format :: T -> String
+format (Cons enc) = "set encoding " ++ enc
+
+formatMaybe :: Maybe T -> [String]
+formatMaybe = listFromMaybeWith format
diff --git a/src/Graphics/Gnuplot/Private/File.hs b/src/Graphics/Gnuplot/Private/File.hs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/Gnuplot/Private/File.hs
@@ -0,0 +1,4 @@
+module Graphics.Gnuplot.Private.File where
+
+class C file where
+   write :: file -> IO ()
diff --git a/src/Graphics/Gnuplot/Private/Frame.hs b/src/Graphics/Gnuplot/Private/Frame.hs
--- a/src/Graphics/Gnuplot/Private/Frame.hs
+++ b/src/Graphics/Gnuplot/Private/Frame.hs
@@ -3,11 +3,10 @@
 import qualified Graphics.Gnuplot.Private.Plot as Plot
 import qualified Graphics.Gnuplot.Private.FrameOptionSet as OptionSet
 
-import qualified Graphics.Gnuplot.Display as Display
+import qualified Graphics.Gnuplot.Private.Display as Display
 import qualified Graphics.Gnuplot.Private.Graph as Graph
 
-import qualified Data.Monoid.State as State
-import Data.Monoid (Monoid, mappend, )
+import Data.Monoid (mappend, )
 
 
 data T graph =
@@ -18,11 +17,6 @@
 
 instance Graph.C graph => Display.C (T graph) where
    toScript frame =
-      (Display.Script $
-         State.Cons $ \(n, opts0) ->
-            let opts1 = option frame
-            in  (Display.Body [] $
-                 OptionSet.diffToString (OptionSet.Cons opts0) opts1,
-                 (n, OptionSet.decons opts1)))
+      (Plot.optionsToScript $ option frame)
       `mappend`
-      (Display.toScript $ plot frame)
+      (Plot.toScript $ plot frame)
diff --git a/src/Graphics/Gnuplot/Private/FrameOption.hs b/src/Graphics/Gnuplot/Private/FrameOption.hs
--- a/src/Graphics/Gnuplot/Private/FrameOption.hs
+++ b/src/Graphics/Gnuplot/Private/FrameOption.hs
@@ -1,27 +1,106 @@
+{- |
+If you add a new option,
+please mind to add a default value to FrameOptionSet.deflt, too.
+-}
 module Graphics.Gnuplot.Private.FrameOption where
 
-newtype T = Cons String
+{- |
+Every option represents an internal state in gnuplot.
+It is altered with gnuplot's set command.
+The first field in 'T' is the name of the option
+and the name of the according internal state in gnuplot.
+
+Sometimes the addressed state is not explicitly mentioned
+but is expressed by the syntax of the values.
+E.g. you can write @set grid xtics@ and @set grid noxtics@,
+but both commands refer to the same internal boolean variable,
+that we like to call @xtics@.
+It is important that the gnuplot Haskell bindings know
+that these two set commands refer to the same gnuplot state,
+since we want to simulate a stateless functional interface
+in front of a stateful imperative one.
+
+In case of a such a hidden state,
+we manage an identifier in the second field of 'T'.
+It is mainly used for distinguishing different hidden states,
+that are accessed by the same @set@ variable.
+This second field may not contain valid gnuplot identifiers,
+however you might use the field for formatting boolean options
+using 'Graphics.Gnuplot.Frame.OptionSet.addBool'.
+-}
+data T = Cons String String
    deriving (Eq, Ord, Show)
 
-custom :: String -> T
+{- |
+Constructs a generic option from Strings for the first and second field of 'T'.
+
+This is very flexible, but not very safe.
+Use it only as fall-back,
+if there is no specific setter function in "Graphics.Gnuplot.Frame.OptionSet".
+-}
+custom :: String -> String -> T
 custom = Cons
 
-title  :: T; title  = Cons "title"
-grid   :: T; grid   = Cons "grid"
-size   :: T; size   = Cons "size"
-key    :: T; key    = Cons "key"
-border :: T; border = Cons "border"
-pm3d   :: T; pm3d   = Cons "pm3d"
-view   :: T; view   = Cons "view"
+grid   :: String -> T; grid   = Cons "grid"
+size   :: String -> T; size   = Cons "size"
+key    :: String -> T; key    = Cons "key"
+border :: String -> T; border = Cons "border"
+pm3d   :: String -> T; pm3d   = Cons "pm3d"
 
-xRange :: T; xRange = Cons "xrange"
-yRange :: T; yRange = Cons "yrange"
-zRange :: T; zRange = Cons "zrange"
+xRange :: String -> T; xRange = Cons "xrange"
+yRange :: String -> T; yRange = Cons "yrange"
+zRange :: String -> T; zRange = Cons "zrange"
 
-xLabel :: T; xLabel = Cons "xlabel"
-yLabel :: T; yLabel = Cons "ylabel"
-zLabel :: T; zLabel = Cons "zlabel"
+xLabel :: String -> T; xLabel = Cons "xlabel"
+yLabel :: String -> T; yLabel = Cons "ylabel"
+zLabel :: String -> T; zLabel = Cons "zlabel"
 
-xTicks :: T; xTicks = Cons "xtics"
-yTicks :: T; yTicks = Cons "ytics"
-zTicks :: T; zTicks = Cons "ztics"
+xTicks :: String -> T; xTicks = Cons "xtics"
+yTicks :: String -> T; yTicks = Cons "ytics"
+zTicks :: String -> T; zTicks = Cons "ztics"
+
+xLogScale :: T; xLogScale = Cons "logscale x" ""
+yLogScale :: T; yLogScale = Cons "logscale y" ""
+zLogScale :: T; zLogScale = Cons "logscale z" ""
+
+
+title :: T; title = Cons "title" ""
+view  :: T; view  = Cons "view" ""
+
+xFormat :: T; xFormat = Cons "format x" ""
+yFormat :: T; yFormat = Cons "format y" ""
+zFormat :: T; zFormat = Cons "format z" ""
+
+timeFmt :: T; timeFmt = Cons "timefmt" ""
+
+xData :: T; xData = Cons "xdata" ""
+yData :: T; yData = Cons "ydata" ""
+zData :: T; zData = Cons "zdata" ""
+
+
+sizeScale :: T; sizeScale = size "scale"
+sizeRatio :: T; sizeRatio = size "ratio"
+keyShow     :: T; keyShow     = key "show"
+keyPosition :: T; keyPosition = key "position"
+
+xRangeBounds :: T; xRangeBounds = xRange "bounds"
+yRangeBounds :: T; yRangeBounds = yRange "bounds"
+zRangeBounds :: T; zRangeBounds = zRange "bounds"
+
+xLabelText :: T; xLabelText = xLabel "text"
+yLabelText :: T; yLabelText = yLabel "text"
+zLabelText :: T; zLabelText = zLabel "text"
+
+xTickLabels :: T; xTickLabels = xTicks "labels"
+yTickLabels :: T; yTickLabels = yTicks "labels"
+zTickLabels :: T; zTickLabels = zTicks "labels"
+
+gridXTicks :: T; gridXTicks = grid "xtics"
+gridYTicks :: T; gridYTicks = grid "ytics"
+gridZTicks :: T; gridZTicks = grid "ztics"
+
+boxwidth :: T; boxwidth = Cons "boxwidth" ""
+
+styleFillSolid  :: T; styleFillSolid  = Cons "style fill" "solid"
+styleFillBorder :: T; styleFillBorder = Cons "style fill" "border"
+styleHistogram  :: T; styleHistogram  = Cons "style histogram" ""
diff --git a/src/Graphics/Gnuplot/Private/FrameOptionSet.hs b/src/Graphics/Gnuplot/Private/FrameOptionSet.hs
--- a/src/Graphics/Gnuplot/Private/FrameOptionSet.hs
+++ b/src/Graphics/Gnuplot/Private/FrameOptionSet.hs
@@ -11,6 +11,7 @@
 module Graphics.Gnuplot.Private.FrameOptionSet where
 
 import qualified Graphics.Gnuplot.Private.FrameOption as Option
+import Graphics.Gnuplot.Utility (formatBool, )
 
 import qualified Data.Map as Map
 
@@ -18,33 +19,57 @@
 import Data.Maybe (mapMaybe, )
 
 
+type Plain = Map.Map Option.T [String]
+
 newtype T graph =
-   Cons {decons :: Map.Map Option.T [String]}
+   Cons {decons :: Plain}
 
+
 {- |
 The default options contain what we expect as default value in gnuplot.
-We need an entry for every option
-that cannot be reset by @unset@.
+We need an entry for every option that cannot be reset by @unset@.
 -}
-deflt :: T graph
+deflt :: Plain
 deflt =
-   Cons $ Map.fromList $
-   (Option.key, []) :
-   (Option.border, []) :
-   (Option.xLabel, []) :
-   (Option.yLabel, []) :
-   (Option.zLabel, []) :
-   (Option.xRange, ["[*:*]"]) :
-   (Option.yRange, ["[*:*]"]) :
-   (Option.zRange, ["[*:*]"]) :
-   (Option.xTicks, []) :
-   (Option.yTicks, []) :
-   (Option.zTicks, []) :
+   Map.fromList $
+   (Option.keyShow, []) :
+--   (Option.border, []) :
+   (Option.sizeRatio, ["noratio"]) :
+   (Option.xLabelText, []) :
+   (Option.yLabelText, []) :
+   (Option.zLabelText, []) :
+   (Option.xRangeBounds, ["[*:*]"]) :
+   (Option.yRangeBounds, ["[*:*]"]) :
+   (Option.zRangeBounds, ["[*:*]"]) :
+   (Option.xFormat, []) :
+   (Option.yFormat, []) :
+   (Option.zFormat, []) :
+   (Option.xTickLabels, []) :
+   (Option.yTickLabels, []) :
+   (Option.zTickLabels, []) :
+   (Option.gridXTicks, ["noxtics"]) :
+   (Option.gridYTicks, ["noytics"]) :
+   (Option.gridZTicks, ["noztics"]) :
+   (Option.styleFillSolid, ["0"]) :
+   (Option.styleFillBorder, []) :
+   (Option.styleHistogram, ["clustered"]) :
+--   (Option.timeFmt, [quote "%s"]) :
+   (Option.boxwidth, []) :
    []
 
+initial :: Plain
+initial =
+   flip Map.union deflt $
+   Map.fromList $
+   (Option.xData, []) :
+   (Option.yData, []) :
+   (Option.zData, []) :
+--   (Option.timeFmt, []) :
+   []
 
 {- |
-Add an option with arguments as plain strings.
+Add (set) an option with arguments as plain strings.
+
 This is very flexible, but not very safe.
 Use it only as fall-back,
 if there is no specific setter function in "Graphics.Gnuplot.Frame.OptionSet".
@@ -54,7 +79,11 @@
    Cons (Map.insert opt args m)
 
 {- |
-Remove an option.
+Remove (unset) an option.
+
+This is very flexible, but not very safe.
+Use it only as fall-back,
+if there is no specific setter function in "Graphics.Gnuplot.Frame.OptionSet".
 -}
 remove :: Option.T -> T graph -> T graph
 remove opt (Cons m) =
@@ -64,17 +93,49 @@
 Convert the difference between the first and the second option set
 into a sequence of 'set' and 'unset' commands.
 -}
-diffToString :: T graph -> T graph -> [String]
-diffToString (Cons m0) (Cons m1) =
+diffToString :: Plain -> Plain -> [String]
+diffToString m0 m1 =
    mapMaybe
-      (\(Option.Cons opt, (old,new)) ->
+      (\(Option.Cons opt _, (old,new)) ->
          toMaybe (old/=new) $
          maybe
             ("unset " ++ opt)
-            (\args -> "set " ++ opt ++ " " ++ unwords args)
+            (\args -> "set " ++ opt ++ concatMap (' ':) args)
             new) $
    Map.toList $
    Map.unionWith
       (\(old,_) (_,new) -> (old,new))
       (fmap (\x -> (Just x, Nothing)) m0)
       (fmap (\x -> (Nothing, Just x)) m1)
+
+{- |
+Set or unset option according to a 'Bool'.
+This is for switches that can be disabled using @unset@.
+
+This is very flexible, but not very safe.
+Use it only as fall-back,
+if there is no specific setter function in "Graphics.Gnuplot.Frame.OptionSet".
+
+See also: 'addBool', 'add', 'remove'.
+-}
+boolean :: Option.T -> Bool -> T graph -> T graph
+boolean opt on =
+   if on
+     then add opt []
+     else remove opt
+
+{- |
+Add an option with boolean value
+that is formatted like @set style fill border@ and @set style fill noborder@.
+The name of the internal state (i.e. @border@)
+must be stored in the second field of the option.
+
+This is very flexible, but not very safe.
+Use it only as fall-back,
+if there is no specific setter function in "Graphics.Gnuplot.Frame.OptionSet".
+
+See also 'boolean'.
+-}
+addBool :: Option.T -> Bool -> T graph -> T graph
+addBool opt@(Option.Cons _ state) arg =
+   add opt [formatBool state arg]
diff --git a/src/Graphics/Gnuplot/Private/Graph.hs b/src/Graphics/Gnuplot/Private/Graph.hs
--- a/src/Graphics/Gnuplot/Private/Graph.hs
+++ b/src/Graphics/Gnuplot/Private/Graph.hs
@@ -1,5 +1,10 @@
 module Graphics.Gnuplot.Private.Graph where
 
+import qualified Graphics.Gnuplot.Private.FrameOptionSet as OptionSet
+
 class C graph where
-   command :: graph -> String
+   command :: Command graph
    toString :: graph -> String
+   defltOptions :: OptionSet.T graph
+
+newtype Command graph = Command {commandString :: String}
diff --git a/src/Graphics/Gnuplot/Private/Graph2D.hs b/src/Graphics/Gnuplot/Private/Graph2D.hs
--- a/src/Graphics/Gnuplot/Private/Graph2D.hs
+++ b/src/Graphics/Gnuplot/Private/Graph2D.hs
@@ -1,53 +1,82 @@
 module Graphics.Gnuplot.Private.Graph2D where
 
+import qualified Graphics.Gnuplot.Private.FrameOptionSet as OptionSet
+import qualified Graphics.Gnuplot.Private.FrameOption as Option
 import qualified Graphics.Gnuplot.Private.LineSpecification as LineSpec
-import qualified Graphics.Gnuplot.Private.GraphType as GraphType
+import qualified Graphics.Gnuplot.Private.Graph2DType as GraphType
 import qualified Graphics.Gnuplot.Private.Graph as Graph
+import qualified Graphics.Gnuplot.Value.Atom as Atom
+import qualified Data.Map as Map
+import qualified Data.List as List
 
 import Prelude hiding (lines, )
 
 
-data T =
+data T x y =
    Cons {
-      column_   :: Column,
+      column_   :: Columns,
       type_     :: Type,
       lineSpec_ :: LineSpec.T
    }
 
-data Column =
-     Dim1 {columnX :: Int}
-   | Dim2 {columnX, columnY :: Int}
-
+type Columns = [Int]
 
-type Type = GraphType.T
+type Type = String
 
 
-columnToString :: Column -> String
-columnToString c =
-   case c of
-      Dim1 x -> show x
-      Dim2 x y -> show x ++ ":" ++ show y
+columnToString :: Columns -> String
+columnToString =
+   concat . List.intersperse ":" . map show
 
-toString :: T -> String
+toString :: T x y -> String
 toString (Cons c t l) =
    "using " ++ columnToString c ++
-   " with " ++ GraphType.toString t ++
+   " with " ++ t ++
    " " ++ LineSpec.toString l
 
-instance Graph.C T where
-   command _ = "plot"
-   toString = toString
 
+type AxisOption x y a =
+   OptionSet.T (T x y) -> Atom.OptionSet a
 
-defaultType :: Type
-defaultType = GraphType.lines
+defltOptions :: (Atom.C x, Atom.C y) => OptionSet.T (T x y)
+defltOptions =
+   let mk ::
+          Option.T -> Option.T ->
+          Atom.OptionSet a -> [(Option.T, [String])]
+       mk optData optFormat opts =
+          (optData, Atom.optData opts) :
+          (optFormat, Atom.optFormat opts) :
+          Atom.optOthers opts
+       result ::
+          Atom.OptionSet x ->
+          Atom.OptionSet y ->
+          OptionSet.T (T x y)
+       result optX optY =
+          OptionSet.Cons $
+          flip Map.union OptionSet.deflt $
+          Map.fromList $
+          mk Option.xData Option.xFormat optX ++
+          mk Option.yData Option.yFormat optY ++
+          (Option.zData, []) :
+          (Option.zFormat, []) :
+          []
+   in  result Atom.options Atom.options
 
-deflt :: Column -> T
-deflt c = Cons c defaultType LineSpec.deflt
 
+instance (Atom.C x, Atom.C y) => Graph.C (T x y) where
+   command = Graph.Command "plot"
+   toString = toString
+   defltOptions = defltOptions
 
-typ :: Type -> T -> T
+
+deflt :: GraphType.T x y a -> Columns -> T x y
+deflt t c = Cons c (GraphType.toString t) LineSpec.deflt
+
+typ :: Type -> T x y -> T x y
 typ t gr = gr{type_ = t}
 
-lineSpec :: LineSpec.T -> T -> T
+{- |
+You can alter the line specification of graphs in a plot using 'fmap'.
+-}
+lineSpec :: LineSpec.T -> T x y -> T x y
 lineSpec ls gr = gr{lineSpec_ = ls}
diff --git a/src/Graphics/Gnuplot/Private/Graph2DType.hs b/src/Graphics/Gnuplot/Private/Graph2DType.hs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/Gnuplot/Private/Graph2DType.hs
@@ -0,0 +1,125 @@
+module Graphics.Gnuplot.Private.Graph2DType where
+
+import qualified Graphics.Gnuplot.Value.Atom as Atom
+import qualified Graphics.Gnuplot.Value.Tuple as Tuple
+import Graphics.Gnuplot.Value.Tuple (Label)
+import Prelude hiding (lines, )
+
+
+{- |
+The type parameter @x@ is for the values on the X axis,
+@y@ of the Y axis and
+@a@ is the type of the plotted data.
+The type @a@ is a pair in case of points in the plane,
+or a more complex tuple in case of error plots and the like.
+-}
+newtype T x y a = Cons String
+
+tupleSize :: (Tuple.C a) => T x y a -> Tuple.ColumnCount a
+tupleSize _ = Tuple.columnCount
+
+
+{-
+See info:/gnuplot/set_style_rectangle
+-}
+
+listLines       :: (Atom.C y) => T Int y y
+listPoints      :: (Atom.C y) => T Int y y
+listLinesPoints :: (Atom.C y) => T Int y y
+listImpulses    :: (Atom.C y) => T Int y y
+listDots        :: (Atom.C y) => T Int y y
+histograms      :: (Atom.C y) => T Int y y
+
+xErrorBarsRelative   :: (Atom.C x, Atom.C y) => T x y ((x,y),x)
+yErrorBarsRelative   :: (Atom.C x, Atom.C y) => T x y ((x,y),y)
+xyErrorBarsRelative  :: (Atom.C x, Atom.C y) => T x y ((x,y),(x,y))
+xErrorBarsAbsolute   :: (Atom.C x, Atom.C y) => T x y ((x,y),(x,x))
+yErrorBarsAbsolute   :: (Atom.C x, Atom.C y) => T x y ((x,y),(y,y))
+xyErrorBarsAbsolute  :: (Atom.C x, Atom.C y) => T x y ((x,y),((x,x),(y,y)))
+
+xErrorLinesRelative  :: (Atom.C x, Atom.C y) => T x y ((x,y),x)
+yErrorLinesRelative  :: (Atom.C x, Atom.C y) => T x y ((x,y),y)
+xyErrorLinesRelative :: (Atom.C x, Atom.C y) => T x y ((x,y),(x,y))
+xErrorLinesAbsolute  :: (Atom.C x, Atom.C y) => T x y ((x,y),(x,x))
+yErrorLinesAbsolute  :: (Atom.C x, Atom.C y) => T x y ((x,y),(y,y))
+xyErrorLinesAbsolute :: (Atom.C x, Atom.C y) => T x y ((x,y),((x,x),(y,y)))
+
+lines          :: (Atom.C x, Atom.C y) => T x y (x,y)
+points         :: (Atom.C x, Atom.C y) => T x y (x,y)
+linesPoints    :: (Atom.C x, Atom.C y) => T x y (x,y)
+impulses       :: (Atom.C x, Atom.C y) => T x y (x,y)
+dots           :: (Atom.C x, Atom.C y) => T x y (x,y)
+steps          :: (Atom.C x, Atom.C y) => T x y (x,y)
+fSteps         :: (Atom.C x, Atom.C y) => T x y (x,y)
+hiSteps        :: (Atom.C x, Atom.C y) => T x y (x,y)
+errorBars      :: (Atom.C x, Atom.C y) => T x y (x,y)
+errorLines     :: (Atom.C x, Atom.C y) => T x y (x,y)
+boxes          :: (Atom.C x, Atom.C y) => T x y (x,y)
+filledCurves   :: (Atom.C x, Atom.C y) => T x y (x,y)
+{-
+boxErrorBars   :: (Atom.C x, Atom.C y) => T x y (x,y)
+boxXYErrorBars :: (Atom.C x, Atom.C y) => T x y (x,y)
+-}
+financeBars    :: (Atom.C x, Atom.C y) => T x y (x,(y,y,y,y))
+candleSticks   :: (Atom.C x, Atom.C y) => T x y (x,(y,y,y,y))
+vectors        :: (Atom.C x, Atom.C y) => T x y ((x,y),(x,y))
+image          :: (Atom.C x, Atom.C y, Atom.C z) => T x y ((x, y), z)
+
+filledStripe      :: (Atom.C x, Atom.C y) => T x y (x,(y,y))
+filledStripeAbove :: (Atom.C x, Atom.C y) => T x y (x,(y,y))
+filledStripeBelow :: (Atom.C x, Atom.C y) => T x y (x,(y,y))
+
+labels          :: (Atom.C x, Atom.C y) => T x y ((x,y),Label)
+
+
+listLines       = Cons "lines"
+listPoints      = Cons "points"
+listLinesPoints = Cons "linespoints"
+listImpulses    = Cons "impulses"
+listDots        = Cons "dots"
+histograms      = Cons "histograms"
+
+xErrorBarsRelative   = Cons "xerrorbars"
+yErrorBarsRelative   = Cons "yerrorbars"
+xyErrorBarsRelative  = Cons "xyerrorbars"
+xErrorBarsAbsolute   = Cons "xerrorbars"
+yErrorBarsAbsolute   = Cons "yerrorbars"
+xyErrorBarsAbsolute  = Cons "xyerrorbars"
+
+xErrorLinesRelative  = Cons "xerrorlines"
+yErrorLinesRelative  = Cons "yerrorlines"
+xyErrorLinesRelative = Cons "xyerrorlines"
+xErrorLinesAbsolute  = Cons "xerrorlines"
+yErrorLinesAbsolute  = Cons "yerrorlines"
+xyErrorLinesAbsolute = Cons "xyerrorlines"
+
+lines          = Cons "lines"
+points         = Cons "points"
+linesPoints    = Cons "linespoints"
+impulses       = Cons "impulses"
+dots           = Cons "dots"
+steps          = Cons "steps"
+fSteps         = Cons "fsteps"
+hiSteps        = Cons "histeps"
+errorBars      = Cons "errorbars"
+errorLines     = Cons "errorlines"
+boxes          = Cons "boxes"
+filledCurves   = Cons "filledcurves"
+{-
+boxErrorBars   = Cons "boxerrorbars"
+boxXYErrorBars = Cons "boxxyerrorbars"
+-}
+financeBars    = Cons "financebars"
+candleSticks   = Cons "candlesticks"
+vectors        = Cons "vectors"
+image          = Cons "image"
+
+filledStripe      = Cons "filledcurves"
+filledStripeAbove = Cons "filledcurves above"
+filledStripeBelow = Cons "filledcurves below"
+
+labels       = Cons "labels"
+
+
+toString :: T x y a -> String
+toString (Cons t) = t
diff --git a/src/Graphics/Gnuplot/Private/Graph3D.hs b/src/Graphics/Gnuplot/Private/Graph3D.hs
--- a/src/Graphics/Gnuplot/Private/Graph3D.hs
+++ b/src/Graphics/Gnuplot/Private/Graph3D.hs
@@ -1,53 +1,93 @@
 module Graphics.Gnuplot.Private.Graph3D where
 
+import qualified Graphics.Gnuplot.Private.FrameOptionSet as OptionSet
+import qualified Graphics.Gnuplot.Private.FrameOption as Option
 import qualified Graphics.Gnuplot.Private.LineSpecification as LineSpec
-import qualified Graphics.Gnuplot.Private.GraphType as GraphType
+import qualified Graphics.Gnuplot.Private.Graph3DType as GraphType
 import qualified Graphics.Gnuplot.Private.Graph as Graph
+import qualified Graphics.Gnuplot.Value.Atom as Atom
+import qualified Data.Map as Map
 
+import Graphics.Gnuplot.Private.Graph2D (Columns, columnToString, )
+
 import Prelude hiding (lines, )
 
 
-data T =
+data T x y z =
    Cons {
-      column_   :: Column,
+      column_   :: Columns,
       type_     :: Type,
       lineSpec_ :: LineSpec.T
    }
 
-data Column =
-     Dim3 {columnX, columnY, columnZ :: Int}
-   | Dim4 {columnX, columnY, columnZ, columnC :: Int}
-
-
-type Type = GraphType.T
+type Type = String
 
 
-columnToString :: Column -> String
-columnToString col =
-   case col of
-      Dim3 x y z -> show x ++ ":" ++ show y ++ ":" ++ show z
-      Dim4 x y z c -> show x ++ ":" ++ show y ++ ":" ++ show z ++ ":" ++ show c
-
-toString :: T -> String
+toString :: T x y z -> String
 toString (Cons c t l) =
    "using " ++ columnToString c ++
-   " with " ++ GraphType.toString t ++
+   " with " ++ t ++
    " " ++ LineSpec.toString l
 
-instance Graph.C T where
-   command _ = "splot"
-   toString = toString
 
+type AxisOption x y z a =
+   OptionSet.T (T x y z) -> Atom.OptionSet a
 
-defaultType :: Type
-defaultType = GraphType.pm3d
+defltOptions :: (Atom.C x, Atom.C y, Atom.C z) => OptionSet.T (T x y z)
+defltOptions =
+   let mk ::
+          Option.T -> Option.T ->
+          Atom.OptionSet a ->
+          [(Option.T, [String])]
+       mk optData optFormat opts =
+          (optData, Atom.optData opts) :
+          (optFormat, Atom.optFormat opts) :
+          Atom.optOthers opts
+       result ::
+          Atom.OptionSet x ->
+          Atom.OptionSet y ->
+          Atom.OptionSet z ->
+          OptionSet.T (T x y z)
+       result optX optY optZ =
+          OptionSet.Cons $
+          flip Map.union OptionSet.deflt $
+          Map.fromList $
+          mk Option.xData Option.xFormat optX ++
+          mk Option.yData Option.yFormat optY ++
+          mk Option.yData Option.yFormat optZ ++
+          []
+   in  result Atom.options Atom.options Atom.options
 
-deflt :: Column -> T
-deflt c = Cons c defaultType LineSpec.deflt
 
+instance (Atom.C x, Atom.C y, Atom.C z) => Graph.C (T x y z) where
+   command = Graph.Command "splot"
+   toString = toString
+   defltOptions = defltOptions
 
-typ :: Type -> T -> T
+
+pm3d :: T x y z
+pm3d = Cons (1:2:3:[]) "pm3d" LineSpec.deflt
+
+deflt :: GraphType.T x y z a -> Columns -> T x y z
+deflt t c = Cons c (GraphType.toString t) LineSpec.deflt
+
+typ :: Type -> T x y z -> T x y z
 typ t gr = gr{type_ = t}
 
-lineSpec :: LineSpec.T -> T -> T
+{-
+for 3D plots not all line attributes are supported like:
+   pointsize
+   pointtype
+
+pm3d and impulses allow:
+   linestyle
+   linewidth
+   linecolor
+   linetype
+   title
+
+FIXME:
+Do we need a separate LineSpec3D type or a type parameter for LineSpec?
+-}
+lineSpec :: LineSpec.T -> T x y z -> T x y z
 lineSpec ls gr = gr{lineSpec_ = ls}
diff --git a/src/Graphics/Gnuplot/Private/Graph3DType.hs b/src/Graphics/Gnuplot/Private/Graph3DType.hs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/Gnuplot/Private/Graph3DType.hs
@@ -0,0 +1,38 @@
+module Graphics.Gnuplot.Private.Graph3DType where
+
+import qualified Graphics.Gnuplot.Value.Atom as Atom
+import qualified Graphics.Gnuplot.Value.Tuple as Tuple
+
+import Prelude hiding (lines, )
+
+
+newtype T x y z a = Cons String
+
+tupleSize :: (Tuple.C a) => T x y z a -> Tuple.ColumnCount a
+tupleSize _ = Tuple.columnCount
+
+
+lines          :: (Atom.C x, Atom.C y, Atom.C z) => T x y z (x,y,z)
+points         :: (Atom.C x, Atom.C y, Atom.C z) => T x y z (x,y,z)
+
+lines          = Cons "lines"
+points         = Cons "points"
+
+
+{-
+See info:/gnuplot/set_style_rectangle
+-}
+
+impulses       :: (Atom.C x, Atom.C y, Atom.C z) => T x y z (x,y,z)
+vectors        :: (Atom.C x, Atom.C y, Atom.C z) => T x y z ((x,y,z), (x,y,z))
+pm3d           :: (Atom.C x, Atom.C y, Atom.C z) => T x y z (x,y,z)
+
+impulses       = Cons "impulses"
+vectors        = Cons "vectors"
+pm3d           = Cons "pm3d"
+
+{-# DEPRECATED pm3d "do not use this as graph type, use Graphics.Gnuplot.Plot.ThreeDimensional.surface instead" #-}
+
+
+toString :: T x y z a -> String
+toString (Cons t) = t
diff --git a/src/Graphics/Gnuplot/Private/GraphEmpty.hs b/src/Graphics/Gnuplot/Private/GraphEmpty.hs
--- a/src/Graphics/Gnuplot/Private/GraphEmpty.hs
+++ b/src/Graphics/Gnuplot/Private/GraphEmpty.hs
@@ -7,11 +7,14 @@
 module Graphics.Gnuplot.Private.GraphEmpty where
 
 import qualified Graphics.Gnuplot.Private.Graph as Graph
+import qualified Graphics.Gnuplot.Private.FrameOptionSet as OptionSet
 
 
 data T = Cons
 
 
 instance Graph.C T where
-   command _ = "clear"
+   command = Graph.Command "clear"
    toString = const ""
+   defltOptions =
+      OptionSet.Cons OptionSet.deflt
diff --git a/src/Graphics/Gnuplot/Private/GraphType.hs b/src/Graphics/Gnuplot/Private/GraphType.hs
deleted file mode 100644
--- a/src/Graphics/Gnuplot/Private/GraphType.hs
+++ /dev/null
@@ -1,61 +0,0 @@
-module Graphics.Gnuplot.Private.GraphType where
-
-import Prelude hiding (lines, )
-
-
-newtype T = Cons String
-
-
-lines          :: T
-points         :: T
-linesPoints    :: T
-impulses       :: T
-dots           :: T
-steps          :: T
-fSteps         :: T
-hiSteps        :: T
-errorBars      :: T
-xErrorBars     :: T
-yErrorBars     :: T
-xyErrorBars    :: T
-errorLines     :: T
-xErrorLines    :: T
-yErrorLines    :: T
-xyErrorLines   :: T
-boxes          :: T
-filledCurves   :: T
-boxErrorBars   :: T
-boxXYErrorBars :: T
-financeBars    :: T
-candleSticks   :: T
-vectors        :: T
-pm3d           :: T
-
-lines          = Cons "lines"
-points         = Cons "points"
-linesPoints    = Cons "linespoints"
-impulses       = Cons "impulses"
-dots           = Cons "dots"
-steps          = Cons "steps"
-fSteps         = Cons "fsteps"
-hiSteps        = Cons "histeps"
-errorBars      = Cons "errorbars"
-xErrorBars     = Cons "xerrorbars"
-yErrorBars     = Cons "yerrorbars"
-xyErrorBars    = Cons "xyerrorbars"
-errorLines     = Cons "errorlines"
-xErrorLines    = Cons "xerrorlines"
-yErrorLines    = Cons "yerrorlines"
-xyErrorLines   = Cons "xyerrorlines"
-boxes          = Cons "boxes"
-filledCurves   = Cons "filledcurves"
-boxErrorBars   = Cons "boxerrorbars"
-boxXYErrorBars = Cons "boxxyerrorbars"
-financeBars    = Cons "financebars"
-candleSticks   = Cons "candlesticks"
-vectors        = Cons "vectors"
-pm3d           = Cons "pm3d"
-
-
-toString :: T -> String
-toString (Cons t) = t
diff --git a/src/Graphics/Gnuplot/Private/LineSpecification.hs b/src/Graphics/Gnuplot/Private/LineSpecification.hs
--- a/src/Graphics/Gnuplot/Private/LineSpecification.hs
+++ b/src/Graphics/Gnuplot/Private/LineSpecification.hs
@@ -1,5 +1,6 @@
 module Graphics.Gnuplot.Private.LineSpecification where
 
+import qualified Graphics.Gnuplot.Private.ColorSpecification as Color
 import Data.Maybe (catMaybes, )
 import Graphics.Gnuplot.Utility (quote, )
 
@@ -14,6 +15,7 @@
       { lineStyle_ :: Maybe Int
       , lineType_  :: Maybe Int
       , lineWidth_ :: Maybe Double
+      , lineColor_ :: Maybe Color.T
       , pointType_ :: Maybe Int
       , pointSize_ :: Maybe Double
       , title_     :: Maybe String
@@ -25,6 +27,7 @@
       { lineStyle_ = Nothing
       , lineType_  = Nothing
       , lineWidth_ = Nothing
+      , lineColor_ = Nothing
       , pointType_ = Nothing
       , pointSize_ = Nothing
       , title_     = Nothing
@@ -39,6 +42,9 @@
 lineWidth :: Double -> T -> T
 lineWidth x ls = ls{lineWidth_ = Just x}
 
+lineColor :: Color.T -> T -> T
+lineColor x ls = ls{lineColor_ = Just x}
+
 pointType :: Int -> T -> T
 pointType x ls = ls{pointType_ = Just x}
 
@@ -54,10 +60,11 @@
    let showField :: String -> (a -> String) -> (T -> Maybe a) -> Maybe [String]
        showField s f access = fmap (\a -> [s, f a]) $ access linespec
    in  unwords $ concat $ catMaybes $
+       showField "linestyle" show  lineStyle_ :
        showField "linetype"  show  lineType_  :
        showField "linewidth" show  lineWidth_ :
+       showField "linecolor" Color.toString lineColor_ :
        showField "pointtype" show  pointType_ :
        showField "pointsize" show  pointSize_ :
        showField "title"     quote title_     :
-       showField "linestyle" show  lineStyle_ :
        []
diff --git a/src/Graphics/Gnuplot/Private/Plot.hs b/src/Graphics/Gnuplot/Private/Plot.hs
--- a/src/Graphics/Gnuplot/Private/Plot.hs
+++ b/src/Graphics/Gnuplot/Private/Plot.hs
@@ -1,39 +1,66 @@
 module Graphics.Gnuplot.Private.Plot where
 
-import qualified Data.Monoid.State as State
-import Data.Monoid (Monoid, mempty, mappend, )
-
-import qualified Graphics.Gnuplot.Display as Display
+import qualified Graphics.Gnuplot.Private.Display as Display
+import qualified Graphics.Gnuplot.Private.FrameOptionSet as OptionSet
 import qualified Graphics.Gnuplot.Private.Graph as Graph
+import qualified Graphics.Gnuplot.Private.File as FileClass
+import qualified Graphics.Gnuplot.File as File
 import Graphics.Gnuplot.Utility (quote, commaConcat, )
 
-import Data.Maybe (mapMaybe, )
+import qualified Control.Monad.Trans.Reader as MR
+import qualified Control.Monad.Trans.State as MS
+import qualified Control.Monad.Trans.Class as MT
+import qualified Data.Accessor.Monad.Trans.State as AccState
+import qualified Data.Accessor.Tuple as AccTuple
+import qualified Data.Foldable as Fold
+import Control.Monad (liftM2, return, )
+import Data.Monoid (Monoid, mempty, mappend, )
+import Data.Semigroup (Semigroup, (<>), )
+import Data.Maybe (Maybe(Just, Nothing), mapMaybe, )
+import Data.List (concatMap, map, (++), )
+import Data.Function (($), (.), )
 
 
+import qualified System.FilePath as Path
+import System.FilePath (FilePath, (</>), )
+
+import Prelude (Functor, fmap, String, show, Int, succ, writeFile, )
+
+
 {- |
-Plots can be assembled using 'mappend' or 'mconcat'.
+Plots can be assembled using 'mappend' or 'mconcat'
+or several functions from "Data.Foldable".
 -}
-newtype T graph = Cons (State.T Int [File graph])
+newtype T graph = Cons (MS.StateT Int (MR.Reader FilePath) [File graph])
 
+pure :: [File graph] -> T graph
+pure = Cons . return
+
+instance Semigroup (T graph) where
+   Cons s0 <> Cons s1 = Cons (liftM2 (<>) s0 s1)
+
 {-
 Could also be implemented with Control.Monad.Trans.State:
 mappend = liftA2 mappend
 -}
 instance Monoid (T graph) where
-   mempty = Cons mempty
-   mappend (Cons s0) (Cons s1) =
-      Cons (mappend s0 s1)
+   mempty = Cons $ return mempty
+   mappend = (<>)
 
 
 withUniqueFile :: String -> [graph] -> T graph
-withUniqueFile content graphs =
-   Cons (State.Cons $ \n ->
-      ([File (tmpFileStem ++ show n ++ ".csv") (Just content) graphs],
-       succ n))
+withUniqueFile content graphs = Cons $ do
+   n <- MS.get
+   dir <- MT.lift MR.ask
+   MS.put $ succ n
+   return $
+      [File
+         (dir </> Path.addExtension (tmpFileStem ++ show n) "csv")
+         (Just content) graphs]
 
 fromGraphs :: FilePath -> [graph] -> T graph
 fromGraphs name gs =
-   Cons (State.pure [File name Nothing gs])
+   pure [File name Nothing gs]
 
 
 data File graph =
@@ -43,9 +70,9 @@
       graphs_ :: [graph]
    }
 
-writeData :: File graph -> IO ()
-writeData (File fn cont _) =
-   maybe (return ()) (writeFile fn) cont
+instance FileClass.C (File graph) where
+   write (File fn cont _) =
+      Fold.mapM_ (writeFile fn) cont
 
 
 tmpFileStem :: FilePath
@@ -63,24 +90,48 @@
       fmap (map (\file -> file{graphs_ = map f $ graphs_ file}))
       mp
 
+{- |
+In contrast to the Display.toScript method instantiation
+this function leaves the options,
+and thus can be used to write the Display.toScript instance for Frame.
+-}
+toScript :: Graph.C graph => T graph -> Display.Script
+toScript p@(Cons mp) =
+   Display.Script $ do
+      blocks <- AccState.liftT AccTuple.first mp
+      let files =
+             mapMaybe
+                (\blk -> fmap (File.Cons (filename_ blk)) (content_ blk))
+                blocks
+          graphs =
+             concatMap
+                (\blk ->
+                   map
+                      (\gr ->
+                         quote (filename_ blk) ++ " " ++
+                         Graph.toString gr) $ graphs_ blk) $
+             blocks
+      return $
+         Display.Body files
+            [Graph.commandString (plotCmd p) ++ " " ++ commaConcat graphs]
+
+optionsToScript :: Graph.C graph => OptionSet.T graph -> Display.Script
+optionsToScript opts =
+   Display.Script $
+   AccState.liftT AccTuple.second $ do
+      opts0 <- MS.get
+      let opts1 = OptionSet.decons opts
+      MS.put opts1
+      return $
+         Display.Body [] $
+         OptionSet.diffToString opts0 opts1
+
+defltOpts :: Graph.C graph => T graph -> OptionSet.T graph
+defltOpts _ = Graph.defltOptions
+
 instance Graph.C graph => Display.C (T graph) where
-   toScript p@(Cons mp) =
-      Display.Script $ State.Cons $
-         \(n0, opts) ->
-            let (blocks, n1) = State.run mp n0
-                files =
-                   mapMaybe
-                      (\blk -> fmap (Display.File (filename_ blk)) (content_ blk))
-                      blocks
-                graphs =
-                   concatMap (\blk ->
-                      map (\gr -> quote (filename_ blk) ++ " " ++ Graph.toString gr) $ graphs_ blk) $
-                      blocks
-            in  (Display.Body files
-                    [plotCmd p undefined ++ " " ++ commaConcat graphs],
-                 (n1, opts))
+   toScript plot =
+      optionsToScript (defltOpts plot)  `mappend`  toScript plot
 
-plotCmd ::
-   Graph.C graph =>
-   T graph -> graph -> String
+plotCmd :: Graph.C graph => T graph -> Graph.Command graph
 plotCmd _plot = Graph.command
diff --git a/src/Graphics/Gnuplot/Private/Terminal.hs b/src/Graphics/Gnuplot/Private/Terminal.hs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/Gnuplot/Private/Terminal.hs
@@ -0,0 +1,19 @@
+module Graphics.Gnuplot.Private.Terminal where
+
+data T =
+   Cons {
+      precommands :: [String],
+      options :: [String],
+      commands :: [String],
+      interactive :: Bool
+   }
+
+class C terminal where
+   canonical :: terminal -> T
+
+format :: T -> [String]
+format (Cons pre opts cmds _ia) =
+   pre ++
+   if null opts
+     then cmds
+     else (unwords $ "set" : "terminal" : opts) : cmds
diff --git a/src/Graphics/Gnuplot/Simple.hs b/src/Graphics/Gnuplot/Simple.hs
--- a/src/Graphics/Gnuplot/Simple.hs
+++ b/src/Graphics/Gnuplot/Simple.hs
@@ -5,6 +5,10 @@
 instead we provide an advanced modularized interface
 in "Graphics.Gnuplot.Advanced".
 
+Here is a pretty simple example:
+
+> Graphics.Gnuplot.Simple> plotFunc [] (linearScale 1000 (-10,10::Double)) sin
+
 This was formerly part of the htam package.
 -}
 module Graphics.Gnuplot.Simple (
@@ -51,27 +55,34 @@
 import qualified Graphics.Gnuplot.Plot.ThreeDimensional as Plot3D
 import qualified Graphics.Gnuplot.Private.LineSpecification as LineSpec
 import qualified Graphics.Gnuplot.Private.Graph2D as Graph2D
-import qualified Graphics.Gnuplot.Private.Graph3D as Graph3D
-import qualified Graphics.Gnuplot.Private.GraphType as GraphType
+import qualified Graphics.Gnuplot.Private.Graph2DType as GraphType
+import qualified Graphics.Gnuplot.Private.Graph as Graph
 import qualified Graphics.Gnuplot.Private.Plot as Plot
 
+import qualified Graphics.Gnuplot.Value.Tuple as Tuple
+import qualified Graphics.Gnuplot.Value.Atom as Atom
+
 {-
 import qualified Graphics.Gnuplot.Terminal.PostScript as PS
 import qualified Graphics.Gnuplot.Terminal.PNG as PNG
 import qualified Graphics.Gnuplot.Terminal.SVG as SVG
 -}
 
-import qualified Graphics.Gnuplot.Terminal as Terminal
-import qualified Graphics.Gnuplot.Execute as Exec
+import qualified Graphics.Gnuplot.Private.Terminal as Terminal
 
-import System.Cmd (rawSystem, )
 import Graphics.Gnuplot.Utility
-   (quote, commaConcat, showTriplet, linearScale, )
-import qualified Data.Monoid.State as State
+   (quote, commaConcat, semiColonConcat, showTriplet, linearScale, )
+
+import qualified Control.Monad.Trans.Reader as MR
+import qualified Control.Monad.Trans.State as MS
+
+import qualified Graphics.Gnuplot.Private.Command as Cmd
+import System.Process (rawSystem, )
+import Control.Functor.HT (void, )
+
+import qualified Data.List.Reverse.StrictElement as ListRev
+import Data.Foldable (foldMap, )
 import Data.Maybe (listToMaybe, mapMaybe, isNothing, )
-import Data.List.HT (dropWhileRev, )
-import Data.List (intersperse, )
-import Data.Monoid (mconcat, )
 
 
 -- * User front-end
@@ -93,6 +104,7 @@
    | Title  String
    | XLabel String
    | YLabel String
+   | ZLabel String
    | XRange (Double, Double)
    | YRange (Double, Double)
    | ZRange (Double, Double)
@@ -109,8 +121,23 @@
      Ratio Double
    | NoRatio
 
-{- The Int types would be better enumerations
-   but their interpretations depend on the gnuplot output type. :-( -}
+{- |
+Be careful with 'LineTitle'
+which can only be used as part of gnuplot's @plot@ command
+but not as part of @set@.
+That is,
+
+> plotList [LineStyle 0 [LineTitle "foobar"]] [0,5..100::Double]
+
+will leave you with an invalid gnuplot script, whereas
+
+> plotListStyle [] (defaultStyle {lineSpec = CustomStyle [LineTitle "foobar"]}) [0,5..100::Double]
+
+does what you want.
+
+The 'Int' types would be better enumerations
+but their interpretations depend on the gnuplot output type. :-(
+-}
 data LineAttr =
      LineType  Int
    | LineWidth Double
@@ -163,75 +190,109 @@
 
 -- * plot functions
 
+list :: (Tuple.C a) => [a] -> Plot2D.T Double Double
+list = Plot2D.list (GraphType.Cons "lines")
+-- list = Plot2D.list GraphType.listLines
+
 {- |
 > plotList [] (take 30 (let fibs = 0 : 1 : zipWith (+) fibs (tail fibs) in fibs))
 -}
-plotList :: Show a => [Attribute] -> [a] -> IO ()
+plotList ::
+   (Tuple.C a) =>
+   [Attribute] -> [a] -> IO ()
 plotList attrs =
-   plot2d attrs . Plot2D.list
+   plot2d attrs . list
 
-plotListStyle :: Show a => [Attribute] -> PlotStyle -> [a] -> IO ()
+{- |
+> plotListStyle [] (defaultStyle{plotType = CandleSticks}) (Plot2D.functionToGraph (linearScale 32 (0,2*pi::Double)) (\t -> (-sin t, -2*sin t, 2*sin t, sin t)))
+-}
+plotListStyle ::
+   (Tuple.C a) =>
+   [Attribute] -> PlotStyle -> [a] -> IO ()
 plotListStyle attrs style =
-   plot2d attrs . setPlotStyle style . Plot2D.list
+   plot2d attrs . setPlotStyle style . list
 
-plotLists :: Show a => [Attribute] -> [[a]] -> IO ()
+plotLists ::
+   (Tuple.C a) =>
+   [Attribute] -> [[a]] -> IO ()
 plotLists attrs xss =
-   plot2d attrs (mconcat $ map Plot2D.list xss)
+   plot2d attrs (foldMap list xss)
 
-plotListsStyle :: Show a => [Attribute] -> [(PlotStyle, [a])] -> IO ()
+plotListsStyle ::
+   (Tuple.C a) =>
+   [Attribute] -> [(PlotStyle, [a])] -> IO ()
 plotListsStyle attrs =
-   plot2d attrs . mconcat .
-   map (\(style,xs) -> setPlotStyle style $ Plot2D.list xs)
+   plot2d attrs .
+   foldMap (\(style,xs) -> setPlotStyle style $ list xs)
 
 {- |
 > plotFunc [] (linearScale 1000 (-10,10)) sin
 -}
-plotFunc :: Show a => [Attribute] -> [a] -> (a -> a) -> IO ()
+plotFunc ::
+   (Atom.C a, Tuple.C a) =>
+   [Attribute] -> [a] -> (a -> a) -> IO ()
 plotFunc attrs args f =
-   plot2d attrs (Plot2D.function args f)
+   plot2d attrs (Plot2D.function GraphType.lines args f)
 
 {- |
 > plotFuncs [] (linearScale 1000 (-10,10)) [sin, cos]
 -}
-plotFuncs :: Show a => [Attribute] -> [a] -> [a -> a] -> IO ()
+plotFuncs ::
+   (Atom.C a, Tuple.C a) =>
+   [Attribute] -> [a] -> [a -> a] -> IO ()
 plotFuncs attrs args fs =
-   plot2d attrs (Plot2D.functions args fs)
+   plot2d attrs (Plot2D.functions GraphType.lines args fs)
 
-plotPath :: Show a => [Attribute] -> [(a,a)] -> IO ()
+plotPath ::
+   (Tuple.C a) =>
+   [Attribute] -> [(a,a)] -> IO ()
 plotPath attrs =
-   plot2d attrs . Plot2D.path
+   plot2d attrs . list
 
-plotPaths :: Show a => [Attribute] -> [[(a,a)]] -> IO ()
+plotPaths ::
+   (Tuple.C a) =>
+   [Attribute] -> [[(a,a)]] -> IO ()
 plotPaths attrs xss =
-   plot2d attrs (mconcat $ map Plot2D.path xss)
+   plot2d attrs (foldMap list xss)
 
-plotPathStyle :: Show a => [Attribute] -> PlotStyle -> [(a,a)] -> IO ()
+plotPathStyle ::
+   (Tuple.C a) =>
+   [Attribute] -> PlotStyle -> [(a,a)] -> IO ()
 plotPathStyle attrs style =
-   plot2d attrs . setPlotStyle style . Plot2D.path
+   plot2d attrs . setPlotStyle style . list
 
-plotPathsStyle :: Show a => [Attribute] -> [(PlotStyle, [(a,a)])] -> IO ()
+plotPathsStyle ::
+   (Tuple.C a) =>
+   [Attribute] -> [(PlotStyle, [(a,a)])] -> IO ()
 plotPathsStyle attrs =
-   plot2d attrs . mconcat .
-   map (\(style,xs) -> setPlotStyle style $ Plot2D.path xs)
+   plot2d attrs .
+   foldMap (\(style,xs) -> setPlotStyle style $ list xs)
 
 {- |
 > plotParamFunc [] (linearScale 1000 (0,2*pi)) (\t -> (sin (2*t), cos t))
 -}
-plotParamFunc :: Show a => [Attribute] -> [a] -> (a -> (a,a)) -> IO ()
+plotParamFunc ::
+   (Atom.C a, Tuple.C a) =>
+   [Attribute] -> [a] -> (a -> (a,a)) -> IO ()
 plotParamFunc attrs args f =
-   plot2d attrs (Plot2D.parameterFunction args f)
+   plot2d attrs (Plot2D.parameterFunction GraphType.lines args f)
 
 {- |
 > plotParamFuncs [] (linearScale 1000 (0,2*pi)) [\t -> (sin (2*t), cos t), \t -> (cos t, sin (2*t))]
 -}
-plotParamFuncs :: Show a => [Attribute] -> [a] -> [a -> (a,a)] -> IO ()
+plotParamFuncs ::
+   (Atom.C a, Tuple.C a) =>
+   [Attribute] -> [a] -> [a -> (a,a)] -> IO ()
 plotParamFuncs attrs args fs =
-   plot2d attrs (mconcat $ map (Plot2D.parameterFunction args) fs)
+   plot2d attrs $
+   foldMap (Plot2D.parameterFunction GraphType.lines args) fs
 
 
-plotDots :: Show a => [Attribute] -> [(a,a)] -> IO ()
+plotDots ::
+   (Atom.C a, Tuple.C a) =>
+   [Attribute] -> [(a,a)] -> IO ()
 plotDots attrs xs =
-   plot2d attrs (fmap (Graph2D.typ GraphType.dots) $ Plot2D.path xs)
+   plot2d attrs (Plot2D.list GraphType.dots xs)
 
 
 
@@ -255,19 +316,25 @@
 
 {- |
 > let xs = [-2,-1.8..2::Double] in plotMesh3d [] [] (do x <- xs; return (do y <- xs; return (x,y,cos(x*x+y*y))))
+
+> let phis = linearScale 30 (-pi, pi :: Double) in plotMesh3d [] [] (do phi <- phis; return (do psi <- phis; let r = 5 + sin psi in return (r * cos phi, r * sin phi, cos psi)))
 -}
-plotMesh3d :: (Show a, Show b, Show c) =>
-   [Attribute] -> [Attribute3d] -> [[(a,b,c)]] -> IO ()
+plotMesh3d ::
+   (Atom.C x, Atom.C y, Atom.C z,
+    Tuple.C x, Tuple.C y, Tuple.C z) =>
+   [Attribute] -> [Attribute3d] -> [[(x,y,z)]] -> IO ()
 plotMesh3d attrs pt dat =
    plot3d attrs pt (Plot3D.mesh dat)
 
 {- |
 > let xs = [-2,-1.8..2::Double] in plotFunc3d [] [] xs xs (\x y -> exp(-(x*x+y*y)))
 -}
-plotFunc3d :: (Show a, Show b, Show c) =>
-   [Attribute] -> [Attribute3d] -> [b] -> [c] -> (b -> c -> a) -> IO ()
+plotFunc3d ::
+   (Atom.C x, Atom.C y, Atom.C z,
+    Tuple.C x, Tuple.C y, Tuple.C z) =>
+   [Attribute] -> [Attribute3d] -> [x] -> [y] -> (x -> y -> z) -> IO ()
 plotFunc3d attrs pt xArgs yArgs f =
-   plot3d attrs pt (Plot3D.function xArgs yArgs f)
+   plot3d attrs pt (Plot3D.surface xArgs yArgs f)
 
 
 
@@ -281,8 +348,7 @@
    -> IO ()
 epspdfPlot filename plot =
    do plot (EPS (filename++".eps") : Key Nothing : [])
-      rawSystem "epstopdf" [filename++".eps"]
-      return ()
+      void $ rawSystem "epstopdf" [filename++".eps"]
 
 {-| Creates an EPS and a PDF graphics
     and returns a string that can be inserted into a LaTeX document
@@ -308,10 +374,8 @@
 attrToProg (Custom attribute parameters) =
    "set " ++ attribute ++ " " ++ unwords parameters
 
-attrToProg (Terminal (Terminal.Cons options commands)) =
-   concat $
-   intersperse "; " $
-   ("set terminal " ++ unwords options) : commands
+attrToProg (Terminal term) =
+   semiColonConcat $ Terminal.format term
 
 attrToProg (EPS filename) =
    "set terminal postscript eps; " ++  -- latex
@@ -343,6 +407,7 @@
 attrToProg (Title  title_)       = "set title " ++ quote title_
 attrToProg (XLabel label)        = "set xlabel " ++ quote label
 attrToProg (YLabel label)        = "set ylabel " ++ quote label
+attrToProg (ZLabel label)        = "set zlabel " ++ quote label
 attrToProg (XRange _)            = ""  -- xrange is handled in plot command
 attrToProg (YRange _)            = ""  -- yrange is handled in plot command
 attrToProg (ZRange _)            = ""  -- zrange is handled in plot command
@@ -370,37 +435,46 @@
    let ranges = map (listToMaybe . flip mapMaybe attrs)
                     [xRangeFromAttr, yRangeFromAttr, zRangeFromAttr]
        showRng (l,r) = "[" ++ show l ++ ":" ++ show r ++ "]"
-   in  unwords (map (maybe "[:]" showRng) (dropWhileRev isNothing ranges))
+   in  unwords $ map (maybe "[:]" showRng) (ListRev.dropWhile isNothing ranges)
 
+interactiveTerm :: [Attribute] -> Bool
+interactiveTerm =
+   all $ \attr ->
+      case attr of
+         Terminal term -> Terminal.interactive term
+         PNG _ -> False
+         EPS _ -> False
+         _ -> True
 
 
-plotTypeToGraph :: PlotType -> GraphType.T
+
+plotTypeToGraph :: PlotType -> Graph2D.Type -- GraphType.T
 plotTypeToGraph t =
    case t of
-      Lines          -> GraphType.lines
-      Points         -> GraphType.points
-      LinesPoints    -> GraphType.linesPoints
-      Impulses       -> GraphType.impulses
-      Dots           -> GraphType.dots
-      Steps          -> GraphType.steps
-      FSteps         -> GraphType.fSteps
-      HiSteps        -> GraphType.hiSteps
-      ErrorBars      -> GraphType.errorBars
-      XErrorBars     -> GraphType.xErrorBars
-      YErrorBars     -> GraphType.yErrorBars
-      XYErrorBars    -> GraphType.xyErrorBars
-      ErrorLines     -> GraphType.errorLines
-      XErrorLines    -> GraphType.xErrorLines
-      YErrorLines    -> GraphType.yErrorLines
-      XYErrorLines   -> GraphType.xyErrorLines
-      Boxes          -> GraphType.boxes
-      FilledCurves   -> GraphType.filledCurves
-      BoxErrorBars   -> GraphType.boxErrorBars
-      BoxXYErrorBars -> GraphType.boxXYErrorBars
-      FinanceBars    -> GraphType.financeBars
-      CandleSticks   -> GraphType.candleSticks
-      Vectors        -> GraphType.vectors
-      PM3d           -> GraphType.pm3d
+      Lines          -> "lines"
+      Points         -> "points"
+      LinesPoints    -> "linespoints"
+      Impulses       -> "impulses"
+      Dots           -> "dots"
+      Steps          -> "steps"
+      FSteps         -> "fsteps"
+      HiSteps        -> "histeps"
+      ErrorBars      -> "errorbars"
+      XErrorBars     -> "xerrorbars"
+      YErrorBars     -> "yerrorbars"
+      XYErrorBars    -> "xyerrorbars"
+      ErrorLines     -> "errorlines"
+      XErrorLines    -> "xerrorlines"
+      YErrorLines    -> "yerrorlines"
+      XYErrorLines   -> "xyerrorlines"
+      Boxes          -> "boxes"
+      FilledCurves   -> "filledcurves"
+      BoxErrorBars   -> "boxerrorbars"
+      BoxXYErrorBars -> "boxxyerrorbars"
+      FinanceBars    -> "financebars"
+      CandleSticks   -> "candlesticks"
+      Vectors        -> "vectors"
+      PM3d           -> "pm3d"
 
 
 plot3dTypeToString :: Plot3dType -> String
@@ -423,30 +497,24 @@
 
 
 
-plot2d :: [Attribute] -> Plot2D.T -> IO ()
-plot2d attrs (Plot.Cons mp) =
-   let files = State.evaluate 0 mp
-   in  do mapM_ Plot.writeData files
-          callGnuplot attrs "plot" $
-             concatMap (\(Plot.File filename _ grs) ->
-                map (\gr -> quote filename ++ " " ++ Graph2D.toString gr) grs) $
-             files
+plot2d ::
+   (Atom.C x, Atom.C y) =>
+   [Attribute] -> Plot2D.T x y -> IO ()
+plot2d attrs plt =
+   runGnuplot attrs "plot" plt
 
-setPlotStyle :: PlotStyle -> Plot2D.T -> Plot2D.T
+setPlotStyle :: PlotStyle -> Plot2D.T x y -> Plot2D.T x y
 setPlotStyle ps =
    fmap (Graph2D.typ (plotTypeToGraph $ plotType ps) .
          Graph2D.lineSpec (lineSpecRecord $ lineSpec ps))
 
 
-plot3d :: [Attribute] -> [Attribute3d] -> Plot3D.T -> IO ()
-plot3d attrs pt (Plot.Cons mp) =
-   let files = State.evaluate 0 mp
-   in  do mapM_ Plot.writeData files
-          callGnuplot
-             (attrs ++ [Custom "pm3d" (map attribute3dToString pt)]) "splot" $
-             concatMap (\(Plot.File filename _ grs) ->
-                map (\gr -> quote filename ++ " " ++ Graph3D.toString gr) grs) $
-             files
+plot3d ::
+   (Atom.C x, Atom.C y, Atom.C z) =>
+   [Attribute] -> [Attribute3d] -> Plot3D.T x y z -> IO ()
+plot3d attrs pt plt =
+   runGnuplot
+      (Custom "pm3d" (map attribute3dToString pt) : attrs) "splot" plt
 
 
 lineSpecRecord :: LineSpec -> LineSpec.T
@@ -466,13 +534,21 @@
          LineTitle s -> LineSpec.title     s
       )
 
-callGnuplot :: [Attribute] -> String -> [String] -> IO ()
-callGnuplot attrs cmd params =
-   Exec.simple
-      (map attrToProg attrs ++
-       [cmd ++ " " ++
-        extractRanges attrs ++ " " ++
-        commaConcat params])
-      ["-persist"]
-   -- instead of the option, one can also use 'set terminal x11 persist'
-     >> return ()
+runGnuplot ::
+   Graph.C graph =>
+   [Attribute] -> String -> Plot.T graph -> IO ()
+runGnuplot attrs cmd (Plot.Cons mp) =
+   void $ Cmd.asyncIfInteractive (interactiveTerm attrs) $ Cmd.run $ \dir ->
+      let files = MR.runReader (MS.evalStateT mp 0) dir
+      in  (map attrToProg attrs ++
+           [cmd ++ " " ++
+            extractRanges attrs ++ " " ++
+            commaConcat (plotFileStatements files)],
+           files)
+
+plotFileStatements ::
+   Graph.C graph => [Plot.File graph] -> [String]
+plotFileStatements =
+   concatMap
+      (\(Plot.File filename _ grs) ->
+         map (\gr -> quote filename ++ " " ++ Graph.toString gr) grs)
diff --git a/src/Graphics/Gnuplot/Terminal.hs b/src/Graphics/Gnuplot/Terminal.hs
--- a/src/Graphics/Gnuplot/Terminal.hs
+++ b/src/Graphics/Gnuplot/Terminal.hs
@@ -1,18 +1,3 @@
-module Graphics.Gnuplot.Terminal where
-
-data T =
-   Cons {
-      options :: [String],
-      commands :: [String]
-   }
-
-class C terminal where
-   canonical :: terminal -> T
-
-deflt :: T
-deflt = Cons ["x11"] []
-
+module Graphics.Gnuplot.Terminal (C, ) where
 
-formatBool :: String -> Bool -> String
-formatBool name b =
-   if b then name else "no"++name
+import Graphics.Gnuplot.Private.Terminal
diff --git a/src/Graphics/Gnuplot/Terminal/Default.hs b/src/Graphics/Gnuplot/Terminal/Default.hs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/Gnuplot/Terminal/Default.hs
@@ -0,0 +1,21 @@
+module Graphics.Gnuplot.Terminal.Default (
+   T, cons,
+   ) where
+
+import qualified Graphics.Gnuplot.Private.Terminal as Terminal
+
+
+data T = Cons
+
+cons :: T
+cons = Cons
+
+
+instance Terminal.C T where
+   canonical _term =
+      Terminal.Cons {
+         Terminal.precommands = [],
+         Terminal.options = [],
+         Terminal.commands = [],
+         Terminal.interactive = True  -- Always true? I don't know.
+      }
diff --git a/src/Graphics/Gnuplot/Terminal/PNG.hs b/src/Graphics/Gnuplot/Terminal/PNG.hs
--- a/src/Graphics/Gnuplot/Terminal/PNG.hs
+++ b/src/Graphics/Gnuplot/Terminal/PNG.hs
@@ -1,20 +1,22 @@
 module Graphics.Gnuplot.Terminal.PNG (
    T, cons,
+   encoding,
    transparent, noTransparent,
    interlace, noInterlace,
    trueColor, noTrueColor,
    fontTiny, fontSmall, fontMedium, fontLarge, fontGiant,
    ) where
 
-import qualified Graphics.Gnuplot.Terminal as Terminal
-import Graphics.Gnuplot.Terminal (formatBool, )
+import qualified Graphics.Gnuplot.Private.Terminal as Terminal
+import qualified Graphics.Gnuplot.Private.Encoding as Encoding
 import Data.Maybe (catMaybes, )
-import Graphics.Gnuplot.Utility (quote, )
+import Graphics.Gnuplot.Utility (quote, formatBool, )
 
 
 data T =
    Cons {
       filename_ :: FilePath,
+      encoding_ :: Maybe Encoding.T,
       transparent_ :: Maybe Bool,
       interlace_ :: Maybe Bool,
       trueColor_ :: Maybe Bool,
@@ -25,6 +27,7 @@
 cons path =
    Cons {
       filename_ = path,
+      encoding_ = Nothing,
       transparent_ = Nothing,
       interlace_ = Nothing,
       trueColor_ = Nothing,
@@ -32,6 +35,13 @@
    }
 
 
+{- |
+Setting the encoding to anything different
+from 'Graphics.Gnuplot.Encoding.locale'
+makes only sense if you write your gnuplot files manually using this encoding.
+-}
+encoding :: Encoding.T -> T -> T
+encoding enc term = term{encoding_ = Just enc}
 
 transparent, noTransparent :: T -> T
 transparent   term = term{transparent_ = Just True}
@@ -78,6 +88,7 @@
 instance Terminal.C T where
    canonical term =
       Terminal.Cons {
+         Terminal.precommands = Encoding.formatMaybe $ encoding_ term,
          Terminal.options =
             "png" :
             catMaybes (
@@ -87,5 +98,6 @@
                (fmap formatFontSize $ fontSize_ term) :
                []),
          Terminal.commands =
-            ["set output " ++ (quote $ filename_ term)]
+            ["set output " ++ (quote $ filename_ term)],
+         Terminal.interactive = False
       }
diff --git a/src/Graphics/Gnuplot/Terminal/PostScript.hs b/src/Graphics/Gnuplot/Terminal/PostScript.hs
--- a/src/Graphics/Gnuplot/Terminal/PostScript.hs
+++ b/src/Graphics/Gnuplot/Terminal/PostScript.hs
@@ -1,30 +1,47 @@
 module Graphics.Gnuplot.Terminal.PostScript (
    T, cons,
+   encoding,
    landscape, portrait, eps,
    color, monochrome,
+   font, embedFont,
    ) where
 
-import qualified Graphics.Gnuplot.Terminal as Terminal
-import Data.Maybe (catMaybes, )
-import Graphics.Gnuplot.Utility (quote, )
+import qualified Graphics.Gnuplot.Private.Terminal as Terminal
+import qualified Graphics.Gnuplot.Private.Encoding as Encoding
+import Graphics.Gnuplot.Utility (listFromMaybeWith, quote, )
+import Data.Foldable (foldMap, )
 
 
 data T =
    Cons {
       filename_ :: FilePath,
+      encoding_ :: Maybe Encoding.T,
       mode_ :: Maybe Mode,
-      color_ :: Maybe Bool
+      color_ :: Maybe Bool,
+      embedFont_ :: [FilePath],
+      font_ :: Maybe (String, Int)
    }
 
 cons :: FilePath -> T
 cons path =
    Cons {
       filename_ = path,
+      encoding_ = Nothing,
       mode_ = Nothing,
-      color_ = Nothing
+      color_ = Nothing,
+      embedFont_ = [],
+      font_ = Nothing
    }
 
 
+{- |
+Setting the encoding to anything different
+from 'Graphics.Gnuplot.Encoding.locale'
+makes only sense if you write your gnuplot files manually using this encoding.
+-}
+encoding :: Encoding.T -> T -> T
+encoding enc term = term{encoding_ = Just enc}
+
 landscape :: T -> T
 landscape = setMode Landscape
 
@@ -43,7 +60,20 @@
 monochrome term =
    term{color_ = Just False}
 
+font :: String -> Int -> T -> T
+font fontName fontSize term =
+   term{font_ = Just (fontName, fontSize)}
 
+{- |
+Embed a font file in the generated PostScript output.
+Each call adds a new font file,
+there is no way to remove it again.
+-}
+embedFont :: FilePath -> T -> T
+embedFont fontFile term =
+   term{embedFont_ = fontFile : embedFont_ term}
+
+
 -- private functions
 
 data Mode =
@@ -65,12 +95,15 @@
 instance Terminal.C T where
    canonical term =
       Terminal.Cons {
+         Terminal.precommands = Encoding.formatMaybe $ encoding_ term,
          Terminal.options =
             "postscript" :
-            catMaybes (
-               (fmap formatMode $ mode_ term) :
-               (fmap (\b -> if b then "color" else "monochrome") $ color_ term) :
-               []),
+            (listFromMaybeWith formatMode $ mode_ term) ++
+            (listFromMaybeWith (\b -> if b then "color" else "monochrome") $ color_ term) ++
+            (concatMap (\path -> "fontfile" : quote path : []) $ embedFont_ term) ++
+            (foldMap (\(name,size) -> "font" : quote name : show size : []) $ font_ term) ++
+            [],
          Terminal.commands =
-            ["set output " ++ (quote $ filename_ term)]
+            ["set output " ++ (quote $ filename_ term)],
+         Terminal.interactive = False
       }
diff --git a/src/Graphics/Gnuplot/Terminal/QT.hs b/src/Graphics/Gnuplot/Terminal/QT.hs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/Gnuplot/Terminal/QT.hs
@@ -0,0 +1,53 @@
+{- |
+Terminal using QT.
+Derived from wxt.
+-}
+module Graphics.Gnuplot.Terminal.QT (
+   T, cons,
+   title, noTitle,
+   persist, noPersist,
+   ) where
+
+import qualified Graphics.Gnuplot.Private.Terminal as Terminal
+import Data.Maybe (catMaybes, )
+import Graphics.Gnuplot.Utility (quote, formatBool, )
+
+
+data T =
+   Cons {
+      title_ :: Maybe String,
+      persist_ :: Maybe Bool
+   }
+
+cons :: T
+cons =
+   Cons {
+      title_ = Nothing,
+      persist_ = Nothing
+   }
+
+
+title :: String -> T -> T
+title text term = term{title_ = Just text}
+
+noTitle :: T -> T
+noTitle term = term{title_ = Nothing}
+
+persist, noPersist :: T -> T
+persist   term = term{persist_ = Just True}
+noPersist term = term{persist_ = Just False}
+
+
+instance Terminal.C T where
+   canonical term =
+      Terminal.Cons {
+         Terminal.precommands = [],
+         Terminal.options =
+            "qt" :
+            catMaybes (
+               (fmap quote $ title_ term) :
+               (fmap (formatBool "persist") $ persist_ term) :
+               []),
+         Terminal.commands = [],
+         Terminal.interactive = True
+      }
diff --git a/src/Graphics/Gnuplot/Terminal/SVG.hs b/src/Graphics/Gnuplot/Terminal/SVG.hs
--- a/src/Graphics/Gnuplot/Terminal/SVG.hs
+++ b/src/Graphics/Gnuplot/Terminal/SVG.hs
@@ -1,22 +1,33 @@
 module Graphics.Gnuplot.Terminal.SVG (
    T, cons,
+   encoding,
    ) where
 
-import qualified Graphics.Gnuplot.Terminal as Terminal
+import qualified Graphics.Gnuplot.Private.Terminal as Terminal
+import qualified Graphics.Gnuplot.Private.Encoding as Encoding
 import Graphics.Gnuplot.Utility (quote, )
 
 
 data T =
    Cons {
-      filename_ :: FilePath
+      filename_ :: FilePath,
+      encoding_ :: Maybe Encoding.T
    }
 
 cons :: FilePath -> T
 cons path =
    Cons {
-      filename_ = path
+      filename_ = path,
+      encoding_ = Nothing
    }
 
+{- |
+Setting the encoding to anything different
+from 'Graphics.Gnuplot.Encoding.locale'
+makes only sense if you write your gnuplot files manually using this encoding.
+-}
+encoding :: Encoding.T -> T -> T
+encoding enc term = term{encoding_ = Just enc}
 
 
 -- private functions
@@ -24,9 +35,11 @@
 instance Terminal.C T where
    canonical term =
       Terminal.Cons {
+         Terminal.precommands = Encoding.formatMaybe $ encoding_ term,
          Terminal.options =
             "svg" :
             [],
          Terminal.commands =
-            ["set output " ++ (quote $ filename_ term)]
+            ["set output " ++ (quote $ filename_ term)],
+         Terminal.interactive = False
       }
diff --git a/src/Graphics/Gnuplot/Terminal/WXT.hs b/src/Graphics/Gnuplot/Terminal/WXT.hs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/Gnuplot/Terminal/WXT.hs
@@ -0,0 +1,53 @@
+{- |
+Terminal using wxwidgets.
+Derived from X11.
+-}
+module Graphics.Gnuplot.Terminal.WXT (
+   T, cons,
+   title, noTitle,
+   persist, noPersist,
+   ) where
+
+import qualified Graphics.Gnuplot.Private.Terminal as Terminal
+import Data.Maybe (catMaybes, )
+import Graphics.Gnuplot.Utility (quote, formatBool, )
+
+
+data T =
+   Cons {
+      title_ :: Maybe String,
+      persist_ :: Maybe Bool
+   }
+
+cons :: T
+cons =
+   Cons {
+      title_ = Nothing,
+      persist_ = Nothing
+   }
+
+
+title :: String -> T -> T
+title text term = term{title_ = Just text}
+
+noTitle :: T -> T
+noTitle term = term{title_ = Nothing}
+
+persist, noPersist :: T -> T
+persist   term = term{persist_ = Just True}
+noPersist term = term{persist_ = Just False}
+
+
+instance Terminal.C T where
+   canonical term =
+      Terminal.Cons {
+         Terminal.precommands = [],
+         Terminal.options =
+            "wxt" :
+            catMaybes (
+               (fmap quote $ title_ term) :
+               (fmap (formatBool "persist") $ persist_ term) :
+               []),
+         Terminal.commands = [],
+         Terminal.interactive = True
+      }
diff --git a/src/Graphics/Gnuplot/Terminal/X11.hs b/src/Graphics/Gnuplot/Terminal/X11.hs
--- a/src/Graphics/Gnuplot/Terminal/X11.hs
+++ b/src/Graphics/Gnuplot/Terminal/X11.hs
@@ -4,10 +4,9 @@
    persist, noPersist,
    ) where
 
-import qualified Graphics.Gnuplot.Terminal as Terminal
-import Graphics.Gnuplot.Terminal (formatBool, )
+import qualified Graphics.Gnuplot.Private.Terminal as Terminal
 import Data.Maybe (catMaybes, )
-import Graphics.Gnuplot.Utility (quote, )
+import Graphics.Gnuplot.Utility (quote, formatBool, )
 
 
 data T =
@@ -38,12 +37,13 @@
 instance Terminal.C T where
    canonical term =
       Terminal.Cons {
+         Terminal.precommands = [],
          Terminal.options =
             "x11" :
             catMaybes (
                (fmap quote $ title_ term) :
                (fmap (formatBool "persist") $ persist_ term) :
                []),
-         Terminal.commands =
-            []
+         Terminal.commands = [],
+         Terminal.interactive = True
       }
diff --git a/src/Graphics/Gnuplot/Time.hs b/src/Graphics/Gnuplot/Time.hs
--- a/src/Graphics/Gnuplot/Time.hs
+++ b/src/Graphics/Gnuplot/Time.hs
@@ -1,7 +1,6 @@
 module Graphics.Gnuplot.Time where
 
-import System.Locale (defaultTimeLocale, )
-import Data.Time.Format (FormatTime, formatTime, )
+import Data.Time.Format (FormatTime, formatTime, defaultTimeLocale, )
 import Data.Tuple.HT (mapFst, )
 
 {- |
diff --git a/src/Graphics/Gnuplot/Utility.hs b/src/Graphics/Gnuplot/Utility.hs
--- a/src/Graphics/Gnuplot/Utility.hs
+++ b/src/Graphics/Gnuplot/Utility.hs
@@ -1,9 +1,12 @@
 module Graphics.Gnuplot.Utility where
 
+import Text.Printf (printf, )
+
+import qualified Data.Char as Char
 import Data.List (intersperse, )
 
 
-functionToGraph :: [a] -> (a -> a) -> [(a,a)]
+functionToGraph :: [x] -> (x -> y) -> [(x,y)]
 functionToGraph args f = map (\x -> (x, f x)) args
 -- functionToGraph args f = map swap $ attachKey f args
 
@@ -22,5 +25,40 @@
 semiColonConcat = concat . intersperse "; "
 
 
-quote :: String -> String
-quote = show
+{-
+In former versions this was simply 'show'.
+However, Haskell formats non-ASCII characters with decimal backslash sequences
+whereas gnuplot expects octal ones.
+gnuplot does also not accept bigger octal numbers.
+The current version writes non-ASCII printable characters
+with the system default encoding.
+-}
+quote, _quote :: String -> String
+quote str = '"' : foldr (++) "\"" (map escapeChar str)
+_quote str = '"' : concatMap escapeChar str ++ "\""
+
+escapeChar :: Char -> String
+escapeChar c =
+   case c of
+      '"'  -> "\\\""
+      '\\' -> "\\\\"
+      '\t' -> "\\t"
+      '\n' -> "\\n"
+      _ -> if Char.isPrint c then [c] else printf "\\%o" $ Char.ord c
+
+assembleCells :: [[ShowS]] -> String
+assembleCells ps =
+   foldr ($) ""
+      (concatMap
+         (\p ->
+            intersperse (showString ", ") p ++
+            [showString "\n"])
+         ps)
+
+
+listFromMaybeWith :: (a -> b) -> Maybe a -> [b]
+listFromMaybeWith f = maybe [] ((:[]) . f)
+
+formatBool :: String -> Bool -> String
+formatBool name b =
+   if b then name else "no"++name
diff --git a/src/Graphics/Gnuplot/Value/Atom.hs b/src/Graphics/Gnuplot/Value/Atom.hs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/Gnuplot/Value/Atom.hs
@@ -0,0 +1,54 @@
+{- |
+Provide a class that restricts the range of Haskell types
+to the ones that gnuplot can process.
+-}
+module Graphics.Gnuplot.Value.Atom (
+   OptionSet(..),
+   C(..),
+   ) where
+
+import qualified Graphics.Gnuplot.Private.FrameOption as Option
+import Graphics.Gnuplot.Utility (quote, )
+
+import qualified Data.Time as Time
+import Data.Word (Word8, Word16, Word32, Word64, )
+import Data.Int (Int8, Int16, Int32, Int64, )
+import Data.Ratio (Ratio, )
+
+
+data OptionSet a =
+   OptionSet {
+      optData :: [String],
+      optFormat :: [String],
+      optOthers :: [(Option.T, [String])]
+   }
+
+class C a where
+   options :: OptionSet a
+   options =
+      OptionSet [] [{- quote "%g" -}] []
+
+instance C Float   where
+instance C Double  where
+instance C Int     where
+instance C Integer where
+instance (Integral a) => C (Ratio a) where
+
+instance C Int8  where
+instance C Int16 where
+instance C Int32 where
+instance C Int64 where
+instance C Word8  where
+instance C Word16 where
+instance C Word32 where
+instance C Word64 where
+
+
+timeOptions :: OptionSet time
+timeOptions =
+   OptionSet ["time"] [quote "%d/%m"] [(Option.timeFmt, [quote "%s"])]
+
+instance C Time.Day where
+   options = timeOptions
+instance C Time.UTCTime where
+   options = timeOptions
diff --git a/src/Graphics/Gnuplot/Value/ColumnSet.hs b/src/Graphics/Gnuplot/Value/ColumnSet.hs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/Gnuplot/Value/ColumnSet.hs
@@ -0,0 +1,38 @@
+{- |
+We provide a way to specify a set of columns
+that matches the tuple structure of a certain graph type.
+-}
+module Graphics.Gnuplot.Value.ColumnSet
+   (T(Cons), atom, pair, triple, quadruple,
+   ) where
+
+import qualified Graphics.Gnuplot.Value.Atom  as Atom
+
+
+newtype T a = Cons [Int]
+
+{-
+Functor and Applicative instances would be useful
+for combining column sets,
+but they are dangerous, because they can bring
+type and column number out of sync.
+
+instance Functor Column where
+   fmap _ (Cons n) = Cons n
+
+instance Applicative Column where
+   pure _ = Cons []
+   Cons ns <*> Cons ms = Cons (ns++ms)
+-}
+
+atom :: Atom.C a => Int -> T a
+atom i = Cons [i]
+
+pair :: T a -> T b -> T (a,b)
+pair (Cons ai) (Cons bi) = Cons (ai++bi)
+
+triple :: T a -> T b -> T c -> T (a,b,c)
+triple (Cons ai) (Cons bi) (Cons ci) = Cons (ai++bi++ci)
+
+quadruple :: T a -> T b -> T c -> T d -> T (a,b,c,d)
+quadruple (Cons ai) (Cons bi) (Cons ci) (Cons di) = Cons (ai++bi++ci++di)
diff --git a/src/Graphics/Gnuplot/Value/Tuple.hs b/src/Graphics/Gnuplot/Value/Tuple.hs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/Gnuplot/Value/Tuple.hs
@@ -0,0 +1,118 @@
+{- |
+Provide a class that renders multiple Haskell values in a text form
+that is accessible by gnuplot.
+
+Maybe we add a method for the binary interface to gnuplot later.
+-}
+module Graphics.Gnuplot.Value.Tuple (
+   C(text, columnCount),
+   ColumnCount(ColumnCount),
+   Label(Label),
+   ) where
+
+import Graphics.Gnuplot.Utility (quote)
+
+import Data.Time.Format (defaultTimeLocale, )
+import qualified Data.Time as Time
+
+import Data.Word (Word8, Word16, Word32, Word64, )
+import Data.Int (Int8, Int16, Int32, Int64, )
+import Data.Ratio (Ratio, )
+
+import Data.Function (id, ($), (.), )
+import Text.Show (Show, ShowS, shows, showString, )
+import Prelude
+         (Eq, Ord, String, Int, Integer, Integral, Float, Double,
+          realToFrac, (+), (++), )
+
+
+class C a where
+   {- |
+   For values that are also in Atom class,
+   'text' must generate a singleton list.
+   -}
+   text :: a -> [ShowS]
+
+   {- |
+   It must hold @ColumnCount (length (text x)) == columnCount@.
+   -}
+   columnCount :: ColumnCount a
+   columnCount = ColumnCount 1
+
+{- |
+Count numbers of gnuplot data columns for the respective type.
+
+Somehow a writer monad with respect to Sum monoid
+without material monadic result.
+
+Cf. ColumnSet module.
+-}
+newtype ColumnCount a = ColumnCount Int
+   deriving (Eq, Ord, Show)
+
+{-
+Functor and Applicative instances would be useful
+for combining column sets,
+but they are dangerous, because they can bring
+type and column columnCount out of sync.
+-}
+
+pure :: a -> ColumnCount a
+pure _ = ColumnCount 0
+
+(<*>) :: ColumnCount (a -> b) -> ColumnCount a -> ColumnCount b
+ColumnCount n <*> ColumnCount m = ColumnCount (n+m)
+
+
+singleton :: a -> [a]
+singleton = (:[])
+
+
+instance C Float   where text = singleton . shows
+instance C Double  where text = singleton . shows
+instance C Int     where text = singleton . shows
+instance C Integer where text = singleton . shows
+instance (Integral a) => C (Ratio a) where
+   text = singleton . shows . (id :: Double->Double) . realToFrac
+
+instance C Int8  where text = singleton . shows
+instance C Int16 where text = singleton . shows
+instance C Int32 where text = singleton . shows
+instance C Int64 where text = singleton . shows
+instance C Word8  where text = singleton . shows
+instance C Word16 where text = singleton . shows
+instance C Word32 where text = singleton . shows
+instance C Word64 where text = singleton . shows
+
+instance C Time.Day where
+   text d = text $ Time.UTCTime d 0
+instance C Time.UTCTime where
+   text = singleton . showString . Time.formatTime defaultTimeLocale "%s"
+
+newtype Label = Label String
+instance C Label where text (Label str) = singleton $ showString $ quote str
+
+
+instance (C a, C b) => C (a,b) where
+   text (a,b) = text a ++ text b
+   columnCount =
+      pure (,)
+         <*> columnCount
+         <*> columnCount
+
+instance (C a, C b, C c) => C (a,b,c) where
+   text (a,b,c) = text a ++ text b ++ text c
+   columnCount =
+      pure (,,)
+         <*> columnCount
+         <*> columnCount
+         <*> columnCount
+
+instance (C a, C b, C c, C d) => C (a,b,c,d) where
+   text (a,b,c,d) = text a ++ text b ++ text c ++ text d
+   columnCount =
+      pure (,,,)
+         <*> columnCount
+         <*> columnCount
+         <*> columnCount
+         <*> columnCount
