packages feed

matplotlib 0.3.0 → 0.4.0

raw patch · 4 files changed

+545/−186 lines, 4 filesdep +tasty-expected-failuredep +tasty-goldenPVP ok

version bump matches the API change (PVP)

Dependencies added: tasty-expected-failure, tasty-golden

API changes (from Hackage documentation)

- Graphics.Matplotlib: maximum2 :: (Ord (t a), Ord a, Foldable t1, Foldable t) => t1 (t a) -> a
- Graphics.Matplotlib: minimum2 :: (Ord (t a), Ord a, Foldable t1, Foldable t) => t1 (t a) -> a
+ Graphics.Matplotlib: axes :: Matplotlib
+ Graphics.Matplotlib: axisXTicksPosition :: MplotValue val => val -> Matplotlib
+ Graphics.Matplotlib: axisYTickLabels :: MplotValue val => val -> Matplotlib
+ Graphics.Matplotlib: axisYTickSpacing :: (MplotValue val1, MplotValue val) => val1 -> val -> Matplotlib
+ Graphics.Matplotlib: axisYTicksPosition :: MplotValue val => val -> Matplotlib
+ Graphics.Matplotlib: figText :: (MplotValue val1, MplotValue val) => val1 -> val -> String -> Matplotlib
+ Graphics.Matplotlib: file :: [Char] -> Matplotlib -> IO (Either String String)
+ Graphics.Matplotlib: lit :: String -> L
+ Graphics.Matplotlib: mapLinear :: (Double -> b) -> Double -> Double -> Double -> [b]
+ Graphics.Matplotlib: raw :: String -> R
+ Graphics.Matplotlib: setAspect :: Matplotlib
+ Graphics.Matplotlib: setAx :: Matplotlib
+ Graphics.Matplotlib: setParameter :: MplotValue val => String -> val -> Matplotlib
+ Graphics.Matplotlib: setSizeInches :: (MplotValue val1, MplotValue val) => val1 -> val -> Matplotlib
+ Graphics.Matplotlib: spine :: MplotValue val => val -> Matplotlib
+ Graphics.Matplotlib: spineSetBounds :: (MplotValue val1, MplotValue val) => val1 -> val -> Matplotlib
+ Graphics.Matplotlib: spineSetPosition :: (MplotValue val1, MplotValue val) => val1 -> val -> Matplotlib
+ Graphics.Matplotlib: spineSetVisible :: MplotValue val => val -> Matplotlib
+ Graphics.Matplotlib: str :: String -> S
+ Graphics.Matplotlib: tightLayout :: Matplotlib
+ Graphics.Matplotlib: updateAxes :: Matplotlib
+ Graphics.Matplotlib: updateFigure :: Matplotlib
+ Graphics.Matplotlib: violinplot :: ToJSON a => a -> Matplotlib
+ Graphics.Matplotlib: xkcd :: Matplotlib
+ Graphics.Matplotlib: xtickLabels :: MplotValue val => val -> Matplotlib
+ Graphics.Matplotlib: xticks :: MplotValue val => val -> Matplotlib
+ Graphics.Matplotlib: ytickLabels :: MplotValue val => val -> Matplotlib
+ Graphics.Matplotlib: yticks :: MplotValue val => val -> Matplotlib
+ Graphics.Matplotlib: ztickLabels :: MplotValue val => val -> Matplotlib
+ Graphics.Matplotlib: zticks :: MplotValue val => val -> Matplotlib
+ Graphics.Matplotlib.Internal: L :: String -> L
+ Graphics.Matplotlib.Internal: R :: String -> R
+ Graphics.Matplotlib.Internal: S :: String -> S
+ Graphics.Matplotlib.Internal: data L
+ Graphics.Matplotlib.Internal: data R
+ Graphics.Matplotlib.Internal: data S
+ Graphics.Matplotlib.Internal: instance GHC.Classes.Eq Graphics.Matplotlib.Internal.L
+ Graphics.Matplotlib.Internal: instance GHC.Classes.Eq Graphics.Matplotlib.Internal.R
+ Graphics.Matplotlib.Internal: instance GHC.Classes.Eq Graphics.Matplotlib.Internal.S
+ Graphics.Matplotlib.Internal: instance GHC.Classes.Ord Graphics.Matplotlib.Internal.L
+ Graphics.Matplotlib.Internal: instance GHC.Classes.Ord Graphics.Matplotlib.Internal.R
+ Graphics.Matplotlib.Internal: instance GHC.Classes.Ord Graphics.Matplotlib.Internal.S
+ Graphics.Matplotlib.Internal: instance GHC.Show.Show Graphics.Matplotlib.Internal.L
+ Graphics.Matplotlib.Internal: instance GHC.Show.Show Graphics.Matplotlib.Internal.R
+ Graphics.Matplotlib.Internal: instance GHC.Show.Show Graphics.Matplotlib.Internal.S
+ Graphics.Matplotlib.Internal: instance Graphics.Matplotlib.Internal.MplotValue Graphics.Matplotlib.Internal.L
+ Graphics.Matplotlib.Internal: instance Graphics.Matplotlib.Internal.MplotValue Graphics.Matplotlib.Internal.R
+ Graphics.Matplotlib.Internal: instance Graphics.Matplotlib.Internal.MplotValue Graphics.Matplotlib.Internal.S
+ Graphics.Matplotlib.Internal: instance Graphics.Matplotlib.Internal.MplotValue [GHC.Integer.Type.Integer]
+ Graphics.Matplotlib.Internal: instance Graphics.Matplotlib.Internal.MplotValue [GHC.Types.Double]
+ Graphics.Matplotlib.Internal: instance Graphics.Matplotlib.Internal.MplotValue [GHC.Types.Int]
+ Graphics.Matplotlib.Internal: instance Graphics.Matplotlib.Internal.MplotValue [Graphics.Matplotlib.Internal.L]
+ Graphics.Matplotlib.Internal: instance Graphics.Matplotlib.Internal.MplotValue [Graphics.Matplotlib.Internal.R]
+ Graphics.Matplotlib.Internal: instance Graphics.Matplotlib.Internal.MplotValue [Graphics.Matplotlib.Internal.S]
+ Graphics.Matplotlib.Internal: instance Graphics.Matplotlib.Internal.MplotValue x => Graphics.Matplotlib.Internal.MplotValue (GHC.Base.Maybe x)
+ Graphics.Matplotlib.Internal: lit :: String -> L
+ Graphics.Matplotlib.Internal: maximum2 :: (Ord (t a), Ord a, Foldable t1, Foldable t) => t1 (t a) -> a
+ Graphics.Matplotlib.Internal: minimum2 :: (Ord (t a), Ord a, Foldable t1, Foldable t) => t1 (t a) -> a
+ Graphics.Matplotlib.Internal: pyBackend :: [Char] -> [Char]
+ Graphics.Matplotlib.Internal: raw :: String -> R
+ Graphics.Matplotlib.Internal: str :: String -> S
+ Graphics.Matplotlib.Internal: toPythonOpt :: MplotValue val => val -> String
+ Graphics.Matplotlib.Internal: updateAxes :: Matplotlib
+ Graphics.Matplotlib.Internal: updateFigure :: Matplotlib
- Graphics.Matplotlib: errorbar :: (ToJSON t, ToJSON t1, ToJSON t2) => t2 -> t1 -> t -> Matplotlib
+ Graphics.Matplotlib: errorbar :: (ToJSON t, ToJSON t1, ToJSON t2, ToJSON t3) => t3 -> t2 -> t1 -> t -> Matplotlib
- Graphics.Matplotlib: figure :: [Char] -> Matplotlib -> IO (Either String String)
+ Graphics.Matplotlib: figure :: MplotValue val => val -> Matplotlib
- Graphics.Matplotlib: o1 :: String -> Option
+ Graphics.Matplotlib: o1 :: MplotValue val => val -> Option
- Graphics.Matplotlib: o2 :: String -> String -> Option
+ Graphics.Matplotlib: o2 :: MplotValue val => String -> val -> Option
- Graphics.Matplotlib: text :: (MplotValue val2, MplotValue val1, MplotValue val) => val2 -> val1 -> val -> Matplotlib
+ Graphics.Matplotlib: text :: (MplotValue val1, MplotValue val) => val1 -> val -> String -> Matplotlib
- Graphics.Matplotlib: title :: MplotValue val => val -> Matplotlib
+ Graphics.Matplotlib: title :: String -> Matplotlib
- Graphics.Matplotlib: xLabel :: MplotValue val => val -> Matplotlib
+ Graphics.Matplotlib: xLabel :: String -> Matplotlib
- Graphics.Matplotlib: yLabel :: MplotValue val => val -> Matplotlib
+ Graphics.Matplotlib: yLabel :: String -> Matplotlib
- Graphics.Matplotlib: zLabel :: MplotValue val => val -> Matplotlib
+ Graphics.Matplotlib: zLabel :: String -> Matplotlib
- Graphics.Matplotlib.Internal: class MplotValue val
+ Graphics.Matplotlib.Internal: class MplotValue val where toPythonOpt = toPython
- Graphics.Matplotlib.Internal: o1 :: String -> Option
+ Graphics.Matplotlib.Internal: o1 :: MplotValue val => val -> Option
- Graphics.Matplotlib.Internal: o2 :: String -> String -> Option
+ Graphics.Matplotlib.Internal: o2 :: MplotValue val => String -> val -> Option
- Graphics.Matplotlib.Internal: pyIncludes :: [[Char]]
+ Graphics.Matplotlib.Internal: pyIncludes :: String -> [[Char]]

