I wrote a Block extension (code is below) that converts pyplot instructions to plots inserted into the document.
Problems:
Bernhard Code:
|
Administrator
|
@ttmetro, Whenever you create an image block via the API, you must specify the target using the target attribute. The target is the path that is used in the src attribute of the <img> tag in the HTML output. For an example, see https://github.com/asciidoctor/asciidoctor-extensions-lab/blob/master/lib/mathematical-treeprocessor/extension.rb#L40 To run code after parsing is complete, you need to use a tree processor. When writing image files, it's best to follow what Asciidoctor Diagram does (since it also generates images to disk). This comes down to use the value of the imagesoutdir attribute if set, otherwise use the value of the to_dir option + imagesdir. See https://github.com/asciidoctor/asciidoctor-diagram/blob/master/lib/asciidoctor-diagram/extensions.rb#L245-L258 Cheers, -Dan On Mon, Sep 17, 2018 at 11:44 AM ttmetro [via Asciidoctor :: Discussion] <[hidden email]> wrote: I wrote a Block extension (code is below) that converts pyplot instructions to plots inserted into the document. Problems: -- Dan Allen | @mojavelinux | https://twitter.com/mojavelinux |
@mojavelinux,
Thank you very much for the response. My code (below) works now. The only part that does not is I don't get a Figure caption and number with the image. But I can live with that. Bernhard ``` require 'asciidoctor/extensions' unless RUBY_ENGINE == 'opal' include Asciidoctor # Inserts pyplot image. # # Usage # # [pyplot] # ---- # plot([1,2,3,4]) # title('pyplot test') # ---- # require 'asciidoctor/extensions' unless RUBY_ENGINE == 'opal' require 'date' include Asciidoctor # Create pyplot # # Usage (see pyplot.adoc) # # .Title of this pyplot # [pyplot] # ---- # def f(t): # return cos(2 * pi * t) * exp(-t) # t = linspace(0, 5, 500) # # plot(t, f(t)) # title("Damped exponential decay") # text(3, 0.15, r"$y = \cos(2 \pi t) e^{-t}$") # xlabel("Time [s]") # ylabel("Voltage [mV]") # ---- # # then run # python3 pyplot.py # class PyplotBlock < Extensions::BlockProcessor use_dsl named :pyplot on_context :listing parse_content_as :simple PY_FILE = "%s/pyplot.py" PL_FILE = "%s/figures/py_fig_%d.svg" @@counter = 0 # number of plot def process parent, reader, attrs base_dir = parent.document.base_dir attributes = parent.document.attributes prefix = attributes['pyplot_prefix'] || "clf(); figure(figsize=(5,4))" postfix = attributes['pyplot_postfix'] || "tight_layout()" pyfile = PY_FILE % base_dir if @@counter < 1 # create PY_FILE with header File.open(pyfile, 'w') do |fo| fo.puts "\# machine generated by PyplotBlock on #{DateTime.now}" fo.puts "from pylab import *" fo.puts "import os" fo.puts "rc('text', usetex=True)" fo.puts "os.makedirs(os.path.dirname('#{PL_FILE}'), exist_ok=True)" % [ base_dir, 0 ] end end @@counter += 1 attrs['target'] = PL_FILE % [ base_dir, @@counter ] attrs['numbered'] = true # wish this would label and number captions but doesn't ... File.open(pyfile, 'a') do |fo| fo.puts fo.puts "%s #{attrs['target']}: #{attrs['title']}" % ('#'*5) fo.puts prefix fo.puts reader.source_lines fo.puts postfix fo.puts "savefig('#{attrs['target']}')" end # puts "attrs = #{attrs}" create_image_block parent, attrs end # call this after parsing entire document # (renders plots) def at_end system("python3 #{PY_FILE}") end end Asciidoctor::Extensions.register do block PyplotBlock end ``` |
Administrator
|
That's great news! If you want a caption with a number, you need to create the block, then set the title property then call the assign_caption method. This assignment is not currently handled by the create_image_block function. img = create_image_block parent, { 'target' => 'foo.png' } img.title = 'Your Caption Here' img.assign_caption nil, 'figure' img It's a bit of a weird API, so perhaps it's something that could be improved. Feel free to open an issue. Cheers, -Dan On Thu, Oct 11, 2018 at 6:31 PM ttmetro [via Asciidoctor :: Discussion] <[hidden email]> wrote: @mojavelinux, -- Dan Allen | @mojavelinux | https://twitter.com/mojavelinux |
All works perfect now, thanks!
In the end, I prefer to run python manually when needed as it is much slower than document rendering. Below are the code and an example, in case someone else has a need. Extension to convert inline python code to plots:
Sample document:
|
Administrator
|
Super! Glad to help. Btw, instead of running the pyplot.py in a separate step, you could use either a TreeProcessor or a Postprocessor to run it as part of the conversion. It would still run at the end, but it would be integrated into the asciidoctor command. Cheers, -Dan On Fri, Oct 12, 2018 at 2:16 PM ttmetro [via Asciidoctor :: Discussion] <[hidden email]> wrote: All works perfect now, thanks! -- Dan Allen | @mojavelinux | https://twitter.com/mojavelinux |
That's what I wanted until I realized that the python step is much slower than formatting the adoc.
So I run python only occasionally when I've added a new plot, not to slow down the live view. Thanks, Bernhard |
Administrator
|
Bernhard, Ahhhh. Now I see what you are saying. In that case, 👍. Cheers, -Dan On Fri, Oct 12, 2018 at 4:56 PM ttmetro [via Asciidoctor :: Discussion] <[hidden email]> wrote: That's what I wanted until I realized that the python step is much slower than formatting the adoc. -- Dan Allen | @mojavelinux | https://twitter.com/mojavelinux |
Free forum by Nabble | Edit this page |