Graphviz diagrams inline with Pollen #46

Open
opened 4 years ago by nixin72 · 7 comments
nixin72 commented 4 years ago (Migrated from github.com)

One thing that I've wanted out of Markdown for a really long time is the ability to draw graphviz diagrams inline with my Markdown code. Now, this isn't going to happen with Markdown, so I just draw my diagrams in graphviz and include the images normally, but this becomes a huge pain when I'm answering answering assignment questions and naming my files something like q5-c.dot and trying to keep track of over a dozen of them. But Racket has a Graphviz library, so I was thinking if it might be possible to achieve this with Pollen.

What I want to be able to do something like:

#lang pollen
(require graphviz)

this is some text 

; Or something like this I guess
(include-graph (make-diagraph `(some code for the graphviz library)))

some more text after a picture of my FSM

I was wondering if this would work by first getting graphviz to generate the image and dump into into a temp file in a bin directory or something, then link to the image with an img tag or with whatever rendering strategy it's trying to use.

Is this something that Pollen can already do? I didn't read anything about it in the tutorials. If not, is it something you'd consider including?

One thing that I've wanted out of Markdown for a really long time is the ability to draw graphviz diagrams inline with my Markdown code. Now, this isn't going to happen with Markdown, so I just draw my diagrams in graphviz and include the images normally, but this becomes a huge pain when I'm answering answering assignment questions and naming my files something like `q5-c.dot` and trying to keep track of over a dozen of them. But Racket has a [Graphviz](https://docs.racket-lang.org/graphviz/index.html) library, so I was thinking if it might be possible to achieve this with Pollen. What I want to be able to do something like: ```racket #lang pollen ◊(require graphviz) this is some text ; Or something like this I guess ◊(include-graph (make-diagraph `(some code for the graphviz library))) some more text after a picture of my FSM ``` I was wondering if this would work by first getting graphviz to generate the image and dump into into a temp file in a bin directory or something, then link to the image with an img tag or with whatever rendering strategy it's trying to use. Is this something that Pollen can already do? I didn't read anything about it in the tutorials. If not, is it something you'd consider including?
sorawee commented 4 years ago (Migrated from github.com)

This is easily doable. In your pollen.rkt, create include-digraph as follows:

#lang racket

(require graphviz)
(provide (all-defined-out))

(define (include-digraph name digraph
                         #:ext [ext 'png]
                         #:tag [tag (λ (x) `(image ,x))]
                         #:dir [dir "images"])
  (make-directory* dir)
  (define path (build-path dir (~a name (equal-hash-code digraph) "." ext)))
  (unless (file-exists? path)
    (send (pict->bitmap (digraph->pict (make-digraph digraph))) save-file path ext))
  (tag (path->string path)))

This renders a digraph into an image file if it doesn't exist already, and then returns its path wrapped with tag.

Then, the Pollen program:

#lang pollen

this is some text

◊(include-digraph "first-diagram" 
                  `("v0" "v1" "v2" "v0 -> v0" "v0 -> v1" "v1 -> v2" "v2 -> v0") 
                  #:tag (λ (img-path) `(img ([src ,img-path]))))

some more text after a picture of my FSM

would produce

'(root
  "this is some text"
  "\n"
  "\n"
  (img ((src "images/first-diagram-1065713455284007950.png")))
  "\n"
  "\n"
  "some more text after a picture of my FSM")

The 1065713455284007950 is a (practically) unique identity of your digraph, so if you modify your digraph, it would render your digraph again. But if you make no changes to your digraph, it will reuse the existing file.

This is easily doable. In your `pollen.rkt`, create `include-digraph` as follows: ``` #lang racket (require graphviz) (provide (all-defined-out)) (define (include-digraph name digraph #:ext [ext 'png] #:tag [tag (λ (x) `(image ,x))] #:dir [dir "images"]) (make-directory* dir) (define path (build-path dir (~a name (equal-hash-code digraph) "." ext))) (unless (file-exists? path) (send (pict->bitmap (digraph->pict (make-digraph digraph))) save-file path ext)) (tag (path->string path))) ``` This renders a digraph into an image file if it doesn't exist already, and then returns its path wrapped with `tag`. Then, the Pollen program: ``` #lang pollen this is some text ◊(include-digraph "first-diagram" `("v0" "v1" "v2" "v0 -> v0" "v0 -> v1" "v1 -> v2" "v2 -> v0") #:tag (λ (img-path) `(img ([src ,img-path])))) some more text after a picture of my FSM ``` would produce ``` '(root "this is some text" "\n" "\n" (img ((src "images/first-diagram-1065713455284007950.png"))) "\n" "\n" "some more text after a picture of my FSM") ``` The `1065713455284007950` is a (practically) unique identity of your digraph, so if you modify your digraph, it would render your digraph again. But if you make no changes to your digraph, it will reuse the existing file.
mbutterick commented 4 years ago (Migrated from github.com)

