29 Membranes
The fourth stage of Plotje’s pipeline turns a fully-resolved plan into a PlotjeMembrane: a tree of layout-and-drawing primitives sized exactly for the output canvas, ready to be rendered to SVG, PNG, or any other format the Membrane library supports.
A PlotjeMembrane is itself a Membrane UI component. It implements the standard Membrane protocols (IOrigin, IBounds, IChildren), so any tool that consumes Membrane components consumes a Plotje plot without special-casing, and any Plotje plot can be composed into a larger Membrane interface alongside hand-built Membrane elements. This chapter walks the membrane stage end to end and shows that interop in action.
(ns plotje-book.membranes
(:require
;; Kindly notebook annotations
[scicloj.kindly.v4.kind :as kind]
;; Plotje, the public API
[scicloj.plotje.api :as pj]
;; Plotje's membrane impl namespace -- defines the schema and
;; the record class
[scicloj.plotje.impl.membrane :as plotje-mem]
;; Rdatasets for example data
[scicloj.metamorph.ml.rdatasets :as rdatasets]
;; Membrane core: protocols and primitives
[membrane.ui :as ui]))A running example
Throughout the chapter we lift one iris scatter into the membrane stage. The pose looks like:
(def iris-pose
(-> (rdatasets/datasets-iris)
(pj/lay-point :sepal-length :sepal-width
{:color :species})
(pj/options {:title "Iris" :y-label "width"})))iris-poseProducing a membrane
The composition shortcut pj/membrane runs the full pipeline up through the membrane stage in one call:
(def iris-membrane (pj/membrane iris-pose))(pj/membrane? iris-membrane)trueThe atomic step pj/plan->membrane does the same starting from an already-resolved plan – handy when you have a plan in hand from inspection and want to skip re-running the earlier stages:
(def iris-plan (pj/plan iris-pose))(pj/membrane? (pj/plan->membrane iris-plan))trueBoth routes return the same shape: a PlotjeMembrane record.
Anatomy
The record carries three structural fields plus optional :plotje/-namespaced attributes. The full value prints with every drawable in :drawables, so it is long, but every part is visible:
iris-membrane{:drawables
[{:x 270.25,
:y 14,
:drawable
{:color [0.2 0.2 0.2 1.0],
:drawables
({:text "Iris",
:font {:name nil, :size 15, :weight nil, :width nil, :slant nil},
:text-anchor "middle"})}}
{:x 12,
:y 197.5,
:drawable
{:degrees -90,
:drawable
{:color [0.2 0.2 0.2 1.0],
:drawables
({:text "width",
:font
{:name nil, :size 13, :weight nil, :width nil, :slant nil},
:text-anchor "middle"})}}}
{:x 270.25,
:y 382.0,
:drawable
{:color [0.2 0.2 0.2 1.0],
:drawables
({:text "sepal length",
:font {:name nil, :size 13, :weight nil, :width nil, :slant nil},
:text-anchor "middle"})}}
{:x 508.0,
:y 35,
:drawable
{:color [0.2 0.2 0.2 1.0],
:drawables
({:text "species",
:font
{:name nil, :size 11, :weight nil, :width nil, :slant nil}})}}
{:x 508.0,
:y 53,
:drawable
[{:x 0,
:y 0,
:drawable
{:color
[0.8941176470588236 0.10196078431372549 0.10980392156862745 1.0],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 8, :height 8, :border-radius 4.0}]})}}
{:x 12,
:y 0,
:drawable
{:color [0.2 0.2 0.2 1.0],
:drawables
({:text "setosa",
:font
{:name nil,
:size 10,
:weight nil,
:width nil,
:slant nil}})}}]}
{:x 508.0,
:y 69,
:drawable
[{:x 0,
:y 0,
:drawable
{:color
[0.21568627450980393 0.49411764705882355 0.7215686274509804 1.0],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 8, :height 8, :border-radius 4.0}]})}}
{:x 12,
:y 0,
:drawable
{:color [0.2 0.2 0.2 1.0],
:drawables
({:text "versicolor",
:font
{:name nil,
:size 10,
:weight nil,
:width nil,
:slant nil}})}}]}
{:x 508.0,
:y 85,
:drawable
[{:x 0,
:y 0,
:drawable
{:color
[0.30196078431372547 0.6862745098039216 0.2901960784313726 1.0],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 8, :height 8, :border-radius 4.0}]})}}
{:x 12,
:y 0,
:drawable
{:color [0.2 0.2 0.2 1.0],
:drawables
({:text "virginica",
:font
{:name nil,
:size 10,
:weight nil,
:width nil,
:slant nil}})}}]}
{:x 52.5,
:y 43.0,
:drawable
{:color
[0.9098039215686274 0.9098039215686274 0.9098039215686274 1.0],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 435.5, :height 309.0}]})}}
{:x 42.5,
:y 33.0,
:drawable
[{:color
[0.9607843137254902 0.9607843137254902 0.9607843137254902 1.0],
:drawables
({:stroke-width 0.6,
:drawables
[{:style :membrane.ui/style-stroke,
:drawables
[{:points
([51.790404040404034 10] [51.790404040404034 319.0])}]}]})}
{:color
[0.9607843137254902 0.9607843137254902 0.9607843137254902 1.0],
:drawables
({:stroke-width 0.6,
:drawables
[{:style :membrane.ui/style-stroke,
:drawables
[{:points
([106.77777777777777 10] [106.77777777777777 319.0])}]}]})}
{:color
[0.9607843137254902 0.9607843137254902 0.9607843137254902 1.0],
:drawables
({:stroke-width 0.6,
:drawables
[{:style :membrane.ui/style-stroke,
:drawables
[{:points
([161.7651515151515 10] [161.7651515151515 319.0])}]}]})}
{:color
[0.9607843137254902 0.9607843137254902 0.9607843137254902 1.0],
:drawables
({:stroke-width 0.6,
:drawables
[{:style :membrane.ui/style-stroke,
:drawables
[{:points
([216.75252525252526 10] [216.75252525252526 319.0])}]}]})}
{:color
[0.9607843137254902 0.9607843137254902 0.9607843137254902 1.0],
:drawables
({:stroke-width 0.6,
:drawables
[{:style :membrane.ui/style-stroke,
:drawables
[{:points
([271.73989898989896 10] [271.73989898989896 319.0])}]}]})}
{:color
[0.9607843137254902 0.9607843137254902 0.9607843137254902 1.0],
:drawables
({:stroke-width 0.6,
:drawables
[{:style :membrane.ui/style-stroke,
:drawables
[{:points
([326.72727272727275 10] [326.72727272727275 319.0])}]}]})}
{:color
[0.9607843137254902 0.9607843137254902 0.9607843137254902 1.0],
:drawables
({:stroke-width 0.6,
:drawables
[{:style :membrane.ui/style-stroke,
:drawables
[{:points
([381.7146464646464 10] [381.7146464646464 319.0])}]}]})}
{:color
[0.9607843137254902 0.9607843137254902 0.9607843137254902 1.0],
:drawables
({:stroke-width 0.6,
:drawables
[{:style :membrane.ui/style-stroke,
:drawables
[{:points
([436.7020202020202 10] [436.7020202020202 319.0])}]}]})}
{:color
[0.9607843137254902 0.9607843137254902 0.9607843137254902 1.0],
:drawables
({:stroke-width 0.6,
:drawables
[{:style :membrane.ui/style-stroke,
:drawables
[{:points
([10 304.95454545454544] [445.5 304.95454545454544])}]}]})}
{:color
[0.9607843137254902 0.9607843137254902 0.9607843137254902 1.0],
:drawables
({:stroke-width 0.6,
:drawables
[{:style :membrane.ui/style-stroke,
:drawables
[{:points
([10 246.4318181818182] [445.5 246.4318181818182])}]}]})}
{:color
[0.9607843137254902 0.9607843137254902 0.9607843137254902 1.0],
:drawables
({:stroke-width 0.6,
:drawables
[{:style :membrane.ui/style-stroke,
:drawables
[{:points
([10 187.90909090909093] [445.5 187.90909090909093])}]}]})}
{:color
[0.9607843137254902 0.9607843137254902 0.9607843137254902 1.0],
:drawables
({:stroke-width 0.6,
:drawables
[{:style :membrane.ui/style-stroke,
:drawables
[{:points
([10 129.38636363636365] [445.5 129.38636363636365])}]}]})}
{:color
[0.9607843137254902 0.9607843137254902 0.9607843137254902 1.0],
:drawables
({:stroke-width 0.6,
:drawables
[{:style :membrane.ui/style-stroke,
:drawables
[{:points
([10 70.8636363636364] [445.5 70.8636363636364])}]}]})}
{:color
[0.9607843137254902 0.9607843137254902 0.9607843137254902 1.0],
:drawables
({:stroke-width 0.6,
:drawables
[{:style :membrane.ui/style-stroke,
:drawables
[{:points
([10 12.340909090909179] [445.5 12.340909090909179])}]}]})}
{:x 114.77525252525247,
:y 126.38636363636365,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 0}
{:x 92.78030303030306,
:y 184.90909090909093,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 1}
{:x 70.78535353535355,
:y 161.5,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 2}
{:x 59.78787878787873,
:y 173.20454545454547,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 3}
{:x 103.77777777777777,
:y 114.68181818181819,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 4}
{:x 147.76767676767682,
:y 79.56818181818187,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 5}
{:x 59.78787878787873,
:y 138.09090909090912,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 6}
{:x 103.77777777777777,
:y 138.09090909090912,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 7}
{:x 37.79292929292932,
:y 196.61363636363637,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 8}
{:x 92.78030303030306,
:y 173.20454545454547,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 9}
{:x 147.76767676767682,
:y 102.97727272727275,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 10}
{:x 81.78282828282826,
:y 138.09090909090912,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 11}
{:x 81.78282828282826,
:y 184.90909090909093,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 12}
{:x 26.795454545454515,
:y 184.90909090909093,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 13}
{:x 191.75757575757575,
:y 67.8636363636364,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 14}
{:x 180.760101010101,
:y 21.04545454545456,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 15}
{:x 147.76767676767682,
:y 79.56818181818187,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 16}
{:x 114.77525252525247,
:y 126.38636363636365,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 17}
{:x 180.760101010101,
:y 91.27272727272734,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 18}
{:x 114.77525252525247,
:y 91.27272727272734,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 19}
{:x 147.76767676767682,
:y 138.09090909090912,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 20}
{:x 114.77525252525247,
:y 102.97727272727275,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 21}
{:x 59.78787878787873,
:y 114.68181818181819,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 22}
{:x 114.77525252525247,
:y 149.7954545454546,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 23}
{:x 81.78282828282826,
:y 138.09090909090912,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 24}
{:x 103.77777777777777,
:y 184.90909090909093,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 25}
{:x 103.77777777777777,
:y 138.09090909090912,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 26}
{:x 125.77272727272731,
:y 126.38636363636365,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 27}
{:x 125.77272727272731,
:y 138.09090909090912,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 28}
{:x 70.78535353535355,
:y 161.5,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 29}
{:x 81.78282828282826,
:y 173.20454545454547,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 30}
{:x 147.76767676767682,
:y 138.09090909090912,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 31}
{:x 125.77272727272731,
:y 56.15909090909099,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 32}
{:x 158.7651515151515,
:y 44.454545454545496,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 33}
{:x 92.78030303030306,
:y 173.20454545454547,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 34}
{:x 103.77777777777777,
:y 161.5,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 35}
{:x 158.7651515151515,
:y 126.38636363636365,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 36}
{:x 92.78030303030306,
:y 114.68181818181819,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 37}
{:x 37.79292929292932,
:y 184.90909090909093,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 38}
{:x 114.77525252525247,
:y 138.09090909090912,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 39}
{:x 103.77777777777777,
:y 126.38636363636365,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 40}
{:x 48.790404040404034,
:y 266.8409090909091,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 41}
{:x 37.79292929292932,
:y 161.5,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 42}
{:x 103.77777777777777,
:y 126.38636363636365,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 43}
{:x 114.77525252525247,
:y 91.27272727272734,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 44}
{:x 81.78282828282826,
:y 184.90909090909093,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 45}
{:x 114.77525252525247,
:y 91.27272727272734,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 46}
{:x 59.78787878787873,
:y 161.5,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 47}
{:x 136.770202020202,
:y 102.97727272727275,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 48}
{:x 103.77777777777777,
:y 149.7954545454546,
:drawable
[{:color
[0.8941176470588236
0.10196078431372549
0.10980392156862745
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 49}
{:x 323.72727272727275,
:y 161.5,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 50}
{:x 257.74242424242425,
:y 161.5,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 51}
{:x 312.72979797979804,
:y 173.20454545454547,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 52}
{:x 158.7651515151515,
:y 266.8409090909091,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 53}
{:x 268.73989898989896,
:y 208.31818181818184,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 54}
{:x 180.760101010101,
:y 208.31818181818184,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 55}
{:x 246.74494949494945,
:y 149.7954545454546,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 56}
{:x 92.78030303030306,
:y 255.13636363636363,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 57}
{:x 279.73737373737373,
:y 196.61363636363637,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 58}
{:x 125.77272727272731,
:y 220.02272727272725,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 59}
{:x 103.77777777777777,
:y 301.95454545454544,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 60}
{:x 202.75505050505052,
:y 184.90909090909093,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 61}
{:x 213.75252525252526,
:y 278.5454545454545,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 62}
{:x 224.74999999999994,
:y 196.61363636363637,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 63}
{:x 169.7626262626262,
:y 196.61363636363637,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 64}
{:x 290.7348484848485,
:y 173.20454545454547,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 65}
{:x 169.7626262626262,
:y 184.90909090909093,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 66}
{:x 191.75757575757575,
:y 220.02272727272725,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 67}
{:x 235.74747474747477,
:y 278.5454545454545,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 68}
{:x 169.7626262626262,
:y 243.4318181818182,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 69}
{:x 202.75505050505052,
:y 161.5,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 70}
{:x 224.74999999999994,
:y 208.31818181818184,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 71}
{:x 246.74494949494945,
:y 243.4318181818182,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 72}
{:x 224.74999999999994,
:y 208.31818181818184,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 73}
{:x 257.74242424242425,
:y 196.61363636363637,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 74}
{:x 279.73737373737373,
:y 184.90909090909093,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 75}
{:x 301.7323232323232,
:y 208.31818181818184,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 76}
{:x 290.7348484848485,
:y 184.90909090909093,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 77}
{:x 213.75252525252526,
:y 196.61363636363637,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 78}
{:x 180.760101010101,
:y 231.72727272727272,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 79}
{:x 158.7651515151515,
:y 255.13636363636363,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 80}
{:x 158.7651515151515,
:y 255.13636363636363,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 81}
{:x 191.75757575757575,
:y 220.02272727272725,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 82}
{:x 213.75252525252526,
:y 220.02272727272725,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 83}
{:x 147.76767676767682,
:y 184.90909090909093,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 84}
{:x 213.75252525252526,
:y 138.09090909090912,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 85}
{:x 290.7348484848485,
:y 173.20454545454547,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 86}
{:x 246.74494949494945,
:y 266.8409090909091,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 87}
{:x 169.7626262626262,
:y 184.90909090909093,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 88}
{:x 158.7651515151515,
:y 243.4318181818182,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 89}
{:x 158.7651515151515,
:y 231.72727272727272,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 90}
{:x 224.74999999999994,
:y 184.90909090909093,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 91}
{:x 191.75757575757575,
:y 231.72727272727272,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 92}
{:x 103.77777777777777,
:y 266.8409090909091,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 93}
{:x 169.7626262626262,
:y 220.02272727272725,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 94}
{:x 180.760101010101,
:y 184.90909090909093,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 95}
{:x 180.760101010101,
:y 196.61363636363637,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 96}
{:x 235.74747474747477,
:y 196.61363636363637,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 97}
{:x 114.77525252525247,
:y 243.4318181818182,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 98}
{:x 180.760101010101,
:y 208.31818181818184,
:drawable
[{:color
[0.21568627450980393
0.49411764705882355
0.7215686274509804
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 99}
{:x 246.74494949494945,
:y 149.7954545454546,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 100}
{:x 191.75757575757575,
:y 220.02272727272725,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 101}
{:x 334.7247474747474,
:y 184.90909090909093,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 102}
{:x 246.74494949494945,
:y 196.61363636363637,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 103}
{:x 268.73989898989896,
:y 184.90909090909093,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 104}
{:x 389.7121212121212,
:y 184.90909090909093,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 105}
{:x 92.78030303030306,
:y 243.4318181818182,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 106}
{:x 356.71969696969694,
:y 196.61363636363637,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 107}
{:x 290.7348484848485,
:y 243.4318181818182,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 108}
{:x 345.72222222222223,
:y 114.68181818181819,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 109}
{:x 268.73989898989896,
:y 161.5,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 110}
{:x 257.74242424242425,
:y 220.02272727272725,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 111}
{:x 301.7323232323232,
:y 184.90909090909093,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 112}
{:x 180.760101010101,
:y 243.4318181818182,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 113}
{:x 191.75757575757575,
:y 208.31818181818184,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 114}
{:x 257.74242424242425,
:y 161.5,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 115}
{:x 268.73989898989896,
:y 184.90909090909093,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 116}
{:x 400.70959595959596,
:y 91.27272727272734,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 117}
{:x 400.70959595959596,
:y 231.72727272727272,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 118}
{:x 213.75252525252526,
:y 278.5454545454545,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 119}
{:x 312.72979797979804,
:y 161.5,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 120}
{:x 169.7626262626262,
:y 208.31818181818184,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 121}
{:x 400.70959595959596,
:y 208.31818181818184,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 122}
{:x 246.74494949494945,
:y 220.02272727272725,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 123}
{:x 290.7348484848485,
:y 149.7954545454546,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 124}
{:x 345.72222222222223,
:y 161.5,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 125}
{:x 235.74747474747477,
:y 208.31818181818184,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 126}
{:x 224.74999999999994,
:y 184.90909090909093,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 127}
{:x 257.74242424242425,
:y 208.31818181818184,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 128}
{:x 345.72222222222223,
:y 184.90909090909093,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 129}
{:x 367.71717171717177,
:y 208.31818181818184,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 130}
{:x 422.7045454545455,
:y 91.27272727272734,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 131}
{:x 257.74242424242425,
:y 208.31818181818184,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 132}
{:x 246.74494949494945,
:y 208.31818181818184,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 133}
{:x 224.74999999999994,
:y 231.72727272727272,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 134}
{:x 400.70959595959596,
:y 184.90909090909093,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 135}
{:x 246.74494949494945,
:y 138.09090909090912,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 136}
{:x 257.74242424242425,
:y 173.20454545454547,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 137}
{:x 213.75252525252526,
:y 184.90909090909093,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 138}
{:x 312.72979797979804,
:y 173.20454545454547,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 139}
{:x 290.7348484848485,
:y 173.20454545454547,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 140}
{:x 312.72979797979804,
:y 173.20454545454547,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 141}
{:x 191.75757575757575,
:y 220.02272727272725,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 142}
{:x 301.7323232323232,
:y 161.5,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 143}
{:x 290.7348484848485,
:y 149.7954545454546,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 144}
{:x 290.7348484848485,
:y 184.90909090909093,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 145}
{:x 246.74494949494945,
:y 243.4318181818182,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 146}
{:x 268.73989898989896,
:y 184.90909090909093,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 147}
{:x 235.74747474747477,
:y 138.09090909090912,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 148}
{:x 202.75505050505052,
:y 184.90909090909093,
:drawable
[{:color
[0.30196078431372547
0.6862745098039216
0.2901960784313726
0.75],
:drawables
({:style :membrane.ui/style-fill,
:drawables [{:width 6.0, :height 6.0, :border-radius 3.0}]})}
nil],
:row-idx 149}
{:x 51.790404040404034,
:y 331.0,
:drawable
{:color [0.4 0.4 0.4 1.0],
:drawables
({:text "4.5",
:font
{:name nil, :size 11, :weight nil, :width nil, :slant nil},
:text-anchor "middle"})}}
{:x 106.77777777777777,
:y 331.0,
:drawable
{:color [0.4 0.4 0.4 1.0],
:drawables
({:text "5.0",
:font
{:name nil, :size 11, :weight nil, :width nil, :slant nil},
:text-anchor "middle"})}}
{:x 161.7651515151515,
:y 331.0,
:drawable
{:color [0.4 0.4 0.4 1.0],
:drawables
({:text "5.5",
:font
{:name nil, :size 11, :weight nil, :width nil, :slant nil},
:text-anchor "middle"})}}
{:x 216.75252525252526,
:y 331.0,
:drawable
{:color [0.4 0.4 0.4 1.0],
:drawables
({:text "6.0",
:font
{:name nil, :size 11, :weight nil, :width nil, :slant nil},
:text-anchor "middle"})}}
{:x 271.73989898989896,
:y 331.0,
:drawable
{:color [0.4 0.4 0.4 1.0],
:drawables
({:text "6.5",
:font
{:name nil, :size 11, :weight nil, :width nil, :slant nil},
:text-anchor "middle"})}}
{:x 326.72727272727275,
:y 331.0,
:drawable
{:color [0.4 0.4 0.4 1.0],
:drawables
({:text "7.0",
:font
{:name nil, :size 11, :weight nil, :width nil, :slant nil},
:text-anchor "middle"})}}
{:x 381.7146464646464,
:y 331.0,
:drawable
{:color [0.4 0.4 0.4 1.0],
:drawables
({:text "7.5",
:font
{:name nil, :size 11, :weight nil, :width nil, :slant nil},
:text-anchor "middle"})}}
{:x 436.7020202020202,
:y 331.0,
:drawable
{:color [0.4 0.4 0.4 1.0],
:drawables
({:text "8.0",
:font
{:name nil, :size 11, :weight nil, :width nil, :slant nil},
:text-anchor "middle"})}}
{:x 7.0,
:y 299.45454545454544,
:drawable
{:color [0.4 0.4 0.4 1.0],
:drawables
({:text "2.0",
:font
{:name nil, :size 11, :weight nil, :width nil, :slant nil},
:text-anchor "end"})}}
{:x 7.0,
:y 240.9318181818182,
:drawable
{:color [0.4 0.4 0.4 1.0],
:drawables
({:text "2.5",
:font
{:name nil, :size 11, :weight nil, :width nil, :slant nil},
:text-anchor "end"})}}
{:x 7.0,
:y 182.40909090909093,
:drawable
{:color [0.4 0.4 0.4 1.0],
:drawables
({:text "3.0",
:font
{:name nil, :size 11, :weight nil, :width nil, :slant nil},
:text-anchor "end"})}}
{:x 7.0,
:y 123.88636363636365,
:drawable
{:color [0.4 0.4 0.4 1.0],
:drawables
({:text "3.5",
:font
{:name nil, :size 11, :weight nil, :width nil, :slant nil},
:text-anchor "end"})}}
{:x 7.0,
:y 65.3636363636364,
:drawable
{:color [0.4 0.4 0.4 1.0],
:drawables
({:text "4.0",
:font
{:name nil, :size 11, :weight nil, :width nil, :slant nil},
:text-anchor "end"})}}
{:x 7.0,
:y 6.840909090909179,
:drawable
{:color [0.4 0.4 0.4 1.0],
:drawables
({:text "4.5",
:font
{:name nil, :size 11, :weight nil, :width nil, :slant nil},
:text-anchor "end"})}}]}],
:width 600,
:height 400,
:plotje/title "Iris"}A summary view of the structural pieces:
{:width (ui/width iris-membrane)
:height (ui/height iris-membrane)
:origin (ui/origin iris-membrane)
:title (:plotje/title iris-membrane)
:n-drawables (count (ui/children iris-membrane))}{:width 600, :height 400, :origin [0 0], :title "Iris", :n-drawables 9}The width and height come from the plan – the membrane stage does not recompute them; it inherits the canvas size the plan resolved. The origin is [0 0] because a PlotjeMembrane is the full canvas; when it is embedded in a larger Membrane layout, the layout’s translation places it. The nine top-level drawables for this iris scatter are the title, the y-axis label, the x-axis label, the panel background, the panel grid plus marks, and the three legend rows.
The map keys, as the record presents them, are three record fields plus the namespaced title:
(sort (filter keyword? (keys iris-membrane)))(:drawables :height :width :plotje/title)The Membrane protocols
A PlotjeMembrane implements three Membrane UI protocols:
IOrigin– the component’s top-left corner inside its parent. Plotje’s membrane is the canvas itself, so(membrane.ui/origin m)returns[0 0].IBounds– the component’s[width height]. Read directly via(membrane.ui/width m)and(membrane.ui/height m), both of which derive from(membrane.ui/bounds m).IChildren– the sub-elements for traversal. Returns the underlying:drawablesvector.
Why these three and not more? Membrane’s protocols partition into “what every UI element supports” (origin, bounds, children) and “what the element does” (drawing, mouse events, key events, …). Plotje implements the first set so a PlotjeMembrane participates in every Membrane consumer that walks a tree generically. Drawing is delegated to the children: when a Membrane backend draws our record, the default IDraw impl walks (children record) and draws each child individually – the existing Translate, WithColor, Path, Label primitives already have per-backend draw implementations.
Title and namespaced attributes
The plot title rides as :plotje/title – not a defrecord field but a namespaced map entry assoc’d onto the record. This keeps the record’s arity stable as we add per-membrane attributes in the future. A pose without a title produces a membrane without that key:
(:plotje/title (pj/membrane (-> (rdatasets/datasets-iris)
(pj/lay-point :sepal-length :sepal-width))))nilFuture per-membrane attributes will use the same :plotje/* namespace (for instance :plotje/subtitle or :plotje/caption). A backend reading the membrane can pick up whichever ones it recognizes and ignore the rest – the :plotje/ prefix makes our keys collision-free with any other library composing into the same map.
Composing with other Membrane components
Because a PlotjeMembrane is a Membrane UI component, you can drop it into any Membrane layout. Two Plotje plots side by side is one line:
(def two-up
(ui/horizontal-layout
(pj/membrane (-> (rdatasets/datasets-iris)
(pj/lay-point :sepal-length :sepal-width
{:color :species})
(pj/options {:title "Sepal length vs sepal width"
:y-label "width"})))
(pj/membrane (-> (rdatasets/datasets-iris)
(pj/lay-point :sepal-length :petal-length
{:color :species})
(pj/options {:title "Sepal length vs petal length"
:y-label "petal"})))))The result is itself a Membrane component with bounds derived from its children. Two 600 by 400 plots side by side, with a 1-unit gap that horizontal-layout inserts, give a 1201 by 400 canvas:
{:width (ui/width two-up)
:height (ui/height two-up)}{:width 1201, :height 400}The combined component is no longer a PlotjeMembrane (it is whatever horizontal-layout chose to return – here, a vector of the two children), but it speaks the same protocol vocabulary, so any Membrane backend can render it. To produce a raster image we bypass pj/membrane->plot (which validates a PlotjeMembrane specifically) and call Membrane’s Java2D backend directly:
(def two-up-png
((requiring-resolve 'membrane.java2d/draw-to-image)
two-up
[(ui/width two-up) (ui/height two-up)]))(instance? java.awt.image.BufferedImage two-up-png)trueThe same pose stages, rendered as raster:
two-up-png
This is why the membrane stage matters as a separate boundary. Plotje produces values that any Membrane consumer understands; Plotje plots compose with hand-built Membrane elements; nothing about the value type is Plotje-specific beyond the namespaced title key.
Rendering through Plotje’s backends
The composition shortcut pj/plot is the convenience case; the explicit step pj/membrane->plot dispatches on a format keyword. :svg is always available – the path that auto-rendered iris-pose at the top of the chapter:
(pj/membrane->plot iris-membrane :svg {}):bufimg is registered when scicloj.plotje.render.bufimg is loaded; it produces a Java BufferedImage, the raster form used in the previous section’s composition:
(pj/membrane->plot iris-membrane :bufimg {})
The membrane stage is format-agnostic: the same iris-membrane produced one valid value, and that value renders to multiple output formats without re-walking the plan. Adding a new format means writing a defmethod on scicloj.plotje.impl.render/membrane->plot. The Extensibility chapter walks a worked example.
Schema
Plotje publishes a Malli schema for the PlotjeMembrane shape. Backend authors validating an incoming membrane (or constructing their own for testing) can use it:
(plotje-mem/valid? iris-membrane)trueA non-membrane value fails validation:
(some? (plotje-mem/explain {:not :a-membrane}))trueSee also
Architecture – the full five-stage pipeline and where the membrane stage fits.
Extensibility – adding a new format by registering a
membrane->plotdefmethod, plus the other extension points (marks, stats, scales, coordinates).