0

I would like to create a mermaid graph from nested map like this

{"a" {"b" {"c" nil
           "d" nil}}
 "e" {"c" nil
      "d" {"h" {"i" nil
                "j" nil}}}}

diagram

I think it should first convert nested map to this form. Then it should be easy.

[{:out-path "a" :out-name "a"
  :in-path  "a-b" :in-name "b"}
 {:out-path "a-b" :out-name "b"
  :in-path  "a-b-c" :in-name "c"}
 {:out-path "a-b" :out-name "b"
  :in-path  "a-b-d" :in-name "d"}
 {:out-path "e" :out-name "e"
  :in-path  "e-f" :in-name "f"}
 {:out-path "e" :out-name "e"
  :in-path  "e-c" :in-name "c"}
 {:out-path "e" :out-name "e"
  :in-path  "e-d" :in-name "d"}
 {:out-path "e-d" :out-name "d"
  :in-path  "e-d-h" :in-name "h"}
 {:out-path "e-d-h" :out-name "h"
  :in-path  "e-d-h-i" :in-name "i"}
 {:out-path "e-d-h" :out-name "h"
  :in-path  "e-d-h-j" :in-name "j"}]

EDIT:

This is what I have created. But I have absolutely no idea how to add path to result map.

(defn myfunc [m]
  (loop [in m out []]
    (let [[[k v] & ts] (seq in)]
      (if (keyword? k)
        (cond
          (map? v)
          (recur (concat v ts)
                 (reduce (fn [o k2]
                           (conj o {:out-name (name k)
                                    :in-name  (name k2)}))
                         out (keys v)))
          (nil? v)
          (recur (concat v ts) out))
        out))))
4
  • 1
    Do you need specific help with code that you have tried? Could you post that? Commented Jul 12, 2016 at 13:32
  • @Bill, I need help adding the "path" for each item. Commented Jul 12, 2016 at 13:51
  • Typically, you'd declare (let) the path of the current level into a variable, then add that to the structure you're building and then pass it down when you recurse to the next level and continue to build it. A multi-arity function might be easier to structure in this case rather than a loop. Commented Jul 12, 2016 at 14:11
  • should every entry of top level map be on separate graph, or all of them would be in one sheet? (if the latter is true, there would be intersections in them, unlike your picture) Commented Jul 12, 2016 at 14:50

1 Answer 1

1

as far as i can see by mermaid docs, to draw the graph it is enough to generate all the nodes in the form of "x-->y" pairs.

we could do that with some a simple recursive function (i believe there are not so many levels in a graph to worry about stack overflow):

(defn map->mermaid [items-map]
  (if (seq items-map)
    (mapcat (fn [[k v]] (concat 
                          (map (partial str k "-->") (keys v))
                          (map->mermaid v)))
      items-map)))

in repl:

user>
(map->mermaid {"a" {"b" {"c" nil
                         "d" nil}}
               "e" {"c" nil
                    "d" {"h" {"i" nil
                              "j" nil}}}})

;; ("a-->b" "b-->c" "b-->d" "e-->c" "e-->d" "d-->h" "h-->i" "h-->j")

so now you just have to make a graph of it like this:

(defn create-graph [items-map]
  (str "graph LR"
       \newline
       (clojure.string/join \newline (map->mermaid items-map))
       \newline))

update

you could use the same strategy for the actual map transformation, just passing the current path to map->mermaid:

(defn make-result-node [path name child-name]
  {:out-path path
   :out-name name
   :in-path (str path "-" child-name)
   :in-name child-name})

(defn map->mermaid
  ([items-map] (map->mermaid "" items-map))
  ([path items-map]
   (if (seq items-map)
     (mapcat (fn [[k v]]
               (let [new-path (if (seq path) (str path "-" k) k)]
                 (concat (map (partial make-result-node new-path k)
                              (keys v))
                         (map->mermaid new-path v))))
             items-map))))

in repl:

user> 
(map->mermaid {"a" {"b" {"c" nil
                         "d" nil}}
               "e" {"c" nil
                    "d" {"h" {"i" nil
                              "j" nil}}}})

;; ({:out-path "a", :out-name "a", :in-path "a-b", :in-name "b"} 
;;  {:out-path "a-b", :out-name "b", :in-path "a-b-c", :in-name "c"} 
;;  {:out-path "a-b", :out-name "b", :in-path "a-b-d", :in-name "d"} 
;;  {:out-path "e", :out-name "e", :in-path "e-c", :in-name "c"} 
;;  {:out-path "e", :out-name "e", :in-path "e-d", :in-name "d"} 
;;  {:out-path "e-d", :out-name "d", :in-path "e-d-h", :in-name "h"} 
;;  {:out-path "e-d-h", :out-name "h", :in-path "e-d-h-i", :in-name "i"} 
;;  {:out-path "e-d-h", :out-name "h", :in-path "e-d-h-j", :in-name "j"})
Sign up to request clarification or add additional context in comments.

3 Comments

I wrote something similar to you. The problem is when the keys is duplicated. Your result diagram look like this i.imgur.com/padT6h7.png
so.. then it would be nice to get an example of "mermaid" code, producing your desired diagram, i'm not really familiar with it..
or that picture of yours means two different diagram sheets?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.