The {···} notation will produce a list of strings, so it would also be possible to write the tag function to directly support (some subset of) DOT input:

#lang pollen

this is some text

◊include-digraph{
v0;
v1;
v2;
v0 -> v0;
v0 -> v1;
v1 -> v2;
v2 -> v0;
} 
 
some more text after a picture of my FSM
The `{···}` notation will produce a list of strings, so it would also be possible to write the tag function to directly support (some subset of) DOT input: ``` #lang pollen this is some text ◊include-digraph{ v0; v1; v2; v0 -> v0; v0 -> v1; v1 -> v2; v2 -> v0; } some more text after a picture of my FSM ```
nixin72 commented 4 years ago (Migrated from github.com)

Thank you so much! I'm pretty sure Pollen is going to become my go-to tool from now on for writing, I can't believe it's that easy to extend to include something like this!

Thank you so much! I'm pretty sure Pollen is going to become my go-to tool from now on for writing, I can't believe it's that easy to extend to include something like this!
sorawee commented 4 years ago (Migrated from github.com)

Note: my code above will create a lot of junk files if you modify the digraph several times. One easy improvement is to read the file images/first-digraph.data and compare it against your digraph. If they match, then skip rendering, but if it doesn't match, then update both images/first-digraph.data and images/first-digraph.png. I guess the main point is that you have a full power of programming here, so you can do whatever you want :)

Note: my code above will create a lot of junk files if you modify the digraph several times. One easy improvement is to read the file `images/first-digraph.data` and compare it against your digraph. If they match, then skip rendering, but if it doesn't match, then update both `images/first-digraph.data` and `images/first-digraph.png`. I guess the main point is that you have a full power of programming here, so you can do whatever you want :)
mbutterick commented 4 years ago (Migrated from github.com)

PS. You say mixing diagrams inline with Markdown “isn't going to happen” but watch this final trick. You can use the #lang pollen/markdown dialect and write in Markdown normally. When you get to the include-digraph tag function, you’d need it to emit valid Markdown (instead of an X-expression, as it does now). But arbitrary HTML is valid inside a Markdown doc. So just run the output of your tag function through xexpr->html and your dream comes true.

PS. You say mixing diagrams inline with Markdown “isn't going to happen” but watch this final trick. You can use the `#lang pollen/markdown` dialect and write in Markdown normally. When you get to the `include-digraph` tag function, you’d need it to emit valid Markdown (instead of an X-expression, as it does now). But arbitrary HTML is valid inside a Markdown doc. So just run the output of your tag function through `xexpr->html` and your dream comes true.
nixin72 commented 4 years ago (Migrated from github.com)

😮

This is so cool... Thank you so much @mbutterick and @sorawee!

:open_mouth: This is so cool... Thank you so much @mbutterick and @sorawee!
shriram commented 4 years ago (Migrated from github.com)

Looks like y'all have solutions, so I don't want to confuse things further, but for people looking to do more visual/graphical content inside Markdown (acknowledging how @mbutterick feels about Markdown <-:), there's Markdeep: https://casual-effects.com/markdeep/.

I don't know what it would take to incorporate into Pollen, but at least Markdeep offers something of real value, especially for diagrams, well beyond the thin veneer over HTML that Markdown is.

Looks like y'all have solutions, so I don't want to confuse things further, but for people looking to do more visual/graphical content inside Markdown (acknowledging how @mbutterick feels about Markdown <-:), there's Markdeep: https://casual-effects.com/markdeep/. I don't know what it would take to incorporate into Pollen, but at least Markdeep offers something of real value, especially for diagrams, well beyond the thin veneer over HTML that Markdown is.
This repo is archived. You cannot comment on issues.
No Milestone
No project
No Assignees
1 Participants
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: mbutterick/pollen-users#46
Loading…
There is no content yet.