packages feed

pandoc-pyplot 2.1.4.0 → 2.1.5.0

raw patch · 8 files changed

+154/−82 lines, 8 filessetup-changedPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

+ Text.Pandoc.Filter.Pyplot: [isTightBbox] :: Configuration -> Bool
+ Text.Pandoc.Filter.Pyplot: [isTransparent] :: Configuration -> Bool
+ Text.Pandoc.Filter.Pyplot.Internal: [isTightBbox] :: Configuration -> Bool
+ Text.Pandoc.Filter.Pyplot.Internal: [isTransparent] :: Configuration -> Bool
+ Text.Pandoc.Filter.Pyplot.Internal: [tightBbox] :: FigureSpec -> Bool
+ Text.Pandoc.Filter.Pyplot.Internal: [transparent] :: FigureSpec -> Bool
+ Text.Pandoc.Filter.Pyplot.Internal: isTightBboxKey :: String
+ Text.Pandoc.Filter.Pyplot.Internal: isTransparentKey :: String
- Text.Pandoc.Filter.Pyplot: Configuration :: FilePath -> PythonScript -> Bool -> SaveFormat -> Int -> String -> [String] -> Configuration
+ Text.Pandoc.Filter.Pyplot: Configuration :: FilePath -> PythonScript -> Bool -> SaveFormat -> Int -> Bool -> Bool -> String -> [String] -> Configuration
- Text.Pandoc.Filter.Pyplot.Internal: Configuration :: FilePath -> PythonScript -> Bool -> SaveFormat -> Int -> String -> [String] -> Configuration
+ Text.Pandoc.Filter.Pyplot.Internal: Configuration :: FilePath -> PythonScript -> Bool -> SaveFormat -> Int -> Bool -> Bool -> String -> [String] -> Configuration
- Text.Pandoc.Filter.Pyplot.Internal: FigureSpec :: String -> Bool -> PythonScript -> SaveFormat -> FilePath -> Int -> Attr -> FigureSpec
+ Text.Pandoc.Filter.Pyplot.Internal: FigureSpec :: String -> Bool -> PythonScript -> SaveFormat -> FilePath -> Int -> Bool -> Bool -> Attr -> FigureSpec

Files

CHANGELOG.md view
@@ -2,6 +2,11 @@ 
 pandoc-pyplot uses [Semantic Versioning](http://semver.org/spec/v2.0.0.html)
 
+Release 2.1.5.0
+---------------
+
+* Added support for two new configuration values: `tight_bbox: true|false` and `transparent: true|false`. These values are only supported via configuration files `.pandoc-pyplot.yml`.
+
 Release 2.1.4.0
 ---------------
 
README.md view
@@ -6,13 +6,24 @@ `pandoc-pyplot` turns Python code present in your documents into embedded Matplotlib figures.
 
 * [Usage](#usage)
-    * [Markdown](#Markdown)
+    * [Markdown](#markdown)
     * [LaTeX](#latex)
     * [Examples](#examples)
 * [Features](#features)
+    * [Captions](#captions)
+    * [Link to source code and high-resolution
+      figure](#link-to-source-code-and-high-resolution-figure)
+    * [Including scripts](#including-scripts)
+    * [No wasted work](#no-wasted-work)
+    * [Compatibility with
+      pandoc-crossref](#compatibility-with-pandoc-crossref)
+    * [Configurable](#configurable)
+        * [Configuration-only parameters](#configuration-only-parameters)
 * [Installation](#installation)
 * [Running the filter](#running-the-filter)
 * [Usage as a Haskell library](#usage-as-a-haskell-library)
+    * [Usage with Hakyll](#usage-with-hakyll)
+* [Warning](#warning)
 
 ## Usage
 
@@ -164,6 +175,15 @@ 
 This `include` parameter is perfect for longer documents with many plots. Simply define the style you want in a separate script! You can also import packages this way, or define functions you often use.
 
+Customization of figures beyond what is available in `pandoc-pyplot` can also be done through the `include` script. For example, if you wanted to have transparent figures, you can do so via `matplotlib.pyplot.rcParams`:
+```python
+import matplotlib.pyplot as plt
+
+plt.rcParams['savefig.transparent'] = True
+...
+```
+You can take a look at all available `matplotlib` parameters [here](https://matplotlib.org/users/customizing.html).
+
 ### No wasted work
 
 `pandoc-pyplot` minimizes work, only generating figures if it absolutely must. Therefore, you can confidently run the filter on very large documents containing dozens of figures --- like a book or a thesis --- and only the figures which have recently changed will be re-generated.
@@ -200,6 +220,8 @@ format: jpeg
 links: false
 dpi: 150
+tight_bbox: true
+transparent: false
 flags: [-O, -Wignore]
 ```
 
@@ -215,9 +237,21 @@ format: png
 links: true
 dpi: 80
+tight_bbox: false
+transparent: false
+flags: []
 ```
 
 Using `pandoc-pyplot --write-example-config` will write the default configuration to a file `.pandoc-pyplot.yml`, which you can then customize.
+
+#### Configuration-only parameters
+
+There are a few parameters that are __only__ available via the configuration file `.pandoc-pyplot.yml`: 
+
+* `interpreter` is the name of the interpreter to use. For example, `interpreter: python36`;
+* `flags` is a list of strings, which are flags that are passed to the python interpreter. For example, `flags: [-O, -Wignore]`;
+* `tight_bbox` is a boolean that determines whether to use `bbox_inches="tight"` or not when saving Matplotlib figures. For example, `tight_bbox: true`. See [here](https://matplotlib.org/api/_as_gen/matplotlib.pyplot.savefig.html) for details;
+* `transparent` is a boolean that determines whether to make figure background transparent or not. This is useful, for example, for displaying a plot on top of a colored background on a web page. For example, `transparent: true`.
 
 ## Installation
 
Setup.hs view
@@ -1,7 +1,7 @@--- This script is used to build and install your package. Typically you don't--- need to change it. The Cabal documentation has more information about this--- file: <https://www.haskell.org/cabal/users-guide/installing-packages.html>.-import qualified Distribution.Simple--main :: IO ()-main = Distribution.Simple.defaultMain+-- This script is used to build and install your package. Typically you don't
+-- need to change it. The Cabal documentation has more information about this
+-- file: <https://www.haskell.org/cabal/users-guide/installing-packages.html>.
+import qualified Distribution.Simple
+
+main :: IO ()
+main = Distribution.Simple.defaultMain
pandoc-pyplot.cabal view
@@ -1,5 +1,5 @@ name:           pandoc-pyplot
-version:        2.1.4.0
+version:        2.1.5.0
 cabal-version:  >= 1.12
 synopsis:       A Pandoc filter to include figures generated from Python code blocks
 description:    A Pandoc filter to include figures generated from Python code blocks. Keep the document and Python code in the same location. Output from Matplotlib is captured and included as a figure.
src/Text/Pandoc/Filter/Pyplot/Configuration.hs view
@@ -21,6 +21,8 @@     , includePathKey
     , saveFormatKey
     , withLinksKey
+    , isTightBboxKey
+    , isTransparentKey
 ) where
 
 import           Data.Maybe                    (fromMaybe)
@@ -34,25 +36,6 @@ 
 import Text.Pandoc.Filter.Pyplot.Types
 
--- | Keys that pandoc-pyplot will look for in code blocks. These are only exported for testing purposes.
-directoryKey, captionKey, dpiKey, includePathKey, saveFormatKey, withLinksKey :: String
-directoryKey   = "directory"
-captionKey     = "caption"
-dpiKey         = "dpi"
-includePathKey = "include"
-saveFormatKey  = "format"
-withLinksKey   = "links"
-
--- | list of all keys related to pandoc-pyplot.
-inclusionKeys :: [String]
-inclusionKeys = [ directoryKey
-                , captionKey
-                , dpiKey
-                , includePathKey
-                , saveFormatKey
-                , withLinksKey
-                ]
-
 -- A @Configuration@ cannot be directly created from a YAML file
 -- for two reasons:
 --
@@ -69,19 +52,23 @@         , defaultWithLinks_   :: Bool
         , defaultSaveFormat_  :: String
         , defaultDPI_         :: Int
+        , tightBbox_          :: Bool
+        , transparent_        :: Bool
         , interpreter_        :: String
         , flags_              :: [String]
         } 
 
 instance FromJSON ConfigPrecursor where
     parseJSON (Object v) = ConfigPrecursor
-        <$> v .:? (T.pack directoryKey)  .!= (defaultDirectory def)
+        <$> v .:? (T.pack directoryKey)     .!= (defaultDirectory def)
         <*> v .:? (T.pack includePathKey)
-        <*> v .:? (T.pack withLinksKey)  .!= (defaultWithLinks def)
-        <*> v .:? (T.pack saveFormatKey) .!= (extension $ defaultSaveFormat def)
-        <*> v .:? (T.pack dpiKey)        .!= (defaultDPI def)
-        <*> v .:? "interpreter"          .!= (interpreter def)
-        <*> v .:? "flags"                .!= (flags def)
+        <*> v .:? (T.pack withLinksKey)     .!= (defaultWithLinks def)
+        <*> v .:? (T.pack saveFormatKey)    .!= (extension $ defaultSaveFormat def)
+        <*> v .:? (T.pack dpiKey)           .!= (defaultDPI def)
+        <*> v .:? (T.pack isTightBboxKey)   .!= (isTightBbox def)
+        <*> v .:? (T.pack isTransparentKey) .!= (isTransparent def)
+        <*> v .:? "interpreter"             .!= (interpreter def)
+        <*> v .:? "flags"                   .!= (flags def)
     
     parseJSON _ = fail "Could not parse the configuration"
 
@@ -94,6 +81,8 @@                            , defaultSaveFormat    = saveFormat'
                            , defaultWithLinks     = defaultWithLinks_ prec
                            , defaultDPI           = defaultDPI_ prec
+                           , isTightBbox          = tightBbox_ prec
+                           , isTransparent        = transparent_ prec
                            , interpreter          = interpreter_ prec
                            , flags                = flags_ prec
                            }
src/Text/Pandoc/Filter/Pyplot/FigureSpec.hs view
@@ -50,7 +50,6 @@ import           Text.Pandoc.Readers          (readMarkdown)
 
 import Text.Pandoc.Filter.Pyplot.Types
-import Text.Pandoc.Filter.Pyplot.Configuration
 
 
 -- | Determine inclusion specifications from Block attributes.
@@ -67,18 +66,21 @@     figureSpec :: IO FigureSpec
     figureSpec = do
         includeScript <- fromMaybe (return $ defaultIncludeScript config) $ T.readFile <$> includePath
-        let header      = "# Generated by pandoc-pyplot " <> ((T.pack . showVersion) version)
-            fullScript  = mconcat $ intersperse "\n" [header, includeScript, T.pack content]
-            caption'    = Map.findWithDefault mempty captionKey attrs'
-            format      = fromMaybe (defaultSaveFormat config) $ join $ saveFormatFromString <$> Map.lookup saveFormatKey attrs'
-            dir         = makeValid $ Map.findWithDefault (defaultDirectory config) directoryKey attrs'
-            dpi'        = fromMaybe (defaultDPI config) $ read <$> Map.lookup dpiKey attrs'
-            withLinks'  = fromMaybe (defaultWithLinks config) $ readBool <$> Map.lookup withLinksKey attrs'
-            blockAttrs' = (id', filter (/= "pyplot") cls, filteredAttrs)
-        return $ FigureSpec caption' withLinks' fullScript format dir dpi' blockAttrs'
+        let header       = "# Generated by pandoc-pyplot " <> ((T.pack . showVersion) version)
+            fullScript   = mconcat $ intersperse "\n" [header, includeScript, T.pack content]
+            caption'     = Map.findWithDefault mempty captionKey attrs'
+            format       = fromMaybe (defaultSaveFormat config) $ join $ saveFormatFromString <$> Map.lookup saveFormatKey attrs'
+            dir          = makeValid $ Map.findWithDefault (defaultDirectory config) directoryKey attrs'
+            dpi'         = fromMaybe (defaultDPI config) $ read <$> Map.lookup dpiKey attrs'
+            withLinks'   = fromMaybe (defaultWithLinks config) $ readBool <$> Map.lookup withLinksKey attrs'
+            tightBbox'   = isTightBbox config
+            transparent' = isTransparent config
+            blockAttrs'  = (id', filter (/= "pyplot") cls, filteredAttrs)
+        return $ FigureSpec caption' withLinks' fullScript format dir dpi' tightBbox' transparent' blockAttrs'
     
 parseFigureSpec _ _ = return Nothing
 
+
 -- | Convert a FigureSpec to a Pandoc block component
 toImage :: FigureSpec -> Block
 toImage spec = head . toList $ para $ imageWith attrs' target' "fig:" caption'
@@ -95,6 +97,7 @@         captionLinks = mconcat [" (", srcLink, ", ", hiresLink, ")"]
         caption'     = if withLinks' then captionText <> captionLinks else captionText
 
+
 -- | Determine the path a figure should have.
 figurePath :: FigureSpec -> FilePath
 figurePath spec = directory spec </> stem spec
@@ -102,16 +105,19 @@     stem = flip addExtension ext . show . hash
     ext  = extension . saveFormat $ spec
 
+
 -- | Determine the path to the source code that generated the figure.
 sourceCodePath :: FigureSpec -> FilePath
 sourceCodePath = flip replaceExtension ".txt" . figurePath
 
+
 -- | The path to the high-resolution figure.
 hiresFigurePath :: FigureSpec -> FilePath
 hiresFigurePath spec = flip replaceExtension (".hires" <> ext) . figurePath $ spec
   where
     ext = extension . saveFormat $ spec
 
+
 -- | Modify a Python plotting script to save the figure to a filename.
 -- An additional file will also be captured.
 addPlotCapture :: FigureSpec   -- ^ Path where to save the figure
@@ -124,15 +130,21 @@         , plotCapture (hiresFigurePath spec) (minimum [200, 2 * dpi spec])
         ]
   where
-    plotCapture fname' dpi' =
-        mconcat
-            [ "\nplt.savefig("
-            , T.pack $ show fname' -- show is required for quotes
-            , ", dpi="
-            , T.pack $ show dpi'
-            , ")"
-            ]
+    tight' = tightBbox spec
+    transparent' = transparent spec
+    plotCapture fname' dpi' = mconcat $ 
+        [ "\nplt.savefig("
+        , T.pack $ show fname' -- show is required for quotes
+        , ", dpi="
+        , T.pack $ show dpi'
+        , ", transparent="
+        , T.pack $ show transparent'
+        , if tight' 
+            then ", bbox_inches=\"tight\")"
+            else ")"
+        ]
 
+
 -- | Reader options for captions.
 readerOptions :: ReaderOptions
 readerOptions = def 
@@ -144,6 +156,7 @@             , Ext_raw_tex
             ] 
     }
+
 
 -- | Read a figure caption in Markdown format. LaTeX math @$...$@ is supported,
 -- as are Markdown subscripts and superscripts.
src/Text/Pandoc/Filter/Pyplot/Types.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE CPP               #-}
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE DeriveGeneric     #-}
 {-|
 Module      : Text.Pandoc.Filter.Pyplot.Types
 Copyright   : (c) Laurent P René de Cotret, 2019
@@ -15,14 +16,41 @@ 
 import Data.Char              (toLower)
 import Data.Default.Class     (Default, def)
-import Data.Hashable          (Hashable, hashWithSalt)
+import Data.Hashable          (Hashable)
 import Data.Semigroup         as Sem
-import Data.Text              (Text)
+import Data.Text              (Text, pack)
 import Data.Yaml
 
+import GHC.Generics           (Generic)
+
 import Text.Pandoc.Definition (Attr)   
 
 
+-- | Keys that pandoc-pyplot will look for in code blocks. These are only exported for testing purposes.
+directoryKey, captionKey, dpiKey, includePathKey, saveFormatKey, withLinksKey, isTightBboxKey, isTransparentKey :: String
+directoryKey     = "directory"
+captionKey       = "caption"
+dpiKey           = "dpi"
+includePathKey   = "include"
+saveFormatKey    = "format"
+withLinksKey     = "links"
+isTightBboxKey   = "tight_bbox"
+isTransparentKey = "transparent"
+
+-- | list of all keys related to pandoc-pyplot that 
+-- can be specified in source material.
+inclusionKeys :: [String]
+inclusionKeys = [ directoryKey
+                , captionKey
+                , dpiKey
+                , includePathKey
+                , saveFormatKey
+                , withLinksKey
+                , isTightBboxKey
+                , isTransparentKey
+                ]
+
+
 -- | String representation of a Python script
 type PythonScript = Text
 
@@ -73,8 +101,10 @@     | EPS
     | GIF
     | TIF
-    deriving (Bounded, Enum, Eq, Show)
+    deriving (Bounded, Enum, Eq, Show, Generic)
 
+instance Hashable SaveFormat -- From Generic
+
 -- | Parse an image save format string
 --
 -- >>> saveFormatFromString ".png"
@@ -125,6 +155,8 @@         , defaultWithLinks     :: Bool         -- ^ The default behavior of whether or not to include links to source code and high-res
         , defaultSaveFormat    :: SaveFormat   -- ^ The default save format of generated figures.
         , defaultDPI           :: Int          -- ^ The default dots-per-inch value for generated figures.
+        , isTightBbox          :: Bool         -- ^ Whether the figures should be saved with @bbox_inches="tight"@ or not. Useful for larger figures with subplots.
+        , isTransparent        :: Bool         -- ^ If True, figures will be saved with transparent background rather than solid color.
         , interpreter          :: String       -- ^ The name of the interpreter to use to render figures.
         , flags                :: [String]     -- ^ Command-line flags to be passed to the Python interpreger, e.g. ["-O", "-Wignore"]
         }
@@ -137,22 +169,26 @@         , defaultWithLinks     = True
         , defaultSaveFormat    = PNG
         , defaultDPI           = 80
+        , isTightBbox          = False
+        , isTransparent        = False
         , interpreter          = defaultPlatformInterpreter
         , flags                = mempty
     }
 
 instance ToJSON Configuration where
-    toJSON (Configuration dir' _ withLinks' savefmt' dpi' interp' flags') = 
+    toJSON (Configuration dir' _ withLinks' savefmt' dpi' tightbbox' transparent' interp' flags') = 
         -- We ignore the include script as we want to examplify that
         -- this is for a filepath
-            object [ "directory"    .= dir'
-                    , "include"     .= ("example.py" :: FilePath)
-                    , "links"       .= withLinks'
-                    , "dpi"         .= dpi'
-                    , "format"      .= (toLower <$> show savefmt')
-                    , "interpreter" .= interp'
-                    , "flags"       .= flags'
-                    ]
+            object [ pack directoryKey      .= dir'
+                   , pack includePathKey   .= ("example.py" :: FilePath)
+                   , pack withLinksKey     .= withLinks'
+                   , pack dpiKey           .= dpi'
+                   , pack saveFormatKey    .= (toLower <$> show savefmt')
+                   , pack isTightBboxKey   .= tightbbox'
+                   , pack isTransparentKey .= transparent'
+                   , "interpreter" .= interp'
+                   , "flags"       .= flags'
+                   ]
 
     
 -- | Datatype containing all parameters required to run pandoc-pyplot. 
@@ -160,22 +196,15 @@ -- It is assumed that once a @FigureSpec@ has been created, no configuration
 -- can overload it; hence, a @FigureSpec@ completely encodes a particular figure.
 data FigureSpec = FigureSpec
-    { caption    :: String       -- ^ Figure caption.
-    , withLinks  :: Bool         -- ^ Append links to source code and high-dpi figure to caption
-    , script     :: PythonScript -- ^ Source code for the figure.
-    , saveFormat :: SaveFormat   -- ^ Save format of the figure
-    , directory  :: FilePath     -- ^ Directory where to save the file
-    , dpi        :: Int          -- ^ Dots-per-inch of figure
-    , blockAttrs :: Attr         -- ^ Attributes not related to @pandoc-pyplot@ will be propagated.
-    }
+    { caption     :: String       -- ^ Figure caption.
+    , withLinks   :: Bool         -- ^ Append links to source code and high-dpi figure to caption.
+    , script      :: PythonScript -- ^ Source code for the figure.
+    , saveFormat  :: SaveFormat   -- ^ Save format of the figure.
+    , directory   :: FilePath     -- ^ Directory where to save the file.
+    , dpi         :: Int          -- ^ Dots-per-inch of figure.
+    , tightBbox   :: Bool         -- ^ Enforce tight bounding-box with @bbox_inches="tight"@.
+    , transparent :: Bool         -- ^ Make figure background transparent.
+    , blockAttrs  :: Attr         -- ^ Attributes not related to @pandoc-pyplot@ will be propagated.
+    } deriving Generic
 
-instance Hashable FigureSpec where
-    hashWithSalt salt spec =
-        -- Some things are not included in the hash because they do not affect the outcome 
-        -- of running scripts, e.g. whether links should be shown or not.
-        hashWithSalt salt ( caption spec
-                          , script spec
-                          , fromEnum . saveFormat $ spec
-                          , directory spec, dpi spec
-                          , blockAttrs spec
-                          )
+instance Hashable FigureSpec -- From Generic
test/Main.hs view
@@ -279,6 +279,8 @@                          , defaultSaveFormat = JPG
                          , defaultDPI = 150
                          , flags = ["-Wignore"]
+                         , isTightBbox = True
+                         , isTransparent = True
                          }
         parsedConfig <- configuration "test/fixtures/.pandoc-pyplot.yml"
         assertEqual "" config parsedConfig