LaurentRDC / pandoc-plot

Render and include figures in Pandoc documents using your plotting toolkit of choice
https://laurentrdc.github.io/pandoc-plot/
GNU General Public License v2.0
224 stars 8 forks source link

Inline SVG #23

Closed adamgordonbell closed 3 years ago

adamgordonbell commented 3 years ago

Great project. I am using pandoc to generate HTML from markdown for a Jekyll site and trying to use pandoc-plot with it.

It would be great if there was an option to inline SVG images into the HTML (or other formats that support it).

LaurentRDC commented 3 years ago

Hi Adam,

That's a good idea. You can already do this in markdown, because you can write HTML directly.

So a markdown file like this works:

# Title

<svg width="100" height="100">
  <circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />
</svg>

Is this what you meant?

adamgordonbell commented 3 years ago

I mean if I give this to pandoc (and pandoc_plot) and ask for html:

{
  .matplotlib
  format=SVG
  source=false
  }
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')

(in a code block in a markdown file)

Instead of this:

<figure>
<img src="plots/796308625745987558.svg" />
</figure>

I could get this html:

<figure>
<svg width="100" height="100">
  <circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />
....
</svg>
</figure>

Or whatever is in the SVG, inlined into the document in place of an image link.

LaurentRDC commented 3 years ago

Ahh yes I see.

That's what pandoc-plot is already doing for HTML "plots" in HTML documents, like the interactive bokeh example on the website.

I can add a special case that embeds SVG plots from any toolkit in HTML output.

LaurentRDC commented 3 years ago

I would have to break backwards compatibility to make pandoc-plot aware of the target format, unfortunately.

However, you can use the following python filter to embed SVG from files:

# embed-svg.py
from pandocfilters import toJSONFilter, Image, RawInline

def embed_svg(key, value, format, meta):
  if key == 'Image':
    attrs, caption, (url, title) = value
    if url.endswith('.svg'):
        svg_content = open(url, mode='r').read()
        return RawInline("html5", f"<svg>\n{svg_content}\n</svg>\n") # requires python 3.6 for f-strings

if __name__ == "__main__":
  toJSONFilter(embed_svg)

This example is made simpler by discarding the caption. Then you can use it as:

pandoc --filter pandoc-plot --filter embed-svg.py -i test.md -t ...

Note the order of filters!

adamgordonbell commented 3 years ago

I will try this, thanks! I didn't expect you to write scripts for me, but I appreciate it :)

adamgordonbell commented 3 years ago

This worked, thanks

LaurentRDC commented 3 years ago

Great, so I will close this for now.

In the future, when I think it's OK to break backwards compatibility, I'll add the option to do this from within pandoc-plot.