Files

matplotlib.cabal view
@@ -1,5 +1,5 @@ name:                matplotlib-version:             0.3.0+version:             0.4.0 synopsis:            Bindings to Matplotlib; a Python plotting library description:     Matplotlib is probably the most full featured plotting library out there.@@ -40,6 +40,10 @@                      , matplotlib                      , tasty                      , tasty-hunit+                     , tasty-expected-failure+                     , tasty-golden+                     , bytestring+                     , process                      , temporary                      , random                      , raw-strings-qq
src/Graphics/Matplotlib.hs view
@@ -24,8 +24,8 @@ -- -- @ --   readData (x, y)---   % mp # "p = plot.plot(data[" # a # "], data[" # b # "]" ## ")"---   % mp # "plot.xlabel('" # label # "')"+--   % mp \# "p = plot.plot(data[" \# a \# "], data[" \# b \# "]" ## ")"+--   % mp \# "plot.xlabel(" \# str label \# ")" -- @ -- -- Where important functions are:@@ -38,21 +38,33 @@ -- -- You can call this plot with ----- > plot [1,2,3,4,5,6] [1,3,2,5,2] @@ [o1 "'go-'", o2 "linewidth" "2"]+-- > plot [1,2,3,4,5,6] [1,3,2,5,2] @@ [o1 "go-", o2 "linewidth" 2] -- -- where '@@' applies an options list replacing the last '##' -----  [@'o1'@] A single positional option---  [@'o2'@] A keyword option+--  [@'o1'@] A single positional option. The value is rendered into python as+--  the appropriate datatype. Strings become python strings, bools become bools,+--  etc. If you want to insert code verbatim into an option use 'lit'. If you+--  want to have a raw string with no escapes use 'raw'.+--  [@'o2'@] A keyword option. The key is awlays a string, the value is treated+--  the same way that the option in 'o1' is treated. -- -- Right now there's no easy way to bind to an option other than the last one -- unless you want to pass options in as parameters.+--+-- The generated Python code should follow some invariants. It must maintain the+-- current figure in "fig", all available axes in "axes", and the current axis+-- in "ax". Plotting commands should use the current axis, never the plot+-- itself; the two APIs are almost identical. When creating low-level bindings+-- one must remember to call "plot.sci" to set the current image when plotting a+-- graph. The current spine of the axes that's being manipulated is in "spine". -----------------------------------------------------------------------------  module Graphics.Matplotlib   ( module Graphics.Matplotlib     -- * Creating custom plots and applying options-  , Matplotlib(), Option(),(@@), (%), o1, o2, (##), (#), mp, def, readData)+  , Matplotlib(), Option(),(@@), (%), o1, o2, (##), (#), mp, def, readData+  , str, raw, lit, updateAxes, updateFigure, mapLinear) where import Data.List import Data.Aeson@@ -62,15 +74,15 @@  -- | Show a plot, blocks until the figure is closed onscreen :: Matplotlib -> IO (Either String String)-onscreen m = withMplot m (\str -> python $ pyIncludes ++ str ++ pyDetach ++ pyOnscreen)+onscreen m = withMplot m (\s -> python $ pyIncludes "" ++ s ++ pyDetach ++ pyOnscreen)  -- | Print the python code that would be executed code :: Matplotlib -> IO String-code m = withMplot m (\str -> return $ unlines $ pyIncludes ++ str ++ pyDetach ++ pyOnscreen)+code m = withMplot m (\s -> return $ unlines $ pyIncludes (pyBackend "agg") ++ s ++ pyDetach ++ pyOnscreen)  -- | Save to a file-figure :: [Char] -> Matplotlib -> IO (Either String String)-figure filename m = withMplot m (\str -> python $ pyIncludes ++ str ++ pyFigure filename)+file :: [Char] -> Matplotlib -> IO (Either String String)+file filename m = withMplot m (\s -> python $ pyIncludes (pyBackend "agg") ++ s ++ pyFigure filename)  -- * Useful plots @@ -80,11 +92,11 @@   % addSubplot 2 1 1   % xcorr xs ys @@ opts   % grid True-  % axhline 0 @@ [o1 "0", o2 "color" "'black'", o2 "lw" "2"]-  % addSubplot 2 1 2 @@ [o2 "sharex" "ax"]+  % axhline 0 @@ [o1 0, o2 "color" "black", o2 "lw" 2]+  % addSubplot 2 1 2 @@ [o2 "sharex" $ lit "ax"]   % acorr xs @@ opts   % grid True-  % axhline 0 @@ [o2 "color" "'black'", o2 "lw" "2"]+  % axhline 0 @@ [o2 "color" "black", o2 "lw" 2]  -- | Plot a histogram for the given values with 'bins' histogram :: (MplotValue val, ToJSON t) => t -> val -> Matplotlib@@ -92,28 +104,35 @@  -- | Plot a 2D histogram for the given values with 'bins' histogram2D x y = readData [x,y] %-  mp # "plot.hist2d(data[0], data[1]" ## ")"+  mp # "plot.sci(ax.hist2d(data[0], data[1]" ## ")[-1])"  -- | Plot the given values as a scatter plot scatter :: (ToJSON t1, ToJSON t) => t1 -> t -> Matplotlib-scatter x y = plot x y `def` [o1 "'.'"]+scatter x y = readData (x, y)+  % mp # "plot.sci(ax.scatter(data[0], data[1]" ## "))"  -- | Plot a line line :: (ToJSON t1, ToJSON t) => t1 -> t -> Matplotlib-line x y = plot x y `def` [o1 "'-'"]+line x y = plot x y `def` [o1 "-"]  -- | Like 'plot' but takes an error bar value per point-errorbar xs ys errs = readData (xs, ys, errs)-  % mp # "ax.errorbar(data[0], data[1], yerr=data[2]" ## ")"+-- errorbar :: (ToJSON x, ToJSON y, ToJSON xs, ToJSON ys) => x -> y -> Maybe xs -> Maybe ys -> Matplotlib+errorbar xs ys xerrs yerrs = readData (xs, ys, xerrs, yerrs)+  % mp # "ax.errorbar(data[0], data[1], xerr=data[2], yerr=data[3]" ## ")"  -- | Plot a line given a function that will be executed for each element of -- given list. The list provides the x values, the function the y values. lineF :: (ToJSON a, ToJSON b) => (a -> b) -> [a] -> Matplotlib-lineF f l = plot l (map f l) `def` [o1 "'-'"]+lineF f l = plot l (map f l) `def` [o1 "-"] -boxplot l = readData l+-- | Create a box plot for the given data+boxplot d = readData d   % mp # "ax.boxplot(data" ## ")" +-- | Create a violin plot for the given data+violinplot d = readData d+  % mp # "ax.violinplot(data" ## ")"+ -- | Given a grid of x and y values and a number of steps call the given -- function and plot the 3D contour contourF :: (ToJSON val, MplotValue val, Ord val) => (Double -> Double -> val) -> Double -> Double -> Double -> Double -> Double -> Matplotlib@@ -150,12 +169,12 @@ -- | Plot a matrix matShow :: ToJSON a => a -> Matplotlib matShow d = readData d-            % (mp # "plot.matshow(data" ## ")")+            % (mp # "plot.sci(ax.matshow(data" ## "))")  -- | Plot a matrix pcolor :: ToJSON a => a -> Matplotlib pcolor d = readData d-            % (mp # "plot.pcolor(np.array(data)" ## ")")+            % (mp # "plot.sci(ax.pcolor(np.array(data)" ## "))")  -- | Plot a KDE of the given functions; a good bandwith will be chosen automatically density :: [Double] -> Maybe (Double, Double) -> Matplotlib@@ -167,27 +186,27 @@  -- * Matplotlib configuration +-- | Set an rcParams key-value+setParameter k v = mp # "matplotlib.rcParams["# str k #"] = " # v++-- | Enable or disable TeX setTeX :: Bool -> Matplotlib setTeX b = mp # "matplotlib.rcParams['text.usetex'] = " # b +-- | Enable or disable unicode setUnicode :: Bool -> Matplotlib setUnicode b = mp # "matplotlib.rcParams['text.latex.unicode'] = " # b - -- * Basic plotting commands  -- | Plot the 'a' and 'b' entries of the data object dataPlot :: (MplotValue val, MplotValue val1) => val1 -> val -> Matplotlib-dataPlot a b = mp # "p = plot.plot(data[" # a # "], data[" # b # "]" ## ")"+dataPlot a b = mp # "p = ax.plot(data[" # a # "], data[" # b # "]" ## ")"  -- | Plot the Haskell objects 'x' and 'y' as a line plot :: (ToJSON t, ToJSON t1) => t1 -> t -> Matplotlib plot x y = readData (x, y) % dataPlot 0 1 --- | Show/hide grid lines-grid :: Bool -> Matplotlib-grid t = mp # "plot.gca().grid(" # t # ")"- -- | Plot x against y where x is a date. --   xunit is something like 'weeks', yearStart, monthStart, dayStart are an offset to x. -- TODO This isn't general enough; it's missing some settings about the format. The call is also a mess.@@ -198,30 +217,18 @@   % dataPlot 0 1 `def` [o1 "-"]   % mp # "ax.xaxis.set_major_formatter(DateFormatter('%B'))"   % mp # "ax.xaxis.set_minor_locator(WeekdayLocator(byweekday=6))"-  --- | Add a label to the x axis-xLabel :: MplotValue val => val -> Matplotlib-xLabel label = mp # "plot.xlabel(r'" # label # "'" ## ")" --- | Add a label to the y axis-yLabel :: MplotValue val => val -> Matplotlib-yLabel label = mp # "plot.ylabel(r'" # label # "'" ## ")"---- | Add a label to the z axis-zLabel :: MplotValue val => val -> Matplotlib-zLabel label = mp # "plot.zlabel(r'" # label # "'" ## ")"- -- | Create a histogram for the 'a' entry of the data array dataHistogram :: (MplotValue val1, MplotValue val) => val1 -> val -> Matplotlib-dataHistogram a bins = mp # "plot.hist(data[" # a # "]," # bins ## ")"+dataHistogram a bins = mp # "ax.hist(data[" # a # "]," # bins ## ")"  -- | Create a scatter plot accessing the given fields of the data array dataScatter :: (MplotValue val1, MplotValue val) => val1 -> val -> Matplotlib-dataScatter a b = dataPlot a b `def` [o1 "'.'"]+dataScatter a b = dataPlot a b `def` [o1 "."]  -- | Create a line accessing the given entires of the data array dataLine :: (MplotValue val1, MplotValue val) => val1 -> val -> Matplotlib-dataLine a b = dataPlot a b `def` [o1 "'-'"]+dataLine a b = dataPlot a b `def` [o1 "-"]  -- | Create a 3D contour contour xs ys zs =@@ -238,10 +245,6 @@   % contourRaw 0 1 2 (maximum2 xs) (maximum2 ys) (minimum2 zs)   % axis3DLabels xs ys zs --- | Enable 3D projection-axis3DProjection :: Matplotlib-axis3DProjection = mp # "ax = plot.gca(projection='3d')"- -- | Plot a 3D wireframe accessing the given elements of the data array wireframe :: (MplotValue val2, MplotValue val1, MplotValue val) => val2 -> val1 -> val -> Matplotlib wireframe a b c = mp # "ax.plot_wireframe(np.array(data[" # a # "]), np.array(data[" # b # "]), np.array(data[" # c # "]), rstride=1, cstride=1)"@@ -259,34 +262,11 @@   % mp # "ax.contour(data[" # a # "], data[" # b # "], data[" # c # "], zdir='x', offset=-" # maxA # ")"   % mp # "ax.contour(data[" # a # "], data[" # b # "], data[" # c # "], zdir='y', offset=" # maxB #")" --- | Smallest element of a list of lists-minimum2 :: (Ord (t a), Ord a, Foldable t1, Foldable t) => t1 (t a) -> a-minimum2 l = minimum $ minimum l--- | Largest element of a list of lists-maximum2 :: (Ord (t a), Ord a, Foldable t1, Foldable t) => t1 (t a) -> a-maximum2 l = maximum $ maximum l---- | Label and set limits of a set of 3D axis--- TODO This is a mess, does both more and less than it claims.-axis3DLabels xs ys zs =-  mp # "ax.set_xlabel('X')"-  % mp # "ax.set_xlim3d(" # minimum2 xs # ", " # maximum2 xs # ")"-  % mp # "ax.set_ylabel('Y')"-  % mp # "ax.set_ylim3d(" # minimum2 ys # ", " # maximum2 ys # ")"-  % mp # "ax.set_zlabel('Z')"-  % mp # "ax.set_zlim3d(" # minimum2 zs # ", " # maximum2 zs # ")"- -- | Draw a bag graph in a subplot -- TODO Why do we need this? subplotDataBar a width offset opts =   mp # "ax.bar(np.arange(len(data[" # a # "]))+" # offset # ", data[" # a # "], " # width ## ")" @@ opts --- | Create a subplot with the coordinates (r,c,f)-addSubplot r c f = mp # "ax = plot.gcf().add_subplot(" # r # c # f ## ")"---- | Access a subplot with the coordinates (r,c,f)-getSubplot r c f = mp # "ax = plot.subplot(" # r # "," # c # "," # f ## ")"- -- | The default bar with barDefaultWidth nr = 1.0 / (fromIntegral nr + 1) @@ -304,90 +284,186 @@   % (let width = barDefaultWidth (length valuesList) in        foldl1 (%) (zipWith3 (\_ opts i -> subplotDataBar i width (width * i) opts) valuesList optsList [0..])) --- | Add a title-title :: MplotValue val => val -> Matplotlib-title s = mp # "plot.title(r'" # s # "'" ## ")"---- | Set the spacing of ticks on the x axis-axisXTickSpacing :: (MplotValue val1, MplotValue val) => val1 -> val -> Matplotlib-axisXTickSpacing nr width = mp # "ax.set_xticks(np.arange(" # nr # ")+" # width ## ")"---- | Set the labels on the x axis-axisXTickLabels :: MplotValue val => val -> Matplotlib-axisXTickLabels labels = mp # "ax.set_xticklabels( (" # labels # ") " ## " )"- -- | Update the data array to linearly interpolate between array entries interpolate :: (MplotValue val, MplotValue val2, MplotValue val1) => val2 -> val1 -> val -> Matplotlib interpolate a b n =   (mp # "data[" # b # "] = mlab.stineman_interp(np.linspace(data[" # a # "][0],data[" # a # "][-1]," # n # "),data[" # a # "],data[" # b # "],None)")   % (mp # "data[" # a # "] = np.linspace(data[" # a # "][0],data[" # a # "][-1]," # n # ")") +-- | Plot a KDE of the given functions with an optional start/end and a bandwidth h+densityBandwidth :: [Double] -> Double -> Maybe (Double, Double) -> Matplotlib+densityBandwidth l h maybeStartEnd =+  plotMapLinear f (case maybeStartEnd of+                    Nothing -> minimum l+                    (Just (start, _)) -> start)+                  (case maybeStartEnd of+                    Nothing -> maximum l+                    (Just (_, end)) -> end)+                   100+  where f x = sum (map (\xi -> gaussianPdf x xi h) l) / ((fromIntegral $ length l) * h)+        gaussianPdf x mu sigma = exp (- sqr (x - mu) / (2 * sigma)) / sqrt (2 * pi * sigma)+        sqr x = x * x++-- | Plot cross-correlation+xcorr x y = readData (x, y) % mp # "ax.xcorr(data[0], data[1]" ## ")"++-- | Plot auto-correlation+acorr x = readData x % mp # "ax.acorr(data" ## ")"++-- | Plot text at a specified location+text x y s = mp # "ax.text(" # x # "," # y # "," # raw s ## ")"++figText x y s = mp # "plot.figtext(" # x # "," # y # "," # raw s ## ")"++-- * Layout, axes, and legends+ -- | Square up the aspect ratio of a plot.+setAspect :: Matplotlib+setAspect = mp # "ax.set_aspect(" ## ")"++-- | Square up the aspect ratio of a plot. squareAxes :: Matplotlib-squareAxes = mp # "plot.axes().set_aspect('equal')"+squareAxes = mp # "ax.set_aspect('equal')"  -- | Set the rotation of the labels on the x axis to the given number of degrees roateAxesLabels :: MplotValue val => val -> Matplotlib-roateAxesLabels degrees = mp # "labels = plot.axes().get_xticklabels()"+roateAxesLabels degrees = mp # "labels = ax.get_xticklabels()"    % mp # "for label in labels:"    % mp # "    label.set_rotation("#degrees#")"  -- | Set the x labels to be vertical verticalAxes :: Matplotlib-verticalAxes = mp # "labels = plot.axes().get_xticklabels()"+verticalAxes = mp # "labels = ax.get_xticklabels()"    % mp # "for label in labels:"    % mp # "    label.set_rotation('vertical')"  -- | Set the x scale to be logarithmic logX :: Matplotlib-logX = mp # "plot.axes().set_xscale('log')"+logX = mp # "ax.set_xscale('log')"  -- | Set the y scale to be logarithmic logY :: Matplotlib-logY = mp # "plot.axes().set_yscale('log')"+logY = mp # "ax.set_yscale('log')"  -- | Set limits on the x axis xlim :: (MplotValue val1, MplotValue val) => val1 -> val -> Matplotlib-xlim l u = mp # "plot.xlim([" # l # "," # u # "])"+xlim l u = mp # "ax.set_xlim(" # l # "," # u # ")"  -- | Set limits on the y axis ylim :: (MplotValue val1, MplotValue val) => val1 -> val -> Matplotlib-ylim l u = mp # "plot.ylim([" # l # "," # u # "])"---- | Plot a KDE of the given functions with an optional start/end and a bandwidth h-densityBandwidth :: [Double] -> Double -> Maybe (Double, Double) -> Matplotlib-densityBandwidth l h maybeStartEnd =-  plotMapLinear f (case maybeStartEnd of-                    Nothing -> minimum l-                    (Just (start, _)) -> start)-                  (case maybeStartEnd of-                    Nothing -> maximum l-                    (Just (_, end)) -> end)-                   100-  where f x = sum (map (\xi -> gaussianPdf x xi h) l) / ((fromIntegral $ length l) * h)-        gaussianPdf x mu sigma = exp (- sqr (x - mu) / (2 * sigma)) / sqrt (2 * pi * sigma)-        sqr x = x * x+ylim l u = mp # "ax.set_ylim(" # l # "," # u # ")"  -- | Add a horizontal line across the axis axhline y = mp # "ax.axhline(" # y ## ")" --- | Plot cross-correlation-xcorr x y = readData (x, y) % mp # "ax.xcorr(data[0], data[1]" ## ")"---- | Plot auto-correlation-acorr x = readData x % mp # "ax.acorr(data" ## ")"---- | Plot text at a specified location-text x y str = mp # "ax.text(" # x # "," # y # "," # "'" # str # "'" ## ")"- -- | Insert a legend-legend = mp # "plot.legend(" ## ")"+legend = mp # "ax.legend(" ## ")"  -- | Insert a color bar+-- TODO This refers to the plot and not an axis. Might cause trouble with subplots colorbar = mp # "plot.colorbar(" ## ")" +-- | Add a title+title :: String -> Matplotlib+title s = mp # "ax.set_title(" # raw s ## ")"++-- | Show/hide grid lines+grid :: Bool -> Matplotlib+grid t = mp # "ax.grid(" # t # ")"++-- | Enable 3D projection+axis3DProjection :: Matplotlib+axis3DProjection = mp # "ax = plot.gca(projection='3d')"++-- | Label and set limits of a set of 3D axis+-- TODO This is a mess, does both more and less than it claims.+axis3DLabels xs ys zs =+  mp # "ax.set_xlabel('X')"+  % mp # "ax.set_xlim3d(" # minimum2 xs # ", " # maximum2 xs # ")"+  % mp # "ax.set_ylabel('Y')"+  % mp # "ax.set_ylim3d(" # minimum2 ys # ", " # maximum2 ys # ")"+  % mp # "ax.set_zlabel('Z')"+  % mp # "ax.set_zlim3d(" # minimum2 zs # ", " # maximum2 zs # ")"++-- | Add a label to the x axis+xLabel :: String -> Matplotlib+xLabel label = mp # "ax.set_xlabel(" # raw label ## ")"++-- | Add a label to the y axis+yLabel :: String -> Matplotlib+yLabel label = mp # "ax.set_ylabel(" # raw label ## ")"++-- | Add a label to the z axis+zLabel :: String -> Matplotlib+zLabel label = mp # "ax.set_zlabel(" # raw label ## ")"++setSizeInches w h = mp # "fig.set_size_inches(" # w # "," # h # ", forward=True)"++tightLayout = mp # "fig.tight_layout()"++xkcd = mp # "plot.xkcd()"++-- * Ticks++xticks l = mp # "ax.set_xticks(" # l # ")"+yticks l = mp # "ax.set_yticks(" # l # ")"+zticks l = mp # "ax.set_zticks(" # l # ")"++xtickLabels l = mp # "ax.set_xticklabels(" # l # ")"+ytickLabels l = mp # "ax.set_yticklabels(" # l # ")"+ztickLabels l = mp # "ax.set_zticklabels(" # l # ")"++-- | Set the spacing of ticks on the x axis+axisXTickSpacing :: (MplotValue val1, MplotValue val) => val1 -> val -> Matplotlib+axisXTickSpacing nr width = mp # "ax.set_xticks(np.arange(" # nr # ")+" # width ## ")"++-- | Set the labels on the x axis+axisXTickLabels :: MplotValue val => val -> Matplotlib+axisXTickLabels labels = mp # "ax.set_xticklabels( (" # labels # ") " ## " )"++-- | Set the spacing of ticks on the y axis+axisYTickSpacing :: (MplotValue val1, MplotValue val) => val1 -> val -> Matplotlib+axisYTickSpacing nr width = mp # "ax.set_yticks(np.arange(" # nr # ")+" # width ## ")"++-- | Set the labels on the y axis+axisYTickLabels :: MplotValue val => val -> Matplotlib+axisYTickLabels labels = mp # "ax.set_yticklabels( (" # labels # ") " ## " )"++axisXTicksPosition p = mp # "ax.xaxis.set_ticks_position('" # p # "')"+axisYTicksPosition p = mp # "ax.yaxis.set_ticks_position('" # p # "')"++-- * Spines++spine s = mp # "spine = ax.spines['" # s # "']"++spineSetBounds l h = mp # "spine.set_bounds(" # l # "," # h # ")"++spineSetVisible b = mp # "spine.set_visible(" # b # ")"++spineSetPosition s n = mp # "spine.set_position((" # s # "," # n # "))"++-- * Subplots++setAx = mp # "plot.sca(ax) "++-- | Create a subplot with the coordinates (r,c,f)+addSubplot r c f = mp # "ax = plot.gcf().add_subplot(" # r # c # f ## ")" % updateAxes % setAx++-- | Access a subplot with the coordinates (r,c,f)+getSubplot r c f = mp # "ax = plot.subplot(" # r # "," # c # "," # f ## ")" % updateAxes % setAx+ -- | Creates subplots and stores them in an internal variable subplots = mp # "fig, axes = plot.subplots(" ## ")"+  % mp # "axes = np.asarray(axes)"+  % mp # "axes = axes.flatten()"+  % updateAxes % setAx  -- | Access a subplot-setSubplot s = mp # "ax = axes[" # s # "]"+setSubplot s = mp # "ax = axes[" # s # "]" % setAx++-- | Add axes to a figure+axes = mp # "ax = plot.axes(" ## ")" % updateAxes % setAx++-- | Creates a new figure with the given id. If the Id is already in use it+-- switches to that figure.+figure id = mp # "plot.figure(" # id ## ")" % updateFigure
src/Graphics/Matplotlib/Internal.hs view
@@ -104,29 +104,89 @@           (Just f) -> m { mpPendingOption = Just (\o -> Exec $ es (f o) ++ toPython v)}       | otherwise = m { mpRest = S.adjust (\(Exec s) -> Exec $ s ++ toPython v) (S.length (mpRest m) - 1) (mpRest m) } +-- | A string to be rendered in python as a string. In other words it is+-- rendered as 'str'.+data S = S String+  deriving (Show, Eq, Ord)++-- | A string to be rendered in python as a raw string. In other words it is+-- rendered as r'str'.+data R = R String+  deriving (Show, Eq, Ord)++-- | A string to be rendered in python as a raw literal/code. In other words it is+-- inserted directly as is into the code.+data L = L String+  deriving (Show, Eq, Ord)+ -- | Values which can be combined together to form a matplotlib command. These -- specify how values are rendered in Python code. class MplotValue val where+  -- | Render a value inline in Python code   toPython :: val -> String+  -- | Render a value as an optional parameter in Python code+  toPythonOpt :: val -> String+  toPythonOpt = toPython +instance MplotValue S where+  toPython (S s) = "'" ++ s ++ "'"+instance MplotValue R where+  toPython (R s) = "r'" ++ s ++ "'"+instance MplotValue L where+  toPython (L s) = s instance MplotValue String where+  -- | A string is just a literal when used in code   toPython s = s+  -- | A string is a real quoted python string when used as an option+  toPythonOpt s = toPythonOpt $ S s instance MplotValue [String] where   toPython [] = ""   toPython (x:xs) = toPython x ++ "," ++ toPython xs+  -- | A list of strings is a list of python strings, not literals+  toPythonOpt s = "[" ++ f s ++ "]"+    where f [] = ""+          f (x:xs) = toPythonOpt (str x) ++ "," ++ f xs instance MplotValue Double where   toPython s = show s+instance MplotValue [Double] where+  toPython s = "[" ++ f s ++ "]"+    where f [] = ""+          f (x:xs) = toPython x ++ "," ++ f xs instance MplotValue Integer where   toPython s = show s+instance MplotValue [Integer] where+  toPython s = "[" ++ f s ++ "]"+    where f [] = ""+          f (x:xs) = toPython x ++ "," ++ f xs instance MplotValue Int where   toPython s = show s+instance MplotValue [Int] where+  toPython s = "[" ++ f s ++ "]"+    where f [] = ""+          f (x:xs) = toPython x ++ "," ++ f xs+instance MplotValue [R] where+  toPython s = "[" ++ f s ++ "]"+    where f [] = ""+          f (x:xs) = toPython x ++ "," ++ f xs+instance MplotValue [S] where+  toPython s = "[" ++ f s ++ "]"+    where f [] = ""+          f (x:xs) = toPython x ++ "," ++ f xs+instance MplotValue [L] where+  toPython s = "[" ++ f s ++ "]"+    where f [] = ""+          f (x:xs) = toPython x ++ "," ++ f xs instance MplotValue Bool where   toPython s = show s instance (MplotValue x) => MplotValue (x, x) where-  toPython (n, v) = toPython n ++ " = " ++ toPython v+  toPython (k, v) = "(" ++ toPython k ++ ", " ++ toPython v ++ ")" instance (MplotValue (x, y)) => MplotValue [(x, y)] where-  toPython [] = ""-  toPython (x:xs) = toPython x ++ ", " ++ toPython xs+  toPython s = "[" ++ f s ++ "]"+    where f [] = ""+          f (x:xs) = toPython x ++ "," ++ f xs+instance MplotValue x => MplotValue (Maybe x) where+  toPython Nothing  = "None"+  toPython (Just x) = toPython x  default (Integer, Int, Double) @@ -165,8 +225,8 @@ renderOptions :: [Option] -> [Char] renderOptions [] = "" renderOptions xs = f xs-  where  f (P a:l) = "," ++ toPython a ++ f l-         f (K a b:l) = "," ++ toPython a ++  "=" ++ toPython b ++ f l+  where  f (P a:l) = "," ++ a ++ f l+         f (K a b:l) = "," ++ a ++  "=" ++ b ++ f l          f [] = ""  -- | An internal helper that modifies the options of a plot.@@ -215,27 +275,30 @@              Right <$> readProcess "/usr/bin/python3" [codeFile] ""))          (\e -> return $ Left $ show (e :: IOException)) +pyBackend backend = "matplotlib.use('" ++ backend ++ "')"+ -- | The standard python includes of every plot-pyIncludes :: [[Char]]-pyIncludes = ["import matplotlib"-             -- TODO Provide a way to set the render backend-             -- ,"matplotlib.use('GtkAgg')"-             ,"import matplotlib.path as mpath"-             ,"import matplotlib.patches as mpatches"-             ,"import matplotlib.pyplot as plot"-             ,"import matplotlib.mlab as mlab"-             ,"import matplotlib.colors as mcolors"-             ,"import matplotlib.collections as mcollections"-             ,"from matplotlib import cm"-             ,"from mpl_toolkits.mplot3d import axes3d"-             ,"import numpy as np"-             ,"import os"-             ,"import sys"-             ,"import json"-             ,"import random, datetime"-             ,"from matplotlib.dates import DateFormatter, WeekdayLocator"-             ,"ax = plot.figure().gca()"-             ,"axes = [plot.figure().gca()]"]+pyIncludes :: String -> [[Char]]+pyIncludes backend = ["import matplotlib"+                     ,backend+                     ,"import matplotlib.path as mpath"+                     ,"import matplotlib.patches as mpatches"+                     ,"import matplotlib.pyplot as plot"+                     ,"import matplotlib.mlab as mlab"+                     ,"import matplotlib.colors as mcolors"+                     ,"import matplotlib.collections as mcollections"+                     ,"import matplotlib.ticker as mticker"+                     ,"from matplotlib import cm"+                     ,"from mpl_toolkits.mplot3d import axes3d"+                     ,"import numpy as np"+                     ,"import os"+                     ,"import sys"+                     ,"import json"+                     ,"import random, datetime"+                     ,"from matplotlib.dates import DateFormatter, WeekdayLocator"+                     ,"fig = plot.gcf()"+                     ,"axes = [plot.gca()]"+                     ,"ax = axes[0]"]  -- | The python command that reads external data into the python data array pyReadData :: [Char] -> [[Char]]@@ -257,7 +320,33 @@ pyFigure output = ["plot.savefig('" ++ output ++ "')"]  -- | Create a positional option-o1 x = P x+o1 x = P $ toPythonOpt x  -- | Create a keyword option-o2 x y = K x y+o2 x = K x . toPythonOpt++-- | Create a string that will be rendered as a python string+str = S++-- | Create a string that will be rendered as a raw python string+raw = R++-- | Create a literal that will inserted into the python code directly+lit = L++-- | Update axes. Should be called any time the state is changed.+updateAxes = mp # "axes = plot.gcf().get_axes()"++-- | Update the figure and the axes. Should be called any time the state is changed.+updateFigure = mp # "fig = plot.gcf()"+  % mp # "axes = plot.gcf().get_axes()"+  % mp # "ax = axes[0] if len(axes) > 0 else None"++-- | Smallest element of a list of lists+minimum2 :: (Ord (t a), Ord a, Foldable t1, Foldable t) => t1 (t a) -> a+minimum2 l = minimum $ minimum l++-- | Largest element of a list of lists+maximum2 :: (Ord (t a), Ord a, Foldable t1, Foldable t) => t1 (t a) -> a+maximum2 l = maximum $ maximum l+
test/Spec.hs view
@@ -1,7 +1,9 @@-{-# language ExtendedDefaultRules, ScopedTypeVariables, QuasiQuotes #-}+{-# language ExtendedDefaultRules, ScopedTypeVariables, QuasiQuotes, ParallelListComp #-}  import Test.Tasty+import Test.Tasty.Runners import Test.Tasty.HUnit+import Test.Tasty.ExpectedFailure import System.IO.Unsafe import Graphics.Matplotlib import System.IO.Temp@@ -9,11 +11,17 @@ import Text.RawString.QQ import Data.List import Data.List.Split+import Control.Monad+import Test.Tasty.Golden.Advanced+import qualified Data.ByteString as BS+import System.Process+import System.IO  -- * Random values for testing  uniforms :: (Random a, Num a) => [a] uniforms = randoms (mkStdGen 42)+ uniforms' lo hi = randomRs (lo,hi) (mkStdGen 42)  -- * Not so random values to enable some fully-reproducible tests@@ -87,54 +95,111 @@  -- * Tests -main = defaultMain tests+main = defaultMain $ tests "All tests" testPlot -tests :: TestTree-tests = testGroup "Tests" [unitTests]+main' = defaultMain $ tests "Golden tests" testPlotGolden +main'' = defaultMain $ testGroup "All tests" [tests "Execution tests" testPlot+                                             , toneDownTests "Unreliable across machines" $ tests "Golden tests" testPlotGolden]++tests name f = testGroup name   [basicTests f,+                                 toneDownTests "Can fail with old matplotlib" $ fragileTests f,+                                 ignoreTest $ failingTests f]++toneDownTests reason tests = wrapTest (liftM (\x -> x { resultOutcome = Success+                                                     , resultShortDescription =+                                                       case resultOutcome x of+                                                         Success -> resultShortDescription x+                                                         _ -> reason ++ ": " ++ resultShortDescription x+                                                     })) tests++testPlotGolden name fn =+         unsafePerformIO $ tmp (\filename ->+                                 return $ goldenTest+                                   name+                                   (BS.readFile ref)+                                   (file filename fn >> BS.readFile filename)+                                   (\g n ->+                                       tmp (\gfile ->+                                               tmp (\nfile -> do+                                                       BS.writeFile gfile g+                                                       BS.writeFile nfile n+                                                       (code, stdout, stderr) <-+                                                         readProcessWithExitCode "/usr/bin/compare" ["-metric"+                                                                                                    ,"PSNR"+                                                                                                    ,gfile+                                                                                                    ,nfile+                                                                                                    ,"null"] ""+                                                       case (stderr, reads stderr) of+                                                         ("inf", _) -> return Nothing+                                                         (_, [(x :: Double, _)]) ->+                                                           if x < 35 then+                                                             return $ Just $ "Images very different; PSNR too low " ++ show x else+                                                             return Nothing)))+                                   (BS.writeFile ref))+  where ref = "imgs/" ++ name ++ ".png"+        tmp f = withSystemTempFile "a.png" (\filename h -> hClose h >> f filename)+ -- | Test one plot; right now we just test that the command executed without -- errors. We should visually compare plots somehow. testPlot name fn = testCase name $ tryit fn @?= Right ""-  where tryit fn = unsafePerformIO $ withSystemTempFile "a.png" (\file _ -> figure file fn)+  where tryit fn = unsafePerformIO $ withSystemTempFile "a.png" (\filename _ -> file filename fn)  -- | This generates examples from the test cases testPlot' name fn = testCase name $ tryit fn name @?= Right ""   where tryit fn name = unsafePerformIO $ do           c <- code fn           print c-          figure ("/tmp/imgs/" ++ name ++ ".png") fn+          file ("/tmp/imgs/" ++ name ++ ".png") fn -unitTests = testGroup "Unit tests"-  [ testPlot "histogram" m1-  , testPlot "cumulative" m2-  , testPlot "scatter" m3-  , testPlot "contour" m4-  , testPlot "labelled-histogram" m5-  -- TODO This test case is broken-  -- , testPlot "sub-bars" m6-  , testPlot "density-bandwidth" m7-  , testPlot "density" m8-  , testPlot "line-function" m9-  , testPlot "quadratic" m10-  , testPlot "projections" m11-  , testPlot "line-options" m12-  , testPlot "corr" mxcorr-  , testPlot "tex" mtex-  , testPlot "show-matrix" mmat-  , testPlot "legend" mlegend-  , testPlot "hist2DLog" mhist2DLog-  , testPlot "eventplot" meventplot-  , testPlot "errorbar" merrorbar-  , testPlot "boxplot" mboxplot+basicTests f = testGroup "Basic tests"+  [ f "histogram" m1+  , f "cumulative" m2+  , f "scatter" m3+  , f "contour" m4+  , f "labelled-histogram" m5+  , f "density-bandwidth" m7+  , f "density" m8+  , f "line-function" m9+  , f "quadratic" m10+  , f "projections" m11+  , f "line-options" m12+  , f "corr" mxcorr+  , f "show-matrix" mmat+  , f "legend" mlegend+  , f "hist2DLog" mhist2DLog+  , f "eventplot" meventplot+  , f "errorbar" merrorbar+  , f "scatterhist" mscatterHist+  , f "histMulti" mhistMulti+  , f "spines" mspines+  , f "hists" mhists+  , f "hinton" mhinton+  , f "integral" mintegral   ] +fragileTests f = testGroup "Fragile tests"+  [ -- TODO Fails on circle ci (with latex)+    f "tex" mtex+    -- TODO Fails on circle ci (labels is not valid; matplotlib too old)+  , f "boxplot" mboxplot+    -- TODO Fails on circle ci (no violin plots; matplotlib too old)+  , f "violinplot" mviolinplot+  ]++failingTests f = testGroup "Failing tests"+  [+    -- TODO This test case is broken+    f "sub-bars" m6+  ]+ -- * These tests are fully-reproducible, the output must be identical every time  m1 :: Matplotlib m1 = histogram xs 8  m2 :: Matplotlib-m2 = histogram xs 8 @@ [o2 "cumulative" "True"]+m2 = histogram xs 8 @@ [o2 "cumulative" True]  m3 = scatter xs ys @@ -161,16 +226,16 @@  m9 = lineF (\x -> x**2) [0,0.01..1] -m10 = plotMapLinear (\x -> x**2) (-2) 2 100 @@ [o1 "'.'"] % title "Quadratic function"+m10 = plotMapLinear (\x -> x**2) (-2) 2 100 @@ [o1 "."] % title "Quadratic function"  m11 = projectionsF (\a b -> cos (degreesRadians a) + sin (degreesRadians b)) (-100) 100 (-200) 200 10 -m12 = plot [1,2,3,4,5,6] [1,3,2,5,2,4] @@ [o1 "'go-'", o2 "linewidth" "2"]+m12 = plot [1,2,3,4,5,6] [1,3,2,5,2,4] @@ [o1 "go-", o2 "linewidth" 2]  -- * These tests can be random and may not be exactly the same every time  -- | http://matplotlib.org/examples/pylab_examples/xcorr_demo.html-mxcorr = xacorr xs ys [o2 "usevlines" "True", o2 "maxlags" "50", o2 "normed" "True", o2 "lw" "2"]+mxcorr = xacorr xs ys [o2 "usevlines" True, o2 "maxlags" 50, o2 "normed" True, o2 "lw" 2]   where (xs :: [Double]) = take 100 normals         (ys :: [Double]) = take 100 normals @@ -179,19 +244,20 @@   % setTeX True   % setUnicode True   % xLabel [r|\textbf{time (s)}|]-  % yLabel [r|\textit{Velocity (\u00B0/sec)}|] @@ [o2 "fontsize" "16"]-  % title [r|\TeX\ is Number $\displaystyle\sum_{n=1}^\infty\frac{-e^{i\pi}}{2^n}$!"|] @@ [o2 "fontsize" "16", o2 "color" "'r'"]+  % yLabel [r|\textit{Velocity (\u00B0/sec)}|] @@ [o2 "fontsize" 16]+  % title [r|\TeX\ is Number $\displaystyle\sum_{n=1}^\infty\frac{-e^{i\pi}}{2^n}$!"|] @@ [o2 "fontsize" 16, o2 "color" "r"]   % grid True -mmat = pcolor (take 10 $ chunksOf 8 uniforms) @@ [o2 "edgecolors" "'k'", o2 "linewidth" "1"]+mmat = pcolor (take 10 $ chunksOf 8 uniforms) @@ [o2 "edgecolors" "k", o2 "linewidth" 1]  -- | http://matplotlib.org/examples/pylab_examples/legend_demo3.html-mlegend = plotMapLinear (\x -> x ** 2) 0 1 100 @@ [o2 "label" "'x^2'"]-  % plotMapLinear (\x -> x ** 3) 0 1 100 @@ [o2 "label" "'x^3'"]-  % legend @@ [o2 "fancybox" "True", o2 "shadow" "True", o2 "title" "'Legend'", o2 "loc" "'upper left'"]+mlegend = plotMapLinear (\x -> x ** 2) 0 1 100 @@ [o2 "label" "x^2"]+  % plotMapLinear (\x -> x ** 3) 0 1 100 @@ [o2 "label" "x^3"]+  % legend @@ [o2 "fancybox" True, o2 "shadow" True, o2 "title" "Legend", o2 "loc" "upper left"]  -- | http://matplotlib.org/examples/pylab_examples/hist2d_log_demo.html-mhist2DLog = histogram2D x y @@ [o2 "bins" "40", o2 "norm" "mcolors.LogNorm()"]+mhist2DLog = histogram2D x y @@ [o2 "bins" 40, o2 "norm" $ lit "mcolors.LogNorm()"]+  % setAx   % colorbar   where (x:y:_) = chunksOf 10000 normals @@ -202,14 +268,138 @@   where xs = sort $ take 10 uniforms         ys = map (\x -> x ** 2) xs -merrorbar = errorbar xs ys errs @@ [o2 "errorevery" "2"]+merrorbar = errorbar xs ys (Nothing :: Maybe [Double]) (Just errs) @@ [o2 "errorevery" 2]   where xs = [0.1,0.2..4]         ys = map (\x -> exp $ -x) xs-        errs = map (\x -> 0.1 + 0.1 * sqrt x) xs+        errs = [map (\x -> 0.1 + 0.1 * sqrt x) xs, map (\x -> 0.1 + 0.1 * sqrt x) ys] -mboxplot = subplots @@ [o2 "ncols" "2", o2 "sharey" "True"]+mboxplot = subplots @@ [o2 "ncols" 2, o2 "sharey" True]   % setSubplot "0"-  % boxplot (take 3 $ chunksOf 10 $ map (* 2) $ normals) @@ [o2 "labels" "['X', 'Y', 'Z']"]+  % boxplot (take 3 $ chunksOf 10 $ map (* 2) $ normals) @@ [o2 "labels" ["X", "Y", "Z"]]   % setSubplot "1"-  % boxplot (take 3 $ chunksOf 10 $ map (* 2) $ normals) @@ [o2 "labels" "['A', 'B', 'C']", o2 "showbox" "False", o2 "showcaps" "False"]+  % boxplot (take 3 $ chunksOf 10 $ map (* 2) $ normals) @@ [o2 "labels" ["A", "B", "C"], o2 "showbox" False, o2 "showcaps" False] +mviolinplot = subplots @@ [o2 "ncols" 2, o2 "sharey" True]+  % setSubplot "0"+  % violinplot (take 3 $ chunksOf 100 $ map (* 2) $ normals)+  % setSubplot "1"+  % violinplot (take 3 $ chunksOf 100 $ map (* 2) $ normals) @@ [o2 "showmeans" True, o2 "showmedians" True, o2 "vert" False]++-- | http://matplotlib.org/examples/pylab_examples/scatter_hist.html+mscatterHist = figure 0+  % setSizeInches 8 8+  -- The scatter plot+  % axes @@ [o1 ([left, bottom', width, height] :: [Double])]+  % scatter  x y+  % xlim (-lim) lim+  % ylim (-lim) lim+  -- The histogram on the right (x)+  % axes @@ [o1 [left, bottom_h, width, 0.2]]+  % mp # "ax.xaxis.set_major_formatter(mticker.NullFormatter())"+  % histogram x bins+  % xlim (-lim) lim+  -- The histogram on top (y)+  % axes @@ [o1 [left_h, bottom', 0.2, height]]+  % mp # "ax.yaxis.set_major_formatter(mticker.NullFormatter())"+  % histogram y bins @@ [o2 "orientation" "horizontal"]+  % ylim (-lim) lim+  where left = 0.1+        width = 0.65+        bottom' = 0.1+        height = 0.65+        bottom_h = left + width + 0.02+        left_h = left + width + 0.02+        [x, y] = take 2 $ chunksOf 1000 $ map (* 2) $ normals+        binwidth = 0.25+        xymax = maximum [maximum $ map abs x, maximum $ map abs y]+        lim = ((fromIntegral $ round $ xymax / binwidth) + 1) * binwidth+        bins = [-lim,-lim+binwidth..(lim + binwidth)]++mhistMulti = subplots @@ [o2 "nrows" 2, o2 "ncols" 2]+  % setSubplot 0+  % histogram x nrBins @@ [o2 "normed" 1, o2 "histtype" "bar", o2 "color" ["red", "tan", "lime"], o2 "label" ["red", "tan", "lime"]]+  % legend @@ [o2 "prop" $ lit "{'size': 10}"]+  % title "bars with legend"+  % setSubplot 1+  % histogram x nrBins @@ [o2 "normed" 1, o2 "histtype" "bar", o2 "stacked" True]+  % title "stacked bar"+  % setSubplot 2+  % histogram x nrBins @@ [o2 "histtype" "step", o2 "stacked" True, o2 "fill" False]+  % title "stacked bar"+  % setSubplot 3+  % histogram (map (\x -> take x normals) [2000, 5000, 10000]) nrBins @@ [o2 "histtype" "bar"]+  % title "different sample sizes"+  % tightLayout+  where nrBins = 10+        x = take 3 $ chunksOf 1000 $ normals++mspines = plot x y @@ [o1 "k--"]+  % plot x y' @@ [o1 "ro"]+  % xlim 0 (2 * pi)+  % xticks [0 :: Double, pi, 2*pi]+  % xtickLabels (map raw ["0", "$\\pi$", "2$\\pi$"])+  % ylim (-1.5) 1.5+  % yticks [-1 :: Double, 0, 1]+  % spine "left"+  % spineSetBounds (-1) 1+  % spine "right"+  % spineSetVisible False+  % spine "top"+  % spineSetVisible False+  % axisYTicksPosition "left"+  % axisXTicksPosition "bottom"+  where x  = mapLinear (\x -> x) 0 (2 * pi) 50+        y  = map sin x+        y' = zipWith (\a b -> a + 0.1*b) y normals++mhists = h 10 1.5+       % h 4 1+       % h 15 2+       % h 6 0.5+  where ns mu var = map (\x -> mu + x * var) $ take 1000 normals+        h mu var = histogram (ns mu var) 25 @@ [o2 "histtype" "stepfilled"+                                             ,o2 "alpha" 0.8+                                             ,o2 "normed" True]++mhinton = mp # "ax.patch.set_facecolor('gray')"+  % setAspect @@ [o1 "equal", o1 "box"]+  % mp # "ax.xaxis.set_major_locator(plot.NullLocator())"+  % mp # "ax.yaxis.set_major_locator(plot.NullLocator())"+  % foldl (\a (x,y,w) -> a % f x y w) mp m+  % mp # "ax.autoscale_view()"+  % mp # "ax.invert_yaxis()"+  where m = [ (x,y,w) | x <- [0..19], y <- [0..19] | w <- (map (\x -> x - 0.5) normals) ]+        maxWeight = maximum $ map (\(_,_,v) -> abs v) m+        f x y w = mp # "ax.add_patch(plot.Rectangle("+                     # "[" # (x - size / 2) # "," # (y - size / 2) # "]"+                     # ", " # size # ", " # size+                     # ", facecolor='" # color # "', edgecolor='" # color # "'))"+          where color = if w > 0 then "white" else "black"+                size  = sqrt $ abs w / maxWeight++mintegral = subplots+  % plot x y @@ [o1 "r", o2 "linewidth" 2]+  % ylim 0 (maximum y)+  % mp # "ax.add_patch(plot.Polygon(" # ([(a, 0)] ++ zip ix iy ++ [(b,0)]) ## "))"+    @@ [o2 "facecolor" "0.9", o2 "edgecolor" "0.5"]+  % text (0.5 * (a + b)) 30 [r|$\int_a^b f(x)\mathrm{d}x$|]+    @@ [o2 "horizontalalignment" "center", o2 "fontsize" 20]+  % figText 0.9 0.05 "$x$"+  % figText 0.1 0.9  "$y$"+  % spine "right"+  % spineSetVisible False+  % spine "top"+  % spineSetVisible False+  % axisXTicksPosition "bottom"+  % xticks (a, b)+  % xtickLabels (raw "$a$", raw "$b$")+  % yticks ([] :: [Double])+  where func x = (x - 3) * (x - 5) * (x - 7) + 85+        -- integral limits+        a = 2 :: Double+        b = 9 :: Double+        (x :: [Double]) = mapLinear (\x -> x) 0 10 100+        y = map func x+        -- shaded region+        (ix :: [Double]) = mapLinear (\x -> x) a b 100+        iy = map func ix