packages feed

pandoc-pyplot 2.1.3.0 → 2.1.4.0

raw patch · 7 files changed

+196/−186 lines, 7 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Text.Pandoc.Filter.Pyplot.Internal: parseFigureSpec :: Configuration -> Block -> IO (Maybe FigureSpec)

Files

CHANGELOG.md view
@@ -2,6 +2,20 @@ 
 pandoc-pyplot uses [Semantic Versioning](http://semver.org/spec/v2.0.0.html)
 
+Release 2.1.4.0
+---------------
+
+* Added examples and documentation on how to use `pandoc-pyplot` on LaTeX documents.
+* Allowed raw LaTeX macros in figure captions. This is required to label figures in LaTeX. E.g.:
+  
+  ```latex
+  \begin{minted}[caption=myCaption\label{myfig}]{pyplot}
+  
+  \end{minted}
+  ```
+
+* `with-links` key changed to `links`. I'm sorry. Pandoc doesn't support LaTeX tokens with `-`.
+
 Release 2.1.3.0
 ---------------
 
README.md view
@@ -6,6 +6,9 @@ `pandoc-pyplot` turns Python code present in your documents into embedded Matplotlib figures.
 
 * [Usage](#usage)
+    * [Markdown](#Markdown)
+    * [LaTeX](#latex)
+    * [Examples](#examples)
 * [Features](#features)
 * [Installation](#installation)
 * [Running the filter](#running-the-filter)
@@ -13,19 +16,21 @@ 
 ## Usage
 
-The filter recognizes code blocks with the `.pyplot` class present. It will run the script in the associated code block in a Python interpreter and capture the generated Matplotlib figure.
+### Markdown
 
+The filter recognizes code blocks with the `.pyplot` class present in Markdown documents. It will run the script in the associated code block in a Python interpreter and capture the generated Matplotlib figure.
+
 Here is a basic example using the scripting `matplotlib.pyplot` API:
 
-```markdown
-    ```{.pyplot}
-    import matplotlib.pyplot as plt
+~~~markdown
+```{.pyplot}
+import matplotlib.pyplot as plt
 
-    plt.figure()
-    plt.plot([0,1,2,3,4], [1,2,3,4,5])
-    plt.title('This is an example figure')
-    ```
+plt.figure()
+plt.plot([0,1,2,3,4], [1,2,3,4,5])
+plt.title('This is an example figure')
 ```
+~~~
 
 Putting the above in `input.md`, we can then generate the plot and embed it:
 
@@ -41,38 +46,80 @@ 
 or any other output format you want.
 
+### LaTeX
+
+The filter works slightly differently in LaTeX documents. In LaTeX, the `minted` environment must be used, with the `pyplot` class. 
+
+```latex
+\begin{minted}{pyplot}
+import matplotlib.pyplot as plt
+
+plt.figure()
+plt.plot([0,1,2,3,4], [1,2,3,4,5])
+plt.title('This is an example figure')
+\end{minted}
+```
+
+Note that __you do not need to have `minted` installed__.
+
+### Examples
+
 There are more examples in the [source repository](https://github.com/LaurentRDC/pandoc-pyplot), in the `\examples` directory.
 
 ## Features
 
 ### Captions
 
-You can also specify a caption for your image. This is done using the optional `caption` parameter:
+You can also specify a caption for your image. This is done using the optional `caption` parameter.
 
-```markdown
-    ```{.pyplot caption="This is a simple figure"}
-    import matplotlib.pyplot as plt
+__Markdown__:
 
-    plt.figure()
-    plt.plot([0,1,2,3,4], [1,2,3,4,5])
-    plt.title('This is an example figure')
-    ```
+~~~markdown
+```{.pyplot caption="This is a simple figure"}
+import matplotlib.pyplot as plt
+
+plt.figure()
+plt.plot([0,1,2,3,4], [1,2,3,4,5])
+plt.title('This is an example figure')
 ```
+~~~
 
+__LaTex__:
+
+```latex
+\begin{minted}[caption=This is a simple figure]{pyplot}
+import matplotlib.pyplot as plt
+
+plt.figure()
+plt.plot([0,1,2,3,4], [1,2,3,4,5])
+plt.title('This is an example figure')
+\end{minted}
+```
+
 Caption formatting is either plain text or Markdown. LaTeX-style math is also support in captions (using dollar signs $...$).
 
 ### Link to source code and high-resolution figure
 
 In case of an output format that supports links (e.g. HTML), the embedded image generated by `pandoc-pyplot` will be a link to the source code which was used to generate the file. Therefore, other people can see what Python code was used to create your figures. A high resolution image will be made available in a caption link.
 
-(*New in version 2.1.3.0*) For cleaner output (e.g. PDF), you can turn this off via the `with-links=false` key:
+(*New in version 2.1.3.0*) For cleaner output (e.g. PDF), you can turn this off via the `links=false` key:
 
-```markdown
-    ```{.pyplot with-links=false}
-    ...
-    ```
+__Markdown__:
+
+~~~markdown
+```{.pyplot links=false}
+...
 ```
+~~~
 
+__LaTex__:
+
+```latex
+\begin{minted}[links=false]{pyplot}
+...
+\end{minted}
+```
+
 or via a [configuration file](#Configurable).
 
 ### Including scripts
@@ -86,27 +133,35 @@ 
 and include it in your document as follows:
 
-```markdown
-    ```{.pyplot include=style.py}
-    plt.figure()
-    plt.plot([0,1,2,3,4], [1,2,3,4,5])
-    plt.title('This is an example figure')
-    ```
+~~~markdown
+```{.pyplot include=style.py}
+plt.figure()
+plt.plot([0,1,2,3,4], [1,2,3,4,5])
+plt.title('This is an example figure')
 ```
+~~~
 
 Which is equivalent to writing the following markdown:
 
-```markdown
-    ```{.pyplot}
-    import matplotlib.pyplot as plt
-    plt.style.use('ggplot')
+~~~markdown
+```{.pyplot}
+import matplotlib.pyplot as plt
+plt.style.use('ggplot')
 
-    plt.figure()
-    plt.plot([0,1,2,3,4], [1,2,3,4,5])
-    plt.title('This is an example figure')
-    ```
+plt.figure()
+plt.plot([0,1,2,3,4], [1,2,3,4,5])
+plt.title('This is an example figure')
 ```
+~~~
 
+The equivalent LaTeX usage is as follows:
+
+```latex
+\begin{minted}[include=style.py]{pyplot}
+
+\end{minted}
+```
+
 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.
 
 ### No wasted work
@@ -115,18 +170,18 @@ 
 ### Compatibility with pandoc-crossref
 
-[`pandoc-crossref`](https://github.com/lierdakil/pandoc-crossref) is a pandoc filter that makes it effortless to cross-reference objects on documents. 
+[`pandoc-crossref`](https://github.com/lierdakil/pandoc-crossref) is a pandoc filter that makes it effortless to cross-reference objects in Markdown documents. 
 
 You can use `pandoc-crossref` in conjunction with `pandoc-pyplot` for the ultimate figure-making pipeline. You can combine both in a figure like so:
 
-```markdown
-    ```{#fig:myexample .pyplot caption="This is a caption"}
-    # Insert figure script here
-    ```
-
-    As you can see in @fig:myexample, ...
+~~~markdown
+```{#fig:myexample .pyplot caption="This is a caption"}
+# Insert figure script here
 ```
 
+As you can see in @fig:myexample, ...
+~~~
+
 If the above source is located in file `myfile.md`, you can render the figure and references by applying `pandoc-pyplot` **first**, and then `pandoc-crossref`. For example:
 
 ```bash
@@ -143,7 +198,7 @@ directory: mydirectory/
 include: mystyle.py
 format: jpeg
-with-links: false
+links: false
 dpi: 150
 flags: [-O, -Wignore]
 ```
@@ -152,12 +207,13 @@ 
 ```yaml
 # Defaults if no configuration is provided.
-# Note that the default interpreter name on MacOS and Unix is python3
+# Note that the default interpreter name on MacOS and Unix is 'python3'
+# and 'python' on Windows.
 interpreter: python
 flags: []
 directory: generated/
 format: png
-with-links: true
+links: true
 dpi: 80
 ```
 
pandoc-pyplot.cabal view
@@ -1,5 +1,5 @@ name:           pandoc-pyplot
-version:        2.1.3.0
+version:        2.1.4.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.hs view
@@ -10,8 +10,8 @@ Stability   : stable
 Portability : portable
 
-This module defines a Pandoc filter @makePlot@ that can be
-used to walk over a Pandoc document and generate figures from
+This module defines a Pandoc filter @makePlot@ and related functions 
+that can be used to walk over a Pandoc document and generate figures from
 Python code blocks.
 
 The syntax for code blocks is simple, Code blocks with the @.pyplot@
@@ -30,68 +30,9 @@     * @caption="..."@: Specify a plot caption (or alternate text). Captions support Markdown formatting and LaTeX math (@$...$@).
     * @dpi=...@: Specify a value for figure resolution, or dots-per-inch. Default is 80DPI.
     * @include=...@: Path to a Python script to include before the code block. Ideal to avoid repetition over many figures.
-
-Here are some example blocks in Markdown:
-
-@
-This is a paragraph
-
-```{.pyplot caption="This is a caption."}
-import matplotlib.pyplot as plt
-
-plt.figure()
-plt.plot([0,1,2,3,4], [1,2,3,4,5])
-plt.title('This is an example figure')
-```
-
-This is another paragraph
-
-```{.pyplot dpi=150 format=SVG}
-# This example was taken from the Matplotlib gallery
-# https://matplotlib.org/examples/pylab_examples/bar_stacked.html
-
-import numpy as np
-import matplotlib.pyplot as plt
-
-N = 5
-menMeans = (20, 35, 30, 35, 27)
-womenMeans = (25, 32, 34, 20, 25)
-menStd = (2, 3, 4, 1, 2)
-womenStd = (3, 5, 2, 3, 3)
-ind = np.arange(N)    # the x locations for the groups
-width = 0.35       # the width of the bars: can also be len(x) sequence
-
-p1 = plt.bar(ind, menMeans, width, color='#d62728', yerr=menStd)
-p2 = plt.bar(ind, womenMeans, width,
-             bottom=menMeans, yerr=womenStd)
-
-plt.ylabel('Scores')
-plt.title('Scores by group and gender')
-plt.xticks(ind, ('G1', 'G2', 'G3', 'G4', 'G5'))
-plt.yticks(np.arange(0, 81, 10))
-plt.legend((p1[0], p2[0]), ('Men', 'Women'))
-```
-@
-
-This filter was originally designed to be used with [Hakyll](https://jaspervdj.be/hakyll/). 
-In case you want to use the filter with your own Hakyll setup, you can use a transform 
-function that works on entire documents:
-
-@
-import Text.Pandoc.Filter.Pyplot (plotTransform)
-
-import Hakyll
-
--- Unsafe compiler is required because of the interaction
--- in IO (i.e. running an external Python script).
-makePlotPandocCompiler :: Compiler (Item String)
-makePlotPandocCompiler =
-  pandocCompilerWithTransformM
-    defaultHakyllReaderOptions
-    defaultHakyllWriterOptions
-    (unsafeCompiler . plotTransform)
-@
-
+    * @links=true|false@: Add links to source code and high-resolution version of this figure. 
+      This is @true@ by default, but you may wish to disable this for PDF output.
+      
 Custom configurations are possible via the @Configuration@ type and the filter 
 functions @plotTransformWithConfig@ and @makePlotWithConfig@. 
 -}
@@ -112,63 +53,14 @@     , makePlot'
     ) where
 
-import           Control.Monad                 ((>=>), join)
-
-import           Data.List                     (intersperse)
+import           Control.Monad                 ((>=>))
 
 import           Data.Default.Class            (def)
-import qualified Data.Map.Strict               as Map
-import           Data.Maybe                    (fromMaybe)
-import           Data.Monoid                   ((<>))
-import qualified Data.Text                     as T
-import qualified Data.Text.IO                  as T
-import           Data.Version                  (showVersion)
 
-import           Paths_pandoc_pyplot           (version)
-
-import           System.FilePath               (makeValid)
-
 import           Text.Pandoc.Definition
 import           Text.Pandoc.Walk              (walkM)
 
 import           Text.Pandoc.Filter.Pyplot.Internal
-
--- | Code block class that will trigger the filter
-filterClass :: String
-filterClass = "pyplot"
-
-
--- | Flexible boolean parsing
-readBool :: String -> Bool
-readBool s | s `elem` ["True",  "true",  "'True'",  "'true'",  "1"] = True
-           | s `elem` ["False", "false", "'False'", "'false'", "0"] = False
-           | otherwise = error $ mconcat ["Could not parse '", s, "' into a boolean. Please use 'True' or 'False'"] 
-
--- | Determine inclusion specifications from Block attributes.
--- Note that the @".pyplot"@ class is required, but all other parameters are optional
-parseFigureSpec :: Configuration -> Block -> IO (Maybe FigureSpec)
-parseFigureSpec config (CodeBlock (id', cls, attrs) content)
-    | filterClass `elem` cls = Just <$> figureSpec
-    | otherwise = return Nothing
-  where
-    attrs'        = Map.fromList attrs
-    filteredAttrs = filter (\(k, _) -> k `notElem` inclusionKeys) attrs
-    includePath   = Map.lookup includePathKey attrs'
-
-    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 (/= filterClass) cls, filteredAttrs)
-        return $ FigureSpec caption' withLinks' fullScript format dir dpi' blockAttrs'
-    
-parseFigureSpec _ _ = return Nothing
 
 -- | Main routine to include Matplotlib plots.
 -- Code blocks containing the attributes @.pyplot@ are considered
src/Text/Pandoc/Filter/Pyplot/Configuration.hs view
@@ -41,7 +41,7 @@ dpiKey         = "dpi"
 includePathKey = "include"
 saveFormatKey  = "format"
-withLinksKey   = "with-links"
+withLinksKey   = "links"
 
 -- | list of all keys related to pandoc-pyplot.
 inclusionKeys :: [String]
src/Text/Pandoc/Filter/Pyplot/FigureSpec.hs view
@@ -19,53 +19,65 @@     , sourceCodePath
     , figurePath
     , addPlotCapture
+    , parseFigureSpec
     -- for testing purposes
     , extension
     ) where
 
 import           Control.Monad                (join)
 
+import           Data.Default.Class           (def)
 import           Data.Hashable                (hash)
+import           Data.List                    (intersperse)
+import qualified Data.Map.Strict              as Map
 import           Data.Maybe                   (fromMaybe)
 import           Data.Monoid                  ((<>))
 import qualified Data.Text                    as T
+import qualified Data.Text.IO                 as T
+import           Data.Version                 (showVersion)
 
+import           Paths_pandoc_pyplot          (version)
+
 import           System.FilePath              (FilePath, addExtension,
-                                               replaceExtension, (</>))
+                                               replaceExtension, (</>), makeValid)
 
 import           Text.Pandoc.Definition       
 import           Text.Pandoc.Builder          (imageWith, link, para, fromList, toList)
 
 import           Text.Pandoc.Class            (runPure)
 import           Text.Pandoc.Extensions       (extensionsFromList, Extension(..))
-import           Text.Pandoc.Options          (def, ReaderOptions(..))
+import           Text.Pandoc.Options          (ReaderOptions(..))
 import           Text.Pandoc.Readers          (readMarkdown)
 
 import Text.Pandoc.Filter.Pyplot.Types
+import Text.Pandoc.Filter.Pyplot.Configuration
 
-readerOptions :: ReaderOptions
-readerOptions = def 
-    {readerExtensions = 
-        extensionsFromList 
-            [ Ext_tex_math_dollars
-            , Ext_superscript 
-            , Ext_subscript
-            ] 
-    }
 
--- | Read a figure caption in Markdown format. LaTeX math @$...$@ is supported,
--- as are Markdown subscripts and superscripts.
-captionReader :: String -> Maybe [Inline]
-captionReader t = either (const Nothing) (Just . extractFromBlocks) $ runPure $ readMarkdown' (T.pack t)
-    where
-        readMarkdown' = readMarkdown readerOptions
-
-        extractFromBlocks (Pandoc _ blocks) = mconcat $ extractInlines <$> blocks
+-- | Determine inclusion specifications from Block attributes.
+-- Note that the @".pyplot"@ class is required, but all other parameters are optional
+parseFigureSpec :: Configuration -> Block -> IO (Maybe FigureSpec)
+parseFigureSpec config (CodeBlock (id', cls, attrs) content)
+    | "pyplot" `elem` cls = Just <$> figureSpec
+    | otherwise = return Nothing
+  where
+    attrs'        = Map.fromList attrs
+    filteredAttrs = filter (\(k, _) -> k `notElem` inclusionKeys) attrs
+    includePath   = Map.lookup includePathKey attrs'
 
-        extractInlines (Plain inlines) = inlines
-        extractInlines (Para inlines) = inlines
-        extractInlines (LineBlock multiinlines) = join multiinlines
-        extractInlines _ = []
+    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'
+    
+parseFigureSpec _ _ = return Nothing
 
 -- | Convert a FigureSpec to a Pandoc block component
 toImage :: FigureSpec -> Block
@@ -120,3 +132,36 @@             , T.pack $ show dpi'
             , ")"
             ]
+
+-- | Reader options for captions.
+readerOptions :: ReaderOptions
+readerOptions = def 
+    {readerExtensions = 
+        extensionsFromList 
+            [ Ext_tex_math_dollars
+            , Ext_superscript 
+            , Ext_subscript
+            , Ext_raw_tex
+            ] 
+    }
+
+-- | Read a figure caption in Markdown format. LaTeX math @$...$@ is supported,
+-- as are Markdown subscripts and superscripts.
+captionReader :: String -> Maybe [Inline]
+captionReader t = either (const Nothing) (Just . extractFromBlocks) $ runPure $ readMarkdown' (T.pack t)
+    where
+        readMarkdown' = readMarkdown readerOptions
+
+        extractFromBlocks (Pandoc _ blocks) = mconcat $ extractInlines <$> blocks
+
+        extractInlines (Plain inlines) = inlines
+        extractInlines (Para inlines) = inlines
+        extractInlines (LineBlock multiinlines) = join multiinlines
+        extractInlines _ = []
+
+
+-- | Flexible boolean parsing
+readBool :: String -> Bool
+readBool s | s `elem` ["True",  "true",  "'True'",  "'true'",  "1"] = True
+           | s `elem` ["False", "false", "'False'", "'false'", "0"] = False
+           | otherwise = error $ mconcat ["Could not parse '", s, "' into a boolean. Please use 'True' or 'False'"] 
src/Text/Pandoc/Filter/Pyplot/Types.hs view
@@ -147,7 +147,7 @@         -- this is for a filepath
             object [ "directory"    .= dir'
                     , "include"     .= ("example.py" :: FilePath)
-                    , "with-links"  .= withLinks'
+                    , "links"       .= withLinks'
                     , "dpi"         .= dpi'
                     , "format"      .= (toLower <$> show savefmt')
                     , "interpreter" .= interp'
@@ -155,7 +155,10 @@                     ]
 
     
--- | Datatype containing all parameters required to run pandoc-pyplot
+-- | Datatype containing all parameters required to run pandoc-pyplot. 
+--
+-- 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