summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent P. René de Cotret <LaurentRDC@users.noreply.github.com>2023-10-25 09:21:05 -0400
committerGitHub <noreply@github.com>2023-10-25 09:21:05 -0400
commit46e6d920db1a9393adaa9eb79cb57ecac96b0e3a (patch)
treeb803c2fe4fb033cb2b4044532763a227875aa418
parent7e98e106635bb799f723ad37d94dd23809621c1e (diff)
parent4920ed6b2f2840982607fe28d1bd475302a30c12 (diff)
Merge pull request #61 from mgajda/michal/asymptote-support
Support Asymptote diagrams
-rw-r--r--.github/workflows/ci.yml23
-rw-r--r--cabal.project2
-rw-r--r--pandoc-plot.cabal1
-rw-r--r--src/Text/Pandoc/Filter/Plot/Configuration.hs19
-rw-r--r--src/Text/Pandoc/Filter/Plot/Monad.hs7
-rw-r--r--src/Text/Pandoc/Filter/Plot/Monad/Types.hs3
-rw-r--r--src/Text/Pandoc/Filter/Plot/Renderers.hs8
-rw-r--r--src/Text/Pandoc/Filter/Plot/Renderers/Asymptote.hs50
-rw-r--r--src/Text/Pandoc/Filter/Plot/Renderers/GGPlot2.hs2
-rw-r--r--src/Text/Pandoc/Filter/Plot/Renderers/Matplotlib.hs2
-rw-r--r--tests/Common.hs36
-rw-r--r--tests/Main.hs2
-rw-r--r--tests/includes/asymptote.asy1
-rw-r--r--tests/issue55.md74
14 files changed, 213 insertions, 17 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 22fc5eb..c67e5ef 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -98,19 +98,23 @@ jobs:
run: |
Rscript -e "install.packages('ggplot2', repos='http://cran.rstudio.com/')"
- - name: Install Octave, Gnuplot, Graphviz, and PlantUML [Linux]
+ - name: Install Octave, Gnuplot, Graphviz, PlantUML, and Asymptote [Linux]
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get --quiet --yes install octave
sudo apt-get --quiet --yes install gnuplot
sudo apt-get --quiet --yes install graphviz
-
+ sudo apt-get --quiet --yes install asymptote
sudo apt-get --quiet --yes install plantuml
+ echo $(dot -version</dev/null)
+ echo $(asy --version)
+ echo $(asy --environment)
echo $(plantuml -version)
# The ubuntu package version is too old
sudo curl -L "http://sourceforge.net/projects/plantuml/files/plantuml.jar/download" -o "/usr/share/plantuml/plantuml.jar"
echo $(plantuml -version)
+ echo $PATH
- name: Install Graphviz, GNUplot, and PlantUML [Windows]
if: runner.os == 'Windows'
@@ -120,6 +124,14 @@ jobs:
dot -c
choco install --yes --no-progress gnuplot
+ #refreshenv
+ #gnuplot --version
+
+ choco install --yes --no-progress asymptote
+ #refreshenv
+ #asy -version
+ #asy -environment
+
choco install --yes --no-progress plantuml
plantuml -h
@@ -127,6 +139,7 @@ jobs:
if: runner.os == 'macOS'
run: |
brew update
+ brew install asymptote
brew install octave
brew install gnuplot
brew install graphviz
@@ -202,6 +215,12 @@ jobs:
exit 1
fi
pandoc-plot clean tests/issue53.md
+
+ pandoc --filter pandoc-plot -i tests/issue55.md -t native
+ if [ $(ls "plots" | wc -l) != 2 ]; then
+ exit 1
+ fi
+ pandoc-plot clean tests/issue55.md
- name: Build documentation
run: source tools/mkmanual.sh
diff --git a/cabal.project b/cabal.project
index 4d6021c..2a5e7ae 100644
--- a/cabal.project
+++ b/cabal.project
@@ -4,4 +4,4 @@ test-show-details: streaming
jobs: $ncpus
-allow-newer: haddock-library:base, \ No newline at end of file
+allow-newer: haddock-library:base,
diff --git a/pandoc-plot.cabal b/pandoc-plot.cabal
index da5052f..5e9af62 100644
--- a/pandoc-plot.cabal
+++ b/pandoc-plot.cabal
@@ -82,6 +82,7 @@ library
Text.Pandoc.Filter.Plot.Renderers.PlantUML
Text.Pandoc.Filter.Plot.Renderers.SageMath
Text.Pandoc.Filter.Plot.Renderers.D2
+ Text.Pandoc.Filter.Plot.Renderers.Asymptote
Text.Pandoc.Filter.Plot.Monad
Text.Pandoc.Filter.Plot.Monad.Logging
Text.Pandoc.Filter.Plot.Monad.Types
diff --git a/src/Text/Pandoc/Filter/Plot/Configuration.hs b/src/Text/Pandoc/Filter/Plot/Configuration.hs
index e7d6113..c399986 100644
--- a/src/Text/Pandoc/Filter/Plot/Configuration.hs
+++ b/src/Text/Pandoc/Filter/Plot/Configuration.hs
@@ -65,6 +65,7 @@ defaultConfiguration =
plantumlPreamble = mempty,
sagemathPreamble = mempty,
d2Preamble = mempty,
+ asyPreamble = mempty,
-- Executables
matplotlibExe = python,
matlabExe = "matlab",
@@ -80,6 +81,7 @@ defaultConfiguration =
plantumlExe = "java",
sagemathExe = "sage",
d2Exe = "d2",
+ asyExe = "asy",
-- Command line arguments
matplotlibCmdArgs = mempty,
matlabCmdArgs = mempty,
@@ -95,6 +97,7 @@ defaultConfiguration =
plantumlCmdArgs = "-jar plantuml.jar",
sagemathCmdArgs = mempty,
d2CmdArgs = mempty,
+ asyCmdArgs = mempty,
-- Extras
matplotlibTightBBox = False,
matplotlibTransparent = False
@@ -155,7 +158,8 @@ data ConfigPrecursor = ConfigPrecursor
_plotsjlPrec :: !PlotsjlPrecursor,
_plantumlPrec :: !PlantUMLPrecursor,
_sagemathPrec :: !SageMathPrecursor,
- _d2Prec :: !D2Precursor
+ _d2Prec :: !D2Precursor,
+ _asyPrec :: !AsyPrecursor
}
defaultConfigPrecursor :: ConfigPrecursor
@@ -183,7 +187,8 @@ defaultConfigPrecursor =
_plotsjlPrec = PlotsjlPrecursor Nothing (plotsjlExe defaultConfiguration) (plotsjlCmdArgs defaultConfiguration),
_plantumlPrec = PlantUMLPrecursor Nothing (plantumlExe defaultConfiguration) (plantumlCmdArgs defaultConfiguration),
_sagemathPrec = SageMathPrecursor Nothing (sagemathExe defaultConfiguration) (sagemathCmdArgs defaultConfiguration),
- _d2Prec = D2Precursor Nothing (d2Exe defaultConfiguration) (d2CmdArgs defaultConfiguration)
+ _d2Prec = D2Precursor Nothing (d2Exe defaultConfiguration) (d2CmdArgs defaultConfiguration),
+ _asyPrec = AsyPrecursor Nothing (asyExe defaultConfiguration) (asyCmdArgs defaultConfiguration)
}
data LoggingPrecursor = LoggingPrecursor
@@ -226,6 +231,8 @@ data SageMathPrecursor = SageMathPrecursor {_sagemathPreamble :: !(Maybe FilePat
data D2Precursor = D2Precursor {_d2Preamble :: !(Maybe FilePath), _d2Exe :: !FilePath, _d2CmdArgs :: !Text}
+data AsyPrecursor = AsyPrecursor {_asyPreamble :: !(Maybe FilePath), _asyExe :: !FilePath, _asyCmdArgs :: !Text}
+
instance FromJSON LoggingPrecursor where
parseJSON (Object v) =
LoggingPrecursor
@@ -298,6 +305,10 @@ instance FromJSON D2Precursor where
parseJSON (Object v) = D2Precursor <$> v .:? asKey PreambleK <*> v .:? asKey ExecutableK .!= d2Exe defaultConfiguration <*> v .:? asKey CommandLineArgsK .!= d2CmdArgs defaultConfiguration
parseJSON _ = fail $ mconcat ["Could not parse ", show SageMath, " configuration."]
+instance FromJSON AsyPrecursor where
+ parseJSON (Object v) = AsyPrecursor <$> v .:? asKey PreambleK <*> v .:? asKey ExecutableK .!= asyExe defaultConfiguration <*> v .:? asKey CommandLineArgsK .!= asyCmdArgs defaultConfiguration
+ parseJSON _ = fail $ mconcat ["Could not parse ", show Asymptote, " configuration."]
+
toolkitAsKey :: Toolkit -> Key
toolkitAsKey = fromString . unpack . cls
@@ -328,6 +339,7 @@ instance FromJSON ConfigPrecursor where
_plantumlPrec <- v .:? toolkitAsKey PlantUML .!= _plantumlPrec defaultConfigPrecursor
_sagemathPrec <- v .:? toolkitAsKey SageMath .!= _sagemathPrec defaultConfigPrecursor
_d2Prec <- v .:? toolkitAsKey D2 .!= _d2Prec defaultConfigPrecursor
+ _asyPrec <- v .:? toolkitAsKey Asymptote .!= _asyPrec defaultConfigPrecursor
return $ ConfigPrecursor {..}
parseJSON _ = fail "Could not parse configuration."
@@ -363,6 +375,7 @@ renderConfig ConfigPrecursor {..} = do
plantumlExe = _plantumlExe _plantumlPrec
sagemathExe = _sagemathExe _sagemathPrec
d2Exe = _d2Exe _d2Prec
+ asyExe = _asyExe _asyPrec
matplotlibCmdArgs = _matplotlibCmdArgs _matplotlibPrec
matlabCmdArgs = _matlabCmdArgs _matlabPrec
@@ -378,6 +391,7 @@ renderConfig ConfigPrecursor {..} = do
plantumlCmdArgs = _plantumlCmdArgs _plantumlPrec
sagemathCmdArgs = _sagemathCmdArgs _sagemathPrec
d2CmdArgs = _d2CmdArgs _d2Prec
+ asyCmdArgs = _asyCmdArgs _asyPrec
matplotlibPreamble <- readPreamble (_matplotlibPreamble _matplotlibPrec)
matlabPreamble <- readPreamble (_matlabPreamble _matlabPrec)
@@ -393,6 +407,7 @@ renderConfig ConfigPrecursor {..} = do
plantumlPreamble <- readPreamble (_plantumlPreamble _plantumlPrec)
sagemathPreamble <- readPreamble (_sagemathPreamble _sagemathPrec)
d2Preamble <- readPreamble (_d2Preamble _d2Prec)
+ asyPreamble <- readPreamble (_asyPreamble _asyPrec)
return Configuration {..}
where
diff --git a/src/Text/Pandoc/Filter/Plot/Monad.hs b/src/Text/Pandoc/Filter/Plot/Monad.hs
index 66f87a7..ed5b607 100644
--- a/src/Text/Pandoc/Filter/Plot/Monad.hs
+++ b/src/Text/Pandoc/Filter/Plot/Monad.hs
@@ -283,6 +283,7 @@ executable tk = exeSelector tk <&> exeFromPath
exeSelector PlantUML = asksConfig plantumlExe
exeSelector SageMath = asksConfig sagemathExe
exeSelector D2 = asksConfig d2Exe
+ exeSelector Asymptote = asksConfig asyExe
-- | The @Configuration@ type holds the default values to use
-- when running pandoc-plot. These values can be overridden in code blocks.
@@ -353,6 +354,8 @@ data Configuration = Configuration
sagemathPreamble :: !Script,
-- | The default preamble script for the d2 toolkit.
d2Preamble :: !Script,
+ -- | The default preamble script for the Asymptote toolkit.
+ asyPreamble :: !Script,
-- | The executable to use to generate figures using the matplotlib toolkit.
matplotlibExe :: !FilePath,
-- | The executable to use to generate figures using the MATLAB toolkit.
@@ -381,6 +384,8 @@ data Configuration = Configuration
sagemathExe :: !FilePath,
-- | The executable to use to generate figures using d2.
d2Exe :: !FilePath,
+ -- | The executable to use to generate figures using Asymptote
+ asyExe :: !FilePath,
-- | Command-line arguments to pass to the Python interpreter for the Matplotlib toolkit
matplotlibCmdArgs :: !Text,
-- | Command-line arguments to pass to the interpreter for the MATLAB toolkit.
@@ -409,6 +414,8 @@ data Configuration = Configuration
sagemathCmdArgs :: !Text,
-- | Command-line arguments to pass to the interpreter for the d2 toolkit.
d2CmdArgs :: !Text,
+ -- | Command-line arguments to pass to the interpreter for the Asymptote toolkit.
+ asyCmdArgs :: !Text,
-- | Whether or not to make Matplotlib figures tight by default.
matplotlibTightBBox :: !Bool,
-- | Whether or not to make Matplotlib figures transparent by default.
diff --git a/src/Text/Pandoc/Filter/Plot/Monad/Types.hs b/src/Text/Pandoc/Filter/Plot/Monad/Types.hs
index f06b300..003c827 100644
--- a/src/Text/Pandoc/Filter/Plot/Monad/Types.hs
+++ b/src/Text/Pandoc/Filter/Plot/Monad/Types.hs
@@ -62,6 +62,7 @@ data Toolkit
| PlantUML
| SageMath
| D2
+ | Asymptote
deriving (Bounded, Eq, Enum, Generic, Ord)
-- | This instance should only be used to display toolkit names
@@ -80,6 +81,7 @@ instance Show Toolkit where
show PlantUML = "PlantUML"
show SageMath = "SageMath"
show D2 = "D2"
+ show Asymptote = "Asymptote"
-- | Class name which will trigger the filter
cls :: Toolkit -> Text
@@ -97,6 +99,7 @@ cls Plotsjl = "plotsjl"
cls PlantUML = "plantuml"
cls SageMath = "sageplot"
cls D2 = "d2"
+cls Asymptote = "asy"
-- | Executable program, and sometimes the directory where it can be found.
data Executable
diff --git a/src/Text/Pandoc/Filter/Plot/Renderers.hs b/src/Text/Pandoc/Filter/Plot/Renderers.hs
index e727c10..5fca78b 100644
--- a/src/Text/Pandoc/Filter/Plot/Renderers.hs
+++ b/src/Text/Pandoc/Filter/Plot/Renderers.hs
@@ -95,7 +95,10 @@ import Text.Pandoc.Filter.Plot.Renderers.SageMath
( sagemath,
sagemathSupportedSaveFormats,
)
-
+import Text.Pandoc.Filter.Plot.Renderers.Asymptote
+ ( asymptote,
+ asymptoteSupportedSaveFormats,
+ )
-- | Get the renderer associated with a toolkit.
-- If the renderer has not been used before,
-- initialize it and store where it is. It will be re-used.
@@ -114,6 +117,7 @@ renderer Plotsjl = plotsjl
renderer PlantUML = plantuml
renderer SageMath = sagemath
renderer D2 = d2
+renderer Asymptote = asymptote
-- | Save formats supported by this renderer.
supportedSaveFormats :: Toolkit -> [SaveFormat]
@@ -131,6 +135,7 @@ supportedSaveFormats Plotsjl = plotsjlSupportedSaveFormats
supportedSaveFormats PlantUML = plantumlSupportedSaveFormats
supportedSaveFormats SageMath = sagemathSupportedSaveFormats
supportedSaveFormats D2 = d2SupportedSaveFormats
+supportedSaveFormats Asymptote = asymptoteSupportedSaveFormats
-- | The function that maps from configuration to the preamble.
preambleSelector :: Toolkit -> (Configuration -> Script)
@@ -148,6 +153,7 @@ preambleSelector Plotsjl = plotsjlPreamble
preambleSelector PlantUML = plantumlPreamble
preambleSelector SageMath = sagemathPreamble
preambleSelector D2 = d2Preamble
+preambleSelector Asymptote = asyPreamble
-- | Parse code block headers for extra attributes that are specific
-- to this renderer. By default, no extra attributes are parsed.
diff --git a/src/Text/Pandoc/Filter/Plot/Renderers/Asymptote.hs b/src/Text/Pandoc/Filter/Plot/Renderers/Asymptote.hs
new file mode 100644
index 0000000..6356054
--- /dev/null
+++ b/src/Text/Pandoc/Filter/Plot/Renderers/Asymptote.hs
@@ -0,0 +1,50 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+-- |
+-- Module : $header$
+-- Copyright : (c) Laurent P René de Cotret, 2019 - present
+-- License : GNU GPL, version 2 or above
+-- Maintainer : laurent.decotret@outlook.com
+-- Stability : internal
+-- Portability : portable
+--
+-- Rendering Asymptote plots code blocks
+module Text.Pandoc.Filter.Plot.Renderers.Asymptote
+ ( asymptote,
+ asymptoteSupportedSaveFormats,
+ )
+where
+
+import Text.Pandoc.Filter.Plot.Renderers.Prelude
+import Data.Char(toLower)
+
+asymptote :: PlotM Renderer
+asymptote = do
+ cmdargs <- asksConfig asyCmdArgs
+ return
+ $ Renderer
+ { rendererToolkit = Asymptote,
+ rendererCapture = asymptoteCapture,
+ rendererCommand = asymptoteCommand cmdargs,
+ rendererAvailability = CommandSuccess $ \exe -> [st|#{pathToExe exe} -environment|],
+ rendererSupportedSaveFormats = asymptoteSupportedSaveFormats,
+ rendererChecks = mempty,
+ rendererLanguage = "asy",
+ rendererComment = mappend "// ",
+ rendererScriptExtension = ".asy"
+ }
+
+asymptoteSupportedSaveFormats :: [SaveFormat]
+asymptoteSupportedSaveFormats = [PDF, EPS, PNG]
+
+asymptoteCommand :: Text -> OutputSpec -> Text
+asymptoteCommand cmdArgs OutputSpec {..} =
+ [st|#{pathToExe oExecutable} #{cmdArgs} -f #{toLower <$> show (saveFormat oFigureSpec)} -o "#{oFigurePath}" "#{oScriptPath}"|]
+
+-- Asymptote export is entirely based on command-line arguments
+-- so there is no need to modify the script itself.
+asymptoteCapture :: FigureSpec -> FilePath -> Script
+asymptoteCapture FigureSpec {..} _ = script
diff --git a/src/Text/Pandoc/Filter/Plot/Renderers/GGPlot2.hs b/src/Text/Pandoc/Filter/Plot/Renderers/GGPlot2.hs
index b2855bc..2039aa1 100644
--- a/src/Text/Pandoc/Filter/Plot/Renderers/GGPlot2.hs
+++ b/src/Text/Pandoc/Filter/Plot/Renderers/GGPlot2.hs
@@ -38,7 +38,7 @@ ggplot2 = do
}
ggplot2SupportedSaveFormats :: [SaveFormat]
-ggplot2SupportedSaveFormats = [PNG, PDF, SVG, JPG, EPS, TIF]
+ggplot2SupportedSaveFormats = [PNG, PDF, SVG, JPG, EPS]
ggplot2Command :: Text -> OutputSpec -> Text
ggplot2Command cmdargs OutputSpec {..} = [st|#{pathToExe oExecutable} #{cmdargs} "#{oScriptPath}"|]
diff --git a/src/Text/Pandoc/Filter/Plot/Renderers/Matplotlib.hs b/src/Text/Pandoc/Filter/Plot/Renderers/Matplotlib.hs
index ce74429..760e55b 100644
--- a/src/Text/Pandoc/Filter/Plot/Renderers/Matplotlib.hs
+++ b/src/Text/Pandoc/Filter/Plot/Renderers/Matplotlib.hs
@@ -44,7 +44,7 @@ matplotlib = do
}
matplotlibSupportedSaveFormats :: [SaveFormat]
-matplotlibSupportedSaveFormats = [PNG, PDF, SVG, JPG, EPS, GIF, TIF]
+matplotlibSupportedSaveFormats = [PNG, PDF, SVG, JPG, EPS, TIF]
matplotlibCommand :: Text -> OutputSpec -> Text
matplotlibCommand cmdargs OutputSpec {..} = [st|#{pathToExe oExecutable} #{cmdargs} "#{oScriptPath}"|]
diff --git a/tests/Common.hs b/tests/Common.hs
index 6d32a7c..3a14e80 100644
--- a/tests/Common.hs
+++ b/tests/Common.hs
@@ -3,8 +3,8 @@
module Common where
-import Control.Monad (unless, when)
-import Data.List (isInfixOf, isSuffixOf, (!!))
+import Control.Monad (unless, when, forM)
+import Data.List (isInfixOf, isSuffixOf, (!!), (\\))
import Data.Monoid ((<>))
import qualified Data.Set as S
import Data.String (fromString)
@@ -33,7 +33,8 @@ defaultTestConfig :: Configuration
defaultTestConfig =
defaultConfiguration
{ logVerbosity = Silent,
- logSink = StdErr
+ logSink = StdErr,
+ defaultSaveFormat = PNG
}
-------------------------------------------------------------------------------
@@ -121,17 +122,35 @@ testFileInclusion tk =
include PlantUML = "tests/includes/plantuml.txt"
include SageMath = "tests/includes/sagemath.sage"
include D2 = "tests/includes/d2-dd.d2"
+ include Asymptote = "tests/includes/asymptote.asy"
+
+-------------------------------------------------------------------------------
+-- Tests that the files are saved in all the advertised formats
+testAllSaveFormats :: Toolkit -> TestTree
+-- Correct formats unsupported on CI.
+-- TODO: change when CI support improves
+testAllSaveFormats tk@Graphviz =
+ testGroup "advertised save formats that work on CI"
+ (testSaveFormat tk <$> (supportedSaveFormats tk \\ [WEBP]))
+testAllSaveFormats tk@Matlab =
+ testGroup "advertised save formats that work on CI"
+ (testSaveFormat tk <$> (supportedSaveFormats tk \\ [SVG]))
+testAllSaveFormats tk@GGPlot2 =
+ testGroup "advertised save formats that work on CI"
+ (testSaveFormat tk <$> (supportedSaveFormats tk \\ [SVG]))
+-- All other formats:
+testAllSaveFormats tk =
+ testGroup "advertised output formats" (testSaveFormat tk <$> supportedSaveFormats tk)
-------------------------------------------------------------------------------
-- Test that the files are saved in the appropriate format
-testSaveFormat :: Toolkit -> TestTree
-testSaveFormat tk =
- testCase "saves in the appropriate format" $ do
+testSaveFormat :: Toolkit -> SaveFormat -> TestTree
+testSaveFormat tk fmt =
+ testCase ("saves in the appropriate format (" <> show fmt <> ")") $ do
let postfix = unpack . cls $ tk
tempDir <- (</> "test-safe-format-" <> postfix) <$> getTemporaryDirectory
ensureDirectoryExistsAndEmpty tempDir
- let fmt = head (supportedSaveFormats tk)
- cb =
+ let cb =
( addSaveFormat fmt $
addDirectory tempDir $
codeBlock tk (trivialContent tk)
@@ -403,6 +422,7 @@ trivialContent Plotsjl = "using Plots; x = 1:10; y = rand(10); plot(x, y);"
trivialContent PlantUML = "@startuml\nAlice -> Bob: test\n@enduml"
trivialContent SageMath = "G = plot(sin, 1, 10)"
trivialContent D2 = "x -> y -> z"
+trivialContent Asymptote = "draw((0,0)--(1,0));"
addCaption :: String -> Block -> Block
addCaption caption (CodeBlock (id', cls, attrs) script) =
diff --git a/tests/Main.hs b/tests/Main.hs
index 4b66177..09abdd8 100644
--- a/tests/Main.hs
+++ b/tests/Main.hs
@@ -51,7 +51,7 @@ toolkitSuite tk =
testFileCreationPathWithSpaces,
testNestedCodeBlocks,
testFileInclusion,
- testSaveFormat,
+ testAllSaveFormats,
testSaveFormatIncompatibility,
testWithSource,
testSourceLabel,
diff --git a/tests/includes/asymptote.asy b/tests/includes/asymptote.asy
new file mode 100644
index 0000000..305a9e8
--- /dev/null
+++ b/tests/includes/asymptote.asy
@@ -0,0 +1 @@
+// This is comment in Asymptote
diff --git a/tests/issue55.md b/tests/issue55.md
new file mode 100644
index 0000000..8810eff
--- /dev/null
+++ b/tests/issue55.md
@@ -0,0 +1,74 @@
+---
+plot-configuration: tests/fixtures/.verbose-config.yml
+---
+
+# Example Asymptote plot
+
+```{.asy}
+
+// This example was taken from Asymptote's gallery
+import graph;
+
+size(9cm,8cm,IgnoreAspect);
+string data="westnile.csv";
+
+file in=input(data).line().csv();
+
+string[] columnlabel=in;
+
+real[][] A=in;
+A=transpose(A);
+real[] number=A[0], survival=A[1];
+
+path g=graph(number,survival);
+draw(g);
+
+scale(true);
+
+xaxis("Initial no.\ of mosquitoes per bird ($S_{M_0}/N_{B_0}$)",
+ Bottom,LeftTicks);
+xaxis(Top);
+yaxis("Susceptible bird survival",Left,RightTicks(trailingzero));
+yaxis(Right);
+
+real a=number[0];
+real b=number[number.length-1];
+
+real S1=0.475;
+path h1=(a,S1)--(b,S1);
+real M1=interp(a,b,intersect(h1,g)[0]);
+
+real S2=0.9;
+path h2=(a,S2)--(b,S2);
+real M2=interp(a,b,intersect(h2,g)[0]);
+
+labelx("$M_1$",M1);
+labelx("$M_2$",M2);
+
+draw((a,S2)--(M2,S2)--(M2,0),Dotted);
+draw((a,S1)--(M1,S1)--(M1,0),dashed);
+
+pen p=fontsize(10pt);
+
+real y3=0.043;
+path reduction=(M1,y3)--(M2,y3);
+draw(reduction,Arrow,TrueMargin(0,0.5*(linewidth(Dotted)+linewidth())));
+
+arrow(shift(-20,5)*Label(minipage("\flushleft{\begin{itemize}\item[1.]
+Estimate proportion of birds surviving at end of season\end{itemize}}",100),
+ align=NNE),
+ (M1,S1),NNE,1cm,p,Arrow(NoFill));
+
+arrow(shift(-24,5)*Label(minipage("\flushleft{\begin{itemize}\item[2.]
+Read off initial mosquito abundance\end{itemize}}",80),align=NNE),
+ (M1,0),NE,2cm,p,Arrow(NoFill));
+
+arrow(shift(20,0)*Label(minipage("\flushleft{\begin{itemize}\item[3.]
+Determine desired bird survival for next season\end{itemize}}",90),align=SW),
+ (M2,S2),SW,arrowlength,p,Arrow(NoFill));
+
+arrow(shift(8,-15)*Label(minipage("\flushleft{\begin{itemize}\item[4.]
+Calculate required proportional reduction in mosquitoes\end{itemize}}",90),
+ align=NW),
+ point(reduction,0.5),NW,1.5cm,p,Arrow(NoFill));
+```