Skip to content

Commit d738721

Browse files
authored
Merge pull request #45 from LaurentRDC/SageMath-support
Support for sage
2 parents a4caa40 + 2e3c088 commit d738721

File tree

11 files changed

+146
-6
lines changed

11 files changed

+146
-6
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22

33
pandoc-plot uses [Semantic Versioning](http://semver.org/spec/v2.0.0.html)
44

5-
## Release 1.4.2
5+
## Release 1.5.0
66

7+
* Added support for [Sage](https://www.sagemath.org/) (#44)
78
* Fixed an issue where the parsing of default save format from configuration was overly restrictive (#42).
89

910
## Release 1.4.1

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ The resulting `output.html` looks like this:
6969
- `graphviz`: graphs using [Graphviz](http://graphviz.org/);
7070
- `bokeh`: plots using the [Bokeh](https://bokeh.org/) visualization library;
7171
- `plotsjl`: plots using the [Julia `Plots.jl`](https://docs.juliaplots.org/latest/) package;
72-
- `plantuml`: diagrams using the [PlantUML](https://plantuml.com/) software suite.
72+
- `plantuml`: diagrams using the [PlantUML](https://plantuml.com/) software suite;
73+
- `sageplot`: plots using the [Sage](https://www.sagemath.org/) software system.
7374

7475
To know which toolkits are useable on *your machine* (and which ones are
7576
not available), you can check with the `toolkits` command:

example-config.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,4 +136,9 @@ plantuml:
136136
# use the following configuration instead:
137137
# plantuml:
138138
# executable: plantuml
139-
# command_line_arguments:
139+
# command_line_arguments:
140+
141+
sageplot:
142+
# preamble: sageplot.sage
143+
executable: sage
144+
command_line_arguments:

pandoc-plot.cabal

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
cabal-version: 2.2
22
name: pandoc-plot
3-
version: 1.4.1
3+
version: 1.5.0
44
synopsis: A Pandoc filter to include figures generated from code blocks using your plotting toolkit of choice.
55
description: A Pandoc filter to include figures generated from code blocks.
66
Keep the document and code in the same location. Output is
@@ -73,6 +73,7 @@ library
7373
Text.Pandoc.Filter.Plot.Renderers.Bokeh
7474
Text.Pandoc.Filter.Plot.Renderers.Plotsjl
7575
Text.Pandoc.Filter.Plot.Renderers.PlantUML
76+
Text.Pandoc.Filter.Plot.Renderers.SageMath
7677
Text.Pandoc.Filter.Plot.Monad
7778
Text.Pandoc.Filter.Plot.Monad.Logging
7879
Text.Pandoc.Filter.Plot.Monad.Types

src/Text/Pandoc/Filter/Plot/Configuration.hs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ defaultConfiguration =
6363
bokehPreamble = mempty,
6464
plotsjlPreamble = mempty,
6565
plantumlPreamble = mempty,
66+
sagemathPreamble = mempty,
6667
-- Executables
6768
matplotlibExe = python,
6869
matlabExe = "matlab",
@@ -76,6 +77,7 @@ defaultConfiguration =
7677
bokehExe = python,
7778
plotsjlExe = "julia",
7879
plantumlExe = "java",
80+
sagemathExe = "sage",
7981
-- Command line arguments
8082
matplotlibCmdArgs = mempty,
8183
matlabCmdArgs = mempty,
@@ -89,6 +91,7 @@ defaultConfiguration =
8991
bokehCmdArgs = mempty,
9092
plotsjlCmdArgs = mempty,
9193
plantumlCmdArgs = "-jar plantuml.jar",
94+
sagemathCmdArgs = mempty,
9295
-- Extras
9396
matplotlibTightBBox = False,
9497
matplotlibTransparent = False
@@ -147,7 +150,8 @@ data ConfigPrecursor = ConfigPrecursor
147150
_graphvizPrec :: !GraphvizPrecursor,
148151
_bokehPrec :: !BokehPrecursor,
149152
_plotsjlPrec :: !PlotsjlPrecursor,
150-
_plantumlPrec :: !PlantUMLPrecursor
153+
_plantumlPrec :: !PlantUMLPrecursor,
154+
_sagemathPrec :: !SageMathPrecursor
151155
}
152156

153157
defaultConfigPrecursor :: ConfigPrecursor
@@ -173,7 +177,8 @@ defaultConfigPrecursor =
173177
_graphvizPrec = GraphvizPrecursor Nothing (graphvizExe defaultConfiguration) (graphvizCmdArgs defaultConfiguration),
174178
_bokehPrec = BokehPrecursor Nothing (bokehExe defaultConfiguration) (bokehCmdArgs defaultConfiguration),
175179
_plotsjlPrec = PlotsjlPrecursor Nothing (plotsjlExe defaultConfiguration) (plotsjlCmdArgs defaultConfiguration),
176-
_plantumlPrec = PlantUMLPrecursor Nothing (plantumlExe defaultConfiguration) (plantumlCmdArgs defaultConfiguration)
180+
_plantumlPrec = PlantUMLPrecursor Nothing (plantumlExe defaultConfiguration) (plantumlCmdArgs defaultConfiguration),
181+
_sagemathPrec = SageMathPrecursor Nothing (sagemathExe defaultConfiguration) (sagemathCmdArgs defaultConfiguration)
177182
}
178183

179184
data LoggingPrecursor = LoggingPrecursor
@@ -212,6 +217,8 @@ data PlotsjlPrecursor = PlotsjlPrecursor {_plotsjlPreamble :: !(Maybe FilePath),
212217

213218
data PlantUMLPrecursor = PlantUMLPrecursor {_plantumlPreamble :: !(Maybe FilePath), _plantumlExe :: !FilePath, _plantumlCmdArgs :: !Text}
214219

220+
data SageMathPrecursor = SageMathPrecursor {_sagemathPreamble :: !(Maybe FilePath), _sagemathExe :: !FilePath, _sagemathCmdArgs :: !Text}
221+
215222
instance FromJSON LoggingPrecursor where
216223
parseJSON (Object v) =
217224
LoggingPrecursor <$> v .:? "verbosity" .!= logVerbosity defaultConfiguration
@@ -275,6 +282,10 @@ instance FromJSON PlantUMLPrecursor where
275282
parseJSON (Object v) = PlantUMLPrecursor <$> v .:? asKey PreambleK <*> v .:? asKey ExecutableK .!= plantumlExe defaultConfiguration <*> v .:? asKey CommandLineArgsK .!= plantumlCmdArgs defaultConfiguration
276283
parseJSON _ = fail $ mconcat ["Could not parse ", show PlantUML, " configuration."]
277284

285+
instance FromJSON SageMathPrecursor where
286+
parseJSON (Object v) = SageMathPrecursor <$> v .:? asKey PreambleK <*> v .:? asKey ExecutableK .!= sagemathExe defaultConfiguration <*> v .:? asKey CommandLineArgsK .!= sagemathCmdArgs defaultConfiguration
287+
parseJSON _ = fail $ mconcat ["Could not parse ", show SageMath, " configuration."]
288+
278289
toolkitAsKey :: Toolkit -> Key
279290
toolkitAsKey = fromString . unpack . cls
280291

@@ -303,6 +314,7 @@ instance FromJSON ConfigPrecursor where
303314
_bokehPrec <- v .:? toolkitAsKey Bokeh .!= _bokehPrec defaultConfigPrecursor
304315
_plotsjlPrec <- v .:? toolkitAsKey Plotsjl .!= _plotsjlPrec defaultConfigPrecursor
305316
_plantumlPrec <- v .:? toolkitAsKey PlantUML .!= _plantumlPrec defaultConfigPrecursor
317+
_sagemathPrec <- v .:? toolkitAsKey SageMath .!= _sagemathPrec defaultConfigPrecursor
306318

307319
return $ ConfigPrecursor {..}
308320
parseJSON _ = fail "Could not parse configuration."
@@ -336,6 +348,7 @@ renderConfig ConfigPrecursor {..} = do
336348
bokehExe = _bokehExe _bokehPrec
337349
plotsjlExe = _plotsjlExe _plotsjlPrec
338350
plantumlExe = _plantumlExe _plantumlPrec
351+
sagemathExe = _sagemathExe _sagemathPrec
339352

340353
matplotlibCmdArgs = _matplotlibCmdArgs _matplotlibPrec
341354
matlabCmdArgs = _matlabCmdArgs _matlabPrec
@@ -349,6 +362,7 @@ renderConfig ConfigPrecursor {..} = do
349362
bokehCmdArgs = _bokehCmdArgs _bokehPrec
350363
plotsjlCmdArgs = _plotsjlCmdArgs _plotsjlPrec
351364
plantumlCmdArgs = _plantumlCmdArgs _plantumlPrec
365+
sagemathCmdArgs = _sagemathCmdArgs _sagemathPrec
352366

353367
matplotlibPreamble <- readPreamble (_matplotlibPreamble _matplotlibPrec)
354368
matlabPreamble <- readPreamble (_matlabPreamble _matlabPrec)
@@ -362,6 +376,7 @@ renderConfig ConfigPrecursor {..} = do
362376
bokehPreamble <- readPreamble (_bokehPreamble _bokehPrec)
363377
plotsjlPreamble <- readPreamble (_plotsjlPreamble _plotsjlPrec)
364378
plantumlPreamble <- readPreamble (_plantumlPreamble _plantumlPrec)
379+
sagemathPreamble <- readPreamble (_sagemathPreamble _sagemathPrec)
365380

366381
return Configuration {..}
367382
where

src/Text/Pandoc/Filter/Plot/Monad.hs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@ executable tk =
288288
exeSelector Bokeh = asksConfig bokehExe
289289
exeSelector Plotsjl = asksConfig plotsjlExe
290290
exeSelector PlantUML = asksConfig plantumlExe
291+
exeSelector SageMath = asksConfig sagemathExe
291292

292293
-- | The @Configuration@ type holds the default values to use
293294
-- when running pandoc-plot. These values can be overridden in code blocks.
@@ -354,6 +355,8 @@ data Configuration = Configuration
354355
plotsjlPreamble :: !Script,
355356
-- | The default preamble script for the PlantUML toolkit.
356357
plantumlPreamble :: !Script,
358+
-- | The default preamble script for the SageMath toolkit.
359+
sagemathPreamble :: !Script,
357360
-- | The executable to use to generate figures using the matplotlib toolkit.
358361
matplotlibExe :: !FilePath,
359362
-- | The executable to use to generate figures using the MATLAB toolkit.
@@ -378,6 +381,8 @@ data Configuration = Configuration
378381
plotsjlExe :: !FilePath,
379382
-- | The executable to use to generate figures using the PlantUML toolkit.
380383
plantumlExe :: !FilePath,
384+
-- | The executable to use to generate figures using SageMath.
385+
sagemathExe :: !FilePath,
381386
-- | Command-line arguments to pass to the Python interpreter for the Matplotlib toolkit
382387
matplotlibCmdArgs :: !Text,
383388
-- | Command-line arguments to pass to the interpreter for the MATLAB toolkit.
@@ -402,6 +407,8 @@ data Configuration = Configuration
402407
plotsjlCmdArgs :: !Text,
403408
-- | Command-line arguments to pass to the interpreter for the plantUML toolkit.
404409
plantumlCmdArgs :: !Text,
410+
-- | Command-line arguments to pass to the interpreter for the SageMath toolkit.
411+
sagemathCmdArgs :: !Text,
405412
-- | Whether or not to make Matplotlib figures tight by default.
406413
matplotlibTightBBox :: !Bool,
407414
-- | Whether or not to make Matplotlib figures transparent by default.

src/Text/Pandoc/Filter/Plot/Monad/Types.hs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ data Toolkit
5959
| Bokeh
6060
| Plotsjl
6161
| PlantUML
62+
| SageMath
6263
deriving (Bounded, Eq, Enum, Generic, Ord)
6364

6465
-- | This instance should only be used to display toolkit names
@@ -75,6 +76,7 @@ instance Show Toolkit where
7576
show Bokeh = "Python/Bokeh"
7677
show Plotsjl = "Julia/Plots.jl"
7778
show PlantUML = "PlantUML"
79+
show SageMath = "SageMath"
7880

7981
-- | Class name which will trigger the filter
8082
cls :: Toolkit -> Text
@@ -90,6 +92,7 @@ cls Graphviz = "graphviz"
9092
cls Bokeh = "bokeh"
9193
cls Plotsjl = "plotsjl"
9294
cls PlantUML = "plantuml"
95+
cls SageMath = "sageplot"
9396

9497
-- | Executable program and directory where it can be found.
9598
data Executable = Executable FilePath Text

src/Text/Pandoc/Filter/Plot/Renderers.hs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,31 @@ import Text.Pandoc.Filter.Plot.Monad.Logging
4242
( Logger (lVerbosity),
4343
)
4444
import Text.Pandoc.Filter.Plot.Renderers.Bokeh
45+
( bokeh, bokehSupportedSaveFormats )
4546
import Text.Pandoc.Filter.Plot.Renderers.GGPlot2
47+
( ggplot2, ggplot2SupportedSaveFormats )
4648
import Text.Pandoc.Filter.Plot.Renderers.GNUPlot
49+
( gnuplot, gnuplotSupportedSaveFormats )
4750
import Text.Pandoc.Filter.Plot.Renderers.Graphviz
51+
( graphviz, graphvizSupportedSaveFormats )
4852
import Text.Pandoc.Filter.Plot.Renderers.Mathematica
53+
( mathematica, mathematicaSupportedSaveFormats )
4954
import Text.Pandoc.Filter.Plot.Renderers.Matlab
55+
( matlab, matlabSupportedSaveFormats )
5056
import Text.Pandoc.Filter.Plot.Renderers.Matplotlib
57+
( matplotlib, matplotlibSupportedSaveFormats )
5158
import Text.Pandoc.Filter.Plot.Renderers.Octave
59+
( octave, octaveSupportedSaveFormats )
5260
import Text.Pandoc.Filter.Plot.Renderers.PlantUML
61+
( plantuml, plantumlSupportedSaveFormats )
5362
import Text.Pandoc.Filter.Plot.Renderers.PlotlyPython
63+
( plotlyPython, plotlyPythonSupportedSaveFormats )
5464
import Text.Pandoc.Filter.Plot.Renderers.PlotlyR
65+
( plotlyR, plotlyRSupportedSaveFormats )
5566
import Text.Pandoc.Filter.Plot.Renderers.Plotsjl
67+
( plotsjl, plotsjlSupportedSaveFormats )
68+
import Text.Pandoc.Filter.Plot.Renderers.SageMath
69+
( sagemath, sagemathSupportedSaveFormats )
5670

5771
-- | Get the renderer associated with a toolkit.
5872
-- If the renderer has not been used before,
@@ -87,6 +101,7 @@ renderer tk = do
87101
sel Bokeh = bokeh
88102
sel Plotsjl = plotsjl
89103
sel PlantUML = plantuml
104+
sel SageMath = sagemath
90105

91106
-- | Save formats supported by this renderer.
92107
supportedSaveFormats :: Toolkit -> [SaveFormat]
@@ -102,6 +117,7 @@ supportedSaveFormats Graphviz = graphvizSupportedSaveFormats
102117
supportedSaveFormats Bokeh = bokehSupportedSaveFormats
103118
supportedSaveFormats Plotsjl = plotsjlSupportedSaveFormats
104119
supportedSaveFormats PlantUML = plantumlSupportedSaveFormats
120+
supportedSaveFormats SageMath = sagemathSupportedSaveFormats
105121

106122
-- | The function that maps from configuration to the preamble.
107123
preambleSelector :: Toolkit -> (Configuration -> Script)
@@ -117,6 +133,7 @@ preambleSelector Graphviz = graphvizPreamble
117133
preambleSelector Bokeh = bokehPreamble
118134
preambleSelector Plotsjl = plotsjlPreamble
119135
preambleSelector PlantUML = plantumlPreamble
136+
preambleSelector SageMath = sagemathPreamble
120137

121138
-- | Parse code block headers for extra attributes that are specific
122139
-- to this renderer. By default, no extra attributes are parsed.
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
{-# LANGUAGE OverloadedStrings #-}
2+
{-# LANGUAGE QuasiQuotes #-}
3+
{-# LANGUAGE RecordWildCards #-}
4+
{-# LANGUAGE NoImplicitPrelude #-}
5+
6+
-- |
7+
-- Module : $header$
8+
-- Copyright : (c) Laurent P René de Cotret, 2019 - present
9+
-- License : GNU GPL, version 2 or above
10+
-- Maintainer : laurent.decotret@outlook.com
11+
-- Stability : internal
12+
-- Portability : portable
13+
--
14+
-- Rendering SageMath figures
15+
module Text.Pandoc.Filter.Plot.Renderers.SageMath
16+
( sagemath,
17+
sagemathSupportedSaveFormats,
18+
)
19+
where
20+
21+
import Text.Pandoc.Filter.Plot.Renderers.Prelude
22+
23+
sagemath :: PlotM (Maybe Renderer)
24+
sagemath = do
25+
avail <- sagemathAvailable
26+
if not avail
27+
then return Nothing
28+
else do
29+
cmdargs <- asksConfig sagemathCmdArgs
30+
mexe <- executable SageMath
31+
return $
32+
mexe >>= \exe@(Executable _ exename) ->
33+
return
34+
Renderer
35+
{ rendererToolkit = SageMath,
36+
rendererExe = exe,
37+
rendererCapture = sagemathCapture,
38+
rendererCommand = sagemathCommand cmdargs exename,
39+
rendererSupportedSaveFormats = sagemathSupportedSaveFormats,
40+
rendererChecks = mempty,
41+
rendererLanguage = "sagemath",
42+
rendererComment = mappend "# ",
43+
rendererScriptExtension = ".sage"
44+
}
45+
46+
-- See here:
47+
-- https://doc.sagemath.org/html/en/reference/plotting/sage/plot/graphics.html#sage.plot.graphics.Graphics.save
48+
sagemathSupportedSaveFormats :: [SaveFormat]
49+
sagemathSupportedSaveFormats = [EPS, PDF, PNG, SVG]
50+
51+
sagemathCommand :: Text -> Text -> OutputSpec -> Text
52+
sagemathCommand cmdargs exe OutputSpec {..} = [st|#{exe} #{cmdargs} "#{oScriptPath}"|]
53+
54+
sagemathAvailable :: PlotM Bool
55+
sagemathAvailable = do
56+
mexe <- executable SageMath
57+
case mexe of
58+
Nothing -> return False
59+
Just (Executable dir exe) -> do
60+
withPrependedPath dir $ asks envCWD >>= flip commandSuccess [st|#{exe} -v|]
61+
62+
63+
sagemathCapture :: FigureSpec -> FilePath -> Script
64+
sagemathCapture = appendCapture sagemathCaptureFragment
65+
66+
67+
-- This capture fragment is a bit ugly because sage does not have the
68+
-- equivalent of matplotlib's `plt.gca()` to get a pointer to the most
69+
-- recent graphical object. We must search for it
70+
sagemathCaptureFragment :: FigureSpec -> FilePath -> Script
71+
sagemathCaptureFragment FigureSpec {..} fname =
72+
[st|
73+
import sage.plot.graphics as go
74+
import sage.plot.plot3d.base as go3d
75+
import builtins
76+
# Try to concatenate 3D graphics objects first; if this doesn't work, then
77+
# concatenate all 2D graphic objects.
78+
__all_graphics = builtins.sum( (obj for obj in globals().values() if isinstance(obj, go3d.Graphics3d)))
79+
if not __all_graphics:
80+
__all_graphics = builtins.sum( (obj for obj in globals().values() if isinstance(obj, go.Graphics)))
81+
if not __all_graphics:
82+
raise RuntimeError(''.join([
83+
"No plotting objects detected. ",
84+
"Make sure that all of your plotting objects are named, e.g. `G = plot(...)` rather than just `plot(...)`. ",
85+
"This is a limitation specific to the interaction between sage and pandoc-plot."
86+
]))
87+
__all_graphics.save_image(r"#{fname}", dpi=#{dpi})
88+
|]

tests/Common.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ testFileInclusion tk =
118118
include Bokeh = "tests/includes/bokeh.py"
119119
include Plotsjl = "tests/includes/plotsjl.jl"
120120
include PlantUML = "tests/includes/plantuml.txt"
121+
include SageMath = "tests/includes/sagemath.sage"
121122

122123
-------------------------------------------------------------------------------
123124
-- Test that the files are saved in the appropriate format
@@ -378,6 +379,7 @@ trivialContent Bokeh =
378379
]
379380
trivialContent Plotsjl = "using Plots; x = 1:10; y = rand(10); plot(x, y);"
380381
trivialContent PlantUML = "@startuml\nAlice -> Bob: test\n@enduml"
382+
trivialContent SageMath = "G = plot(sin, 1, 10)"
381383

382384
addCaption :: String -> Block -> Block
383385
addCaption caption (CodeBlock (id', cls, attrs) script) =

0 commit comments

Comments
 (0)