chiark / gitweb /
m.dot: new highly experimental graph drawing plugin.
authorVladimír Vondruš <mosra@centrum.cz>
Mon, 18 Jun 2018 23:23:53 +0000 (01:23 +0200)
committerVladimír Vondruš <mosra@centrum.cz>
Sun, 1 Jul 2018 13:21:06 +0000 (15:21 +0200)
18 files changed:
css/m-components.css
css/m-dark+doxygen.compiled.css
css/m-dark.compiled.css
css/m-light+doxygen.compiled.css
css/m-light.compiled.css
doc/css/components.rst
doc/plugins.rst
doc/plugins/links.rst
doc/plugins/math-and-code.rst
doc/plugins/plots-and-graphs-test.rst [new file with mode: 0644]
doc/plugins/plots-and-graphs.rst [moved from doc/plugins/plots.rst with 53% similarity]
doc/plugins/plots-test.rst [deleted file]
package/ci/travis.yml
pelican-plugins/m/dot.py [new file with mode: 0644]
pelican-plugins/m/test/dot/page.html [new file with mode: 0644]
pelican-plugins/m/test/dot/page.rst [new file with mode: 0644]
pelican-plugins/m/test/test_dot.py [new file with mode: 0644]
site/pelicanconf.py

index 2c8ddd4ce211eb1a303201be7c55662bcc17d57e..8990bf0ba9979fdbd61e6f6e1b38ecc3af89d04d 100644 (file)
@@ -962,13 +962,10 @@ div.m-button.m-default a:active svg.m-math {
   fill: var(--link-active-color);
 }
 
-/* Plots */
-div.m-plot svg {
-  text-align: center;
-}
-div.m-plot .m-background {
-  fill: var(--plot-background-color);
-}
+/* Plots, graphs */
+div.m-plot, div.m-graph { text-align: center; }
+div.m-plot svg, div.m-graph svg { max-width: 100%; }
+div.m-plot .m-background { fill: var(--plot-background-color); }
 /* Font sizes are hardcoded in m.plots, change there first! */
 div.m-plot svg .m-label { font-size: 11px; }
 div.m-plot svg .m-title { font-size: 13px; }
@@ -982,51 +979,239 @@ div.m-plot svg .m-error {
   stroke-width: 1.5;
 }
 div.m-plot svg .m-label.m-dim { fill: var(--dim-color); }
+div.m-graph svg g.m-edge path, div.m-graph svg g.m-node.m-flat ellipse,
+div.m-graph svg g.m-node.m-flat polygon {
+  fill: none;
+}
+div.m-graph svg g.m-node:not(.m-flat) text {
+  fill: var(--button-background-color);
+}
 
-/* Colored math block, inline math, colored math parts, plots */
+/* Colored math block, inline math, colored math parts, plots and
+   global-colored graphs. Should be before local graph coloring, so the latter
+   can override this. */
 div.m-math svg, svg.m-math { fill: var(--color); }
 div.m-math.m-default svg, svg.m-math.m-default,
 div.m-math svg g.m-default, svg.m-math g.m-default,
 div.m-math svg rect.m-default, svg.m-math rect.m-default,
-div.m-plot svg .m-bar.m-default {
+div.m-plot svg .m-bar.m-default,
+div.m-graph svg g.m-edge polygon,
+div.m-graph svg g.m-node:not(.m-flat) ellipse,
+div.m-graph svg g.m-node:not(.m-flat) polygon,
+div.m-graph svg g.m-edge text,
+div.m-graph svg g.m-node.m-flat text,
+div.m-graph.m-default svg g.m-edge polygon,
+div.m-graph.m-default svg g.m-node:not(.m-flat) ellipse,
+div.m-graph.m-default svg g.m-node:not(.m-flat) polygon,
+div.m-graph.m-default svg g.m-edge text,
+div.m-graph.m-default svg g.m-node.m-flat text {
   fill: var(--default-color);
 }
+div.m-graph svg g.m-edge polygon,
+div.m-graph svg g.m-edge path,
+div.m-graph svg g.m-node ellipse,
+div.m-graph svg g.m-node polygon,
+div.m-graph.m-default svg g.m-edge polygon,
+div.m-graph.m-default svg g.m-edge path,
+div.m-graph.m-default svg g.m-node ellipse,
+div.m-graph.m-default svg g.m-node polygon {
+  stroke: var(--default-color);
+}
 div.m-math.m-primary svg, svg.m-math.m-primary,
 div.m-math svg g.m-primary, svg.m-math g.m-primary,
 div.m-math svg rect.m-primary, svg.m-math rect.m-primary,
-div.m-plot svg .m-bar.m-primary {
+div.m-plot svg .m-bar.m-primary,
+div.m-graph.m-primary svg g.m-edge polygon,
+div.m-graph.m-primary svg g.m-node:not(.m-flat) ellipse,
+div.m-graph.m-primary svg g.m-node:not(.m-flat) polygon,
+div.m-graph.m-primary svg g.m-edge text,
+div.m-graph.m-primary svg g.m-node.m-flat text {
   fill: var(--primary-color);
 }
+div.m-graph.m-primary svg g.m-edge polygon,
+div.m-graph.m-primary svg g.m-edge path,
+div.m-graph.m-primary svg g.m-node ellipse,
+div.m-graph.m-primary svg g.m-node polygon {
+  stroke: var(--primary-color);
+}
 div.m-math.m-success svg, svg.m-math.m-success,
 div.m-math svg g.m-success, svg.m-math g.m-success,
 div.m-math svg rect.m-success, svg.m-math rect.m-success,
-div.m-plot svg .m-bar.m-success {
+div.m-plot svg .m-bar.m-success,
+div.m-graph.m-success svg g.m-edge polygon,
+div.m-graph.m-success svg g.m-node:not(.m-flat) ellipse,
+div.m-graph.m-success svg g.m-node:not(.m-flat) polygon,
+div.m-graph.m-success svg g.m-edge text,
+div.m-graph.m-success svg g.m-node.m-flat text {
   fill: var(--success-color);
 }
+div.m-graph.m-success svg g.m-edge polygon,
+div.m-graph.m-success svg g.m-edge path,
+div.m-graph.m-success svg g.m-node ellipse,
+div.m-graph.m-success svg g.m-node polygon {
+  stroke: var(--success-color);
+}
 div.m-math.m-warning svg, svg.m-math.m-warning,
 div.m-math svg g.m-warning, svg.m-math g.m-warning,
 div.m-math svg rect.m-warning, svg.m-math rect.m-warning,
-div.m-plot svg .m-bar.m-warning {
+div.m-plot svg .m-bar.m-warning,
+div.m-graph.m-warning svg g.m-edge polygon,
+div.m-graph.m-warning svg g.m-node:not(.m-flat) ellipse,
+div.m-graph.m-warning svg g.m-node:not(.m-flat) polygon,
+div.m-graph.m-warning svg g.m-edge text,
+div.m-graph.m-warning svg g.m-node.m-flat text {
   fill: var(--warning-color);
 }
+div.m-graph.m-warning svg g.m-edge polygon,
+div.m-graph.m-warning svg g.m-edge path,
+div.m-graph.m-warning svg g.m-node ellipse,
+div.m-graph.m-warning svg g.m-node polygon {
+  stroke: var(--warning-color);
+}
 div.m-math.m-danger svg, svg.m-math.m-danger,
 div.m-math svg g.m-danger, svg.m-math g.m-danger,
 div.m-math svg rect.m-danger, svg.m-math rect.m-danger,
-div.m-plot svg .m-bar.m-danger {
+div.m-plot svg .m-bar.m-danger,
+div.m-graph.m-danger svg g.m-edge polygon,
+div.m-graph.m-danger svg g.m-node:not(.m-flat) ellipse,
+div.m-graph.m-danger svg g.m-node:not(.m-flat) polygon,
+div.m-graph.m-danger svg g.m-edge text,
+div.m-graph.m-danger svg g.m-node.m-flat text {
   fill: var(--danger-color);
 }
+div.m-graph.m-danger svg g.m-edge polygon,
+div.m-graph.m-danger svg g.m-edge path,
+div.m-graph.m-danger svg g.m-node ellipse,
+div.m-graph.m-danger svg g.m-node polygon {
+  stroke: var(--danger-color);
+}
 div.m-math.m-info svg, svg.m-math.m-info,
 div.m-math svg g.m-info, svg.m-math g.m-info,
 div.m-math svg rect.m-info, svg.m-math rect.m-info,
-div.m-plot svg .m-bar.m-info {
+div.m-plot svg .m-bar.m-info,
+div.m-graph.m-info svg g.m-edge polygon,
+div.m-graph.m-info svg g.m-node:not(.m-flat) ellipse,
+div.m-graph.m-info svg g.m-node:not(.m-flat) polygon,
+div.m-graph.m-info svg g.m-edge text,
+div.m-graph.m-info svg g.m-node.m-flat text {
   fill: var(--info-color);
 }
+div.m-graph.m-info svg g.m-edge polygon,
+div.m-graph.m-info svg g.m-edge path,
+div.m-graph.m-info svg g.m-node ellipse,
+div.m-graph.m-info svg g.m-node polygon {
+  stroke: var(--info-color);
+}
 div.m-math.m-dim svg, svg.m-math.m-dim,
 div.m-math svg g.m-dim, svg.m-math g.m-dim,
 div.m-math svg rect.m-dim, svg.m-math rect.m-dim,
-div.m-plot svg .m-bar.m-dim {
+div.m-plot svg .m-bar.m-dim,
+div.m-graph.m-dim svg g.m-edge polygon,
+div.m-graph.m-dim svg g.m-node:not(.m-flat) ellipse,
+div.m-graph.m-dim svg g.m-node:not(.m-flat) polygon,
+div.m-graph.m-dim svg g.m-edge text,
+div.m-graph.m-dim svg g.m-node.m-flat text {
+  fill: var(--dim-color);
+}
+div.m-graph.m-dim svg g.m-edge polygon,
+div.m-graph.m-dim svg g.m-edge path,
+div.m-graph.m-dim svg g.m-node ellipse,
+div.m-graph.m-dim svg g.m-node polygon {
+  stroke: var(--dim-color);
+}
+
+/* Local-colored graphs. Later so it overrides global coloring. */
+div.m-graph svg g.m-edge.m-default polygon,
+div.m-graph svg g.m-node.m-default:not(.m-flat) ellipse,
+div.m-graph svg g.m-node.m-default:not(.m-flat) polygon,
+div.m-graph svg g.m-edge.m-default text,
+div.m-graph svg g.m-node.m-default.m-flat text {
+  fill: var(--default-color);
+}
+div.m-graph svg g.m-edge.m-default polygon,
+div.m-graph svg g.m-edge.m-default path,
+div.m-graph svg g.m-node.m-default ellipse,
+div.m-graph svg g.m-node.m-default polygon {
+  stroke: var(--default-color);
+}
+div.m-graph svg g.m-edge.m-primary polygon,
+div.m-graph svg g.m-node.m-primary:not(.m-flat) ellipse,
+div.m-graph svg g.m-node.m-primary:not(.m-flat) polygon,
+div.m-graph svg g.m-edge.m-primary text,
+div.m-graph svg g.m-node.m-primary.m-flat text {
+  fill: var(--primary-color);
+}
+div.m-graph svg g.m-edge.m-primary polygon,
+div.m-graph svg g.m-edge.m-primary path,
+div.m-graph svg g.m-node.m-primary ellipse,
+div.m-graph svg g.m-node.m-primary polygon {
+  stroke: var(--primary-color);
+}
+div.m-graph svg g.m-edge.m-success polygon,
+div.m-graph svg g.m-node.m-success:not(.m-flat) ellipse,
+div.m-graph svg g.m-node.m-success:not(.m-flat) polygon,
+div.m-graph svg g.m-edge.m-success text,
+div.m-graph svg g.m-node.m-success.m-flat text {
+  fill: var(--success-color);
+}
+div.m-graph svg g.m-edge.m-success polygon,
+div.m-graph svg g.m-edge.m-success path,
+div.m-graph svg g.m-node.m-success ellipse,
+div.m-graph svg g.m-node.m-success polygon {
+  stroke: var(--success-color);
+}
+div.m-graph svg g.m-edge.m-warning polygon,
+div.m-graph svg g.m-node.m-warning:not(.m-flat) ellipse,
+div.m-graph svg g.m-node.m-warning:not(.m-flat) polygon,
+div.m-graph svg g.m-edge.m-warning text,
+div.m-graph svg g.m-node.m-warning.m-flat text {
+  fill: var(--warning-color);
+}
+div.m-graph svg g.m-edge.m-warning polygon,
+div.m-graph svg g.m-edge.m-warning path,
+div.m-graph svg g.m-node.m-warning ellipse,
+div.m-graph svg g.m-node.m-warning polygon {
+  stroke: var(--warning-color);
+}
+div.m-graph svg g.m-edge.m-danger polygon,
+div.m-graph svg g.m-node.m-danger:not(.m-flat) ellipse,
+div.m-graph svg g.m-node.m-danger:not(.m-flat) polygon,
+div.m-graph svg g.m-edge.m-danger text,
+div.m-graph svg g.m-node.m-danger.m-flat text {
+  fill: var(--danger-color);
+}
+div.m-graph svg g.m-edge.m-danger polygon,
+div.m-graph svg g.m-edge.m-danger path,
+div.m-graph svg g.m-node.m-danger ellipse,
+div.m-graph svg g.m-node.m-danger polygon {
+  stroke: var(--danger-color);
+}
+div.m-graph svg g.m-edge.m-info polygon,
+div.m-graph svg g.m-node.m-info:not(.m-flat) ellipse,
+div.m-graph svg g.m-node.m-info:not(.m-flat) polygon,
+div.m-graph svg g.m-edge.m-info text,
+div.m-graph svg g.m-node.m-info.m-flat text {
+  fill: var(--info-color);
+}
+div.m-graph svg g.m-edge.m-info polygon,
+div.m-graph svg g.m-edge.m-info path,
+div.m-graph svg g.m-node.m-info ellipse,
+div.m-graph svg g.m-node.m-info polygon {
+  stroke: var(--info-color);
+}
+div.m-graph svg g.m-edge.m-dim polygon,
+div.m-graph svg g.m-node.m-dim:not(.m-flat) ellipse,
+div.m-graph svg g.m-node.m-dim:not(.m-flat) polygon,
+div.m-graph svg g.m-edge.m-dim text,
+div.m-graph svg g.m-node.m-dim.m-flat text {
   fill: var(--dim-color);
 }
+div.m-graph svg g.m-edge.m-dim polygon,
+div.m-graph svg g.m-edge.m-dim path,
+div.m-graph svg g.m-node.m-dim ellipse,
+div.m-graph svg g.m-node.m-dim polygon {
+  stroke: var(--dim-color);
+}
 
 /* Spacing after every block element, but not after the last and not when
   m-nopadb is specified */
index 2621a41e8302f843eed2475bc830f046b4047b2f..577ccffc6090c11777cf0f42a12a0a4c1237c9d9 100644 (file)
@@ -1268,12 +1268,9 @@ div.m-button.m-flat a:hover svg.m-math, div.m-button.m-default a:focus svg.m-mat
 div.m-button.m-default a:active svg.m-math {
   fill: #a5c9ea;
 }
-div.m-plot svg {
-  text-align: center;
-}
-div.m-plot .m-background {
-  fill: #34424d;
-}
+div.m-plot, div.m-graph { text-align: center; }
+div.m-plot svg, div.m-graph svg { max-width: 100%; }
+div.m-plot .m-background { fill: #34424d; }
 div.m-plot svg .m-label { font-size: 11px; }
 div.m-plot svg .m-title { font-size: 13px; }
 div.m-plot svg .m-label, div.m-plot svg .m-title { fill: #dcdcdc; }
@@ -1286,49 +1283,233 @@ div.m-plot svg .m-error {
   stroke-width: 1.5;
 }
 div.m-plot svg .m-label.m-dim { fill: #747474; }
+div.m-graph svg g.m-edge path, div.m-graph svg g.m-node.m-flat ellipse,
+div.m-graph svg g.m-node.m-flat polygon {
+  fill: none;
+}
+div.m-graph svg g.m-node:not(.m-flat) text {
+  fill: #22272e;
+}
 div.m-math svg, svg.m-math { fill: #dcdcdc; }
 div.m-math.m-default svg, svg.m-math.m-default,
 div.m-math svg g.m-default, svg.m-math g.m-default,
 div.m-math svg rect.m-default, svg.m-math rect.m-default,
-div.m-plot svg .m-bar.m-default {
+div.m-plot svg .m-bar.m-default,
+div.m-graph svg g.m-edge polygon,
+div.m-graph svg g.m-node:not(.m-flat) ellipse,
+div.m-graph svg g.m-node:not(.m-flat) polygon,
+div.m-graph svg g.m-edge text,
+div.m-graph svg g.m-node.m-flat text,
+div.m-graph.m-default svg g.m-edge polygon,
+div.m-graph.m-default svg g.m-node:not(.m-flat) ellipse,
+div.m-graph.m-default svg g.m-node:not(.m-flat) polygon,
+div.m-graph.m-default svg g.m-edge text,
+div.m-graph.m-default svg g.m-node.m-flat text {
   fill: #dcdcdc;
 }
+div.m-graph svg g.m-edge polygon,
+div.m-graph svg g.m-edge path,
+div.m-graph svg g.m-node ellipse,
+div.m-graph svg g.m-node polygon,
+div.m-graph.m-default svg g.m-edge polygon,
+div.m-graph.m-default svg g.m-edge path,
+div.m-graph.m-default svg g.m-node ellipse,
+div.m-graph.m-default svg g.m-node polygon {
+  stroke: #dcdcdc;
+}
 div.m-math.m-primary svg, svg.m-math.m-primary,
 div.m-math svg g.m-primary, svg.m-math g.m-primary,
 div.m-math svg rect.m-primary, svg.m-math rect.m-primary,
-div.m-plot svg .m-bar.m-primary {
+div.m-plot svg .m-bar.m-primary,
+div.m-graph.m-primary svg g.m-edge polygon,
+div.m-graph.m-primary svg g.m-node:not(.m-flat) ellipse,
+div.m-graph.m-primary svg g.m-node:not(.m-flat) polygon,
+div.m-graph.m-primary svg g.m-edge text,
+div.m-graph.m-primary svg g.m-node.m-flat text {
   fill: #a5c9ea;
 }
+div.m-graph.m-primary svg g.m-edge polygon,
+div.m-graph.m-primary svg g.m-edge path,
+div.m-graph.m-primary svg g.m-node ellipse,
+div.m-graph.m-primary svg g.m-node polygon {
+  stroke: #a5c9ea;
+}
 div.m-math.m-success svg, svg.m-math.m-success,
 div.m-math svg g.m-success, svg.m-math g.m-success,
 div.m-math svg rect.m-success, svg.m-math rect.m-success,
-div.m-plot svg .m-bar.m-success {
+div.m-plot svg .m-bar.m-success,
+div.m-graph.m-success svg g.m-edge polygon,
+div.m-graph.m-success svg g.m-node:not(.m-flat) ellipse,
+div.m-graph.m-success svg g.m-node:not(.m-flat) polygon,
+div.m-graph.m-success svg g.m-edge text,
+div.m-graph.m-success svg g.m-node.m-flat text {
   fill: #3bd267;
 }
+div.m-graph.m-success svg g.m-edge polygon,
+div.m-graph.m-success svg g.m-edge path,
+div.m-graph.m-success svg g.m-node ellipse,
+div.m-graph.m-success svg g.m-node polygon {
+  stroke: #3bd267;
+}
 div.m-math.m-warning svg, svg.m-math.m-warning,
 div.m-math svg g.m-warning, svg.m-math g.m-warning,
 div.m-math svg rect.m-warning, svg.m-math rect.m-warning,
-div.m-plot svg .m-bar.m-warning {
+div.m-plot svg .m-bar.m-warning,
+div.m-graph.m-warning svg g.m-edge polygon,
+div.m-graph.m-warning svg g.m-node:not(.m-flat) ellipse,
+div.m-graph.m-warning svg g.m-node:not(.m-flat) polygon,
+div.m-graph.m-warning svg g.m-edge text,
+div.m-graph.m-warning svg g.m-node.m-flat text {
   fill: #c7cf2f;
 }
+div.m-graph.m-warning svg g.m-edge polygon,
+div.m-graph.m-warning svg g.m-edge path,
+div.m-graph.m-warning svg g.m-node ellipse,
+div.m-graph.m-warning svg g.m-node polygon {
+  stroke: #c7cf2f;
+}
 div.m-math.m-danger svg, svg.m-math.m-danger,
 div.m-math svg g.m-danger, svg.m-math g.m-danger,
 div.m-math svg rect.m-danger, svg.m-math rect.m-danger,
-div.m-plot svg .m-bar.m-danger {
+div.m-plot svg .m-bar.m-danger,
+div.m-graph.m-danger svg g.m-edge polygon,
+div.m-graph.m-danger svg g.m-node:not(.m-flat) ellipse,
+div.m-graph.m-danger svg g.m-node:not(.m-flat) polygon,
+div.m-graph.m-danger svg g.m-edge text,
+div.m-graph.m-danger svg g.m-node.m-flat text {
   fill: #cd3431;
 }
+div.m-graph.m-danger svg g.m-edge polygon,
+div.m-graph.m-danger svg g.m-edge path,
+div.m-graph.m-danger svg g.m-node ellipse,
+div.m-graph.m-danger svg g.m-node polygon {
+  stroke: #cd3431;
+}
 div.m-math.m-info svg, svg.m-math.m-info,
 div.m-math svg g.m-info, svg.m-math g.m-info,
 div.m-math svg rect.m-info, svg.m-math rect.m-info,
-div.m-plot svg .m-bar.m-info {
+div.m-plot svg .m-bar.m-info,
+div.m-graph.m-info svg g.m-edge polygon,
+div.m-graph.m-info svg g.m-node:not(.m-flat) ellipse,
+div.m-graph.m-info svg g.m-node:not(.m-flat) polygon,
+div.m-graph.m-info svg g.m-edge text,
+div.m-graph.m-info svg g.m-node.m-flat text {
   fill: #2f83cc;
 }
+div.m-graph.m-info svg g.m-edge polygon,
+div.m-graph.m-info svg g.m-edge path,
+div.m-graph.m-info svg g.m-node ellipse,
+div.m-graph.m-info svg g.m-node polygon {
+  stroke: #2f83cc;
+}
 div.m-math.m-dim svg, svg.m-math.m-dim,
 div.m-math svg g.m-dim, svg.m-math g.m-dim,
 div.m-math svg rect.m-dim, svg.m-math rect.m-dim,
-div.m-plot svg .m-bar.m-dim {
+div.m-plot svg .m-bar.m-dim,
+div.m-graph.m-dim svg g.m-edge polygon,
+div.m-graph.m-dim svg g.m-node:not(.m-flat) ellipse,
+div.m-graph.m-dim svg g.m-node:not(.m-flat) polygon,
+div.m-graph.m-dim svg g.m-edge text,
+div.m-graph.m-dim svg g.m-node.m-flat text {
   fill: #747474;
 }
+div.m-graph.m-dim svg g.m-edge polygon,
+div.m-graph.m-dim svg g.m-edge path,
+div.m-graph.m-dim svg g.m-node ellipse,
+div.m-graph.m-dim svg g.m-node polygon {
+  stroke: #747474;
+}
+div.m-graph svg g.m-edge.m-default polygon,
+div.m-graph svg g.m-node.m-default:not(.m-flat) ellipse,
+div.m-graph svg g.m-node.m-default:not(.m-flat) polygon,
+div.m-graph svg g.m-edge.m-default text,
+div.m-graph svg g.m-node.m-default.m-flat text {
+  fill: #dcdcdc;
+}
+div.m-graph svg g.m-edge.m-default polygon,
+div.m-graph svg g.m-edge.m-default path,
+div.m-graph svg g.m-node.m-default ellipse,
+div.m-graph svg g.m-node.m-default polygon {
+  stroke: #dcdcdc;
+}
+div.m-graph svg g.m-edge.m-primary polygon,
+div.m-graph svg g.m-node.m-primary:not(.m-flat) ellipse,
+div.m-graph svg g.m-node.m-primary:not(.m-flat) polygon,
+div.m-graph svg g.m-edge.m-primary text,
+div.m-graph svg g.m-node.m-primary.m-flat text {
+  fill: #a5c9ea;
+}
+div.m-graph svg g.m-edge.m-primary polygon,
+div.m-graph svg g.m-edge.m-primary path,
+div.m-graph svg g.m-node.m-primary ellipse,
+div.m-graph svg g.m-node.m-primary polygon {
+  stroke: #a5c9ea;
+}
+div.m-graph svg g.m-edge.m-success polygon,
+div.m-graph svg g.m-node.m-success:not(.m-flat) ellipse,
+div.m-graph svg g.m-node.m-success:not(.m-flat) polygon,
+div.m-graph svg g.m-edge.m-success text,
+div.m-graph svg g.m-node.m-success.m-flat text {
+  fill: #3bd267;
+}
+div.m-graph svg g.m-edge.m-success polygon,
+div.m-graph svg g.m-edge.m-success path,
+div.m-graph svg g.m-node.m-success ellipse,
+div.m-graph svg g.m-node.m-success polygon {
+  stroke: #3bd267;
+}
+div.m-graph svg g.m-edge.m-warning polygon,
+div.m-graph svg g.m-node.m-warning:not(.m-flat) ellipse,
+div.m-graph svg g.m-node.m-warning:not(.m-flat) polygon,
+div.m-graph svg g.m-edge.m-warning text,
+div.m-graph svg g.m-node.m-warning.m-flat text {
+  fill: #c7cf2f;
+}
+div.m-graph svg g.m-edge.m-warning polygon,
+div.m-graph svg g.m-edge.m-warning path,
+div.m-graph svg g.m-node.m-warning ellipse,
+div.m-graph svg g.m-node.m-warning polygon {
+  stroke: #c7cf2f;
+}
+div.m-graph svg g.m-edge.m-danger polygon,
+div.m-graph svg g.m-node.m-danger:not(.m-flat) ellipse,
+div.m-graph svg g.m-node.m-danger:not(.m-flat) polygon,
+div.m-graph svg g.m-edge.m-danger text,
+div.m-graph svg g.m-node.m-danger.m-flat text {
+  fill: #cd3431;
+}
+div.m-graph svg g.m-edge.m-danger polygon,
+div.m-graph svg g.m-edge.m-danger path,
+div.m-graph svg g.m-node.m-danger ellipse,
+div.m-graph svg g.m-node.m-danger polygon {
+  stroke: #cd3431;
+}
+div.m-graph svg g.m-edge.m-info polygon,
+div.m-graph svg g.m-node.m-info:not(.m-flat) ellipse,
+div.m-graph svg g.m-node.m-info:not(.m-flat) polygon,
+div.m-graph svg g.m-edge.m-info text,
+div.m-graph svg g.m-node.m-info.m-flat text {
+  fill: #2f83cc;
+}
+div.m-graph svg g.m-edge.m-info polygon,
+div.m-graph svg g.m-edge.m-info path,
+div.m-graph svg g.m-node.m-info ellipse,
+div.m-graph svg g.m-node.m-info polygon {
+  stroke: #2f83cc;
+}
+div.m-graph svg g.m-edge.m-dim polygon,
+div.m-graph svg g.m-node.m-dim:not(.m-flat) ellipse,
+div.m-graph svg g.m-node.m-dim:not(.m-flat) polygon,
+div.m-graph svg g.m-edge.m-dim text,
+div.m-graph svg g.m-node.m-dim.m-flat text {
+  fill: #747474;
+}
+div.m-graph svg g.m-edge.m-dim polygon,
+div.m-graph svg g.m-edge.m-dim path,
+div.m-graph svg g.m-node.m-dim ellipse,
+div.m-graph svg g.m-node.m-dim polygon {
+  stroke: #747474;
+}
 p, ul, ol, dl, blockquote, pre, figure.m-code-figure, figure.m-console-figure,
 hr, .m-note, .m-frame, .m-block, div.m-button, div.m-scroll, table.m-table,
 div.m-image, img.m-image, svg.m-image, figure.m-figure, .m-imagegrid, div.m-math {
index 9df06a756811aaacbf670a6423a5130890ae239f..bcb33b6b652a0c96169981ee051b6401452183ca 100644 (file)
@@ -1268,12 +1268,9 @@ div.m-button.m-flat a:hover svg.m-math, div.m-button.m-default a:focus svg.m-mat
 div.m-button.m-default a:active svg.m-math {
   fill: #a5c9ea;
 }
-div.m-plot svg {
-  text-align: center;
-}
-div.m-plot .m-background {
-  fill: #34424d;
-}
+div.m-plot, div.m-graph { text-align: center; }
+div.m-plot svg, div.m-graph svg { max-width: 100%; }
+div.m-plot .m-background { fill: #34424d; }
 div.m-plot svg .m-label { font-size: 11px; }
 div.m-plot svg .m-title { font-size: 13px; }
 div.m-plot svg .m-label, div.m-plot svg .m-title { fill: #dcdcdc; }
@@ -1286,49 +1283,233 @@ div.m-plot svg .m-error {
   stroke-width: 1.5;
 }
 div.m-plot svg .m-label.m-dim { fill: #747474; }
+div.m-graph svg g.m-edge path, div.m-graph svg g.m-node.m-flat ellipse,
+div.m-graph svg g.m-node.m-flat polygon {
+  fill: none;
+}
+div.m-graph svg g.m-node:not(.m-flat) text {
+  fill: #22272e;
+}
 div.m-math svg, svg.m-math { fill: #dcdcdc; }
 div.m-math.m-default svg, svg.m-math.m-default,
 div.m-math svg g.m-default, svg.m-math g.m-default,
 div.m-math svg rect.m-default, svg.m-math rect.m-default,
-div.m-plot svg .m-bar.m-default {
+div.m-plot svg .m-bar.m-default,
+div.m-graph svg g.m-edge polygon,
+div.m-graph svg g.m-node:not(.m-flat) ellipse,
+div.m-graph svg g.m-node:not(.m-flat) polygon,
+div.m-graph svg g.m-edge text,
+div.m-graph svg g.m-node.m-flat text,
+div.m-graph.m-default svg g.m-edge polygon,
+div.m-graph.m-default svg g.m-node:not(.m-flat) ellipse,
+div.m-graph.m-default svg g.m-node:not(.m-flat) polygon,
+div.m-graph.m-default svg g.m-edge text,
+div.m-graph.m-default svg g.m-node.m-flat text {
   fill: #dcdcdc;
 }
+div.m-graph svg g.m-edge polygon,
+div.m-graph svg g.m-edge path,
+div.m-graph svg g.m-node ellipse,
+div.m-graph svg g.m-node polygon,
+div.m-graph.m-default svg g.m-edge polygon,
+div.m-graph.m-default svg g.m-edge path,
+div.m-graph.m-default svg g.m-node ellipse,
+div.m-graph.m-default svg g.m-node polygon {
+  stroke: #dcdcdc;
+}
 div.m-math.m-primary svg, svg.m-math.m-primary,
 div.m-math svg g.m-primary, svg.m-math g.m-primary,
 div.m-math svg rect.m-primary, svg.m-math rect.m-primary,
-div.m-plot svg .m-bar.m-primary {
+div.m-plot svg .m-bar.m-primary,
+div.m-graph.m-primary svg g.m-edge polygon,
+div.m-graph.m-primary svg g.m-node:not(.m-flat) ellipse,
+div.m-graph.m-primary svg g.m-node:not(.m-flat) polygon,
+div.m-graph.m-primary svg g.m-edge text,
+div.m-graph.m-primary svg g.m-node.m-flat text {
   fill: #a5c9ea;
 }
+div.m-graph.m-primary svg g.m-edge polygon,
+div.m-graph.m-primary svg g.m-edge path,
+div.m-graph.m-primary svg g.m-node ellipse,
+div.m-graph.m-primary svg g.m-node polygon {
+  stroke: #a5c9ea;
+}
 div.m-math.m-success svg, svg.m-math.m-success,
 div.m-math svg g.m-success, svg.m-math g.m-success,
 div.m-math svg rect.m-success, svg.m-math rect.m-success,
-div.m-plot svg .m-bar.m-success {
+div.m-plot svg .m-bar.m-success,
+div.m-graph.m-success svg g.m-edge polygon,
+div.m-graph.m-success svg g.m-node:not(.m-flat) ellipse,
+div.m-graph.m-success svg g.m-node:not(.m-flat) polygon,
+div.m-graph.m-success svg g.m-edge text,
+div.m-graph.m-success svg g.m-node.m-flat text {
   fill: #3bd267;
 }
+div.m-graph.m-success svg g.m-edge polygon,
+div.m-graph.m-success svg g.m-edge path,
+div.m-graph.m-success svg g.m-node ellipse,
+div.m-graph.m-success svg g.m-node polygon {
+  stroke: #3bd267;
+}
 div.m-math.m-warning svg, svg.m-math.m-warning,
 div.m-math svg g.m-warning, svg.m-math g.m-warning,
 div.m-math svg rect.m-warning, svg.m-math rect.m-warning,
-div.m-plot svg .m-bar.m-warning {
+div.m-plot svg .m-bar.m-warning,
+div.m-graph.m-warning svg g.m-edge polygon,
+div.m-graph.m-warning svg g.m-node:not(.m-flat) ellipse,
+div.m-graph.m-warning svg g.m-node:not(.m-flat) polygon,
+div.m-graph.m-warning svg g.m-edge text,
+div.m-graph.m-warning svg g.m-node.m-flat text {
   fill: #c7cf2f;
 }
+div.m-graph.m-warning svg g.m-edge polygon,
+div.m-graph.m-warning svg g.m-edge path,
+div.m-graph.m-warning svg g.m-node ellipse,
+div.m-graph.m-warning svg g.m-node polygon {
+  stroke: #c7cf2f;
+}
 div.m-math.m-danger svg, svg.m-math.m-danger,
 div.m-math svg g.m-danger, svg.m-math g.m-danger,
 div.m-math svg rect.m-danger, svg.m-math rect.m-danger,
-div.m-plot svg .m-bar.m-danger {
+div.m-plot svg .m-bar.m-danger,
+div.m-graph.m-danger svg g.m-edge polygon,
+div.m-graph.m-danger svg g.m-node:not(.m-flat) ellipse,
+div.m-graph.m-danger svg g.m-node:not(.m-flat) polygon,
+div.m-graph.m-danger svg g.m-edge text,
+div.m-graph.m-danger svg g.m-node.m-flat text {
   fill: #cd3431;
 }
+div.m-graph.m-danger svg g.m-edge polygon,
+div.m-graph.m-danger svg g.m-edge path,
+div.m-graph.m-danger svg g.m-node ellipse,
+div.m-graph.m-danger svg g.m-node polygon {
+  stroke: #cd3431;
+}
 div.m-math.m-info svg, svg.m-math.m-info,
 div.m-math svg g.m-info, svg.m-math g.m-info,
 div.m-math svg rect.m-info, svg.m-math rect.m-info,
-div.m-plot svg .m-bar.m-info {
+div.m-plot svg .m-bar.m-info,
+div.m-graph.m-info svg g.m-edge polygon,
+div.m-graph.m-info svg g.m-node:not(.m-flat) ellipse,
+div.m-graph.m-info svg g.m-node:not(.m-flat) polygon,
+div.m-graph.m-info svg g.m-edge text,
+div.m-graph.m-info svg g.m-node.m-flat text {
   fill: #2f83cc;
 }
+div.m-graph.m-info svg g.m-edge polygon,
+div.m-graph.m-info svg g.m-edge path,
+div.m-graph.m-info svg g.m-node ellipse,
+div.m-graph.m-info svg g.m-node polygon {
+  stroke: #2f83cc;
+}
 div.m-math.m-dim svg, svg.m-math.m-dim,
 div.m-math svg g.m-dim, svg.m-math g.m-dim,
 div.m-math svg rect.m-dim, svg.m-math rect.m-dim,
-div.m-plot svg .m-bar.m-dim {
+div.m-plot svg .m-bar.m-dim,
+div.m-graph.m-dim svg g.m-edge polygon,
+div.m-graph.m-dim svg g.m-node:not(.m-flat) ellipse,
+div.m-graph.m-dim svg g.m-node:not(.m-flat) polygon,
+div.m-graph.m-dim svg g.m-edge text,
+div.m-graph.m-dim svg g.m-node.m-flat text {
   fill: #747474;
 }
+div.m-graph.m-dim svg g.m-edge polygon,
+div.m-graph.m-dim svg g.m-edge path,
+div.m-graph.m-dim svg g.m-node ellipse,
+div.m-graph.m-dim svg g.m-node polygon {
+  stroke: #747474;
+}
+div.m-graph svg g.m-edge.m-default polygon,
+div.m-graph svg g.m-node.m-default:not(.m-flat) ellipse,
+div.m-graph svg g.m-node.m-default:not(.m-flat) polygon,
+div.m-graph svg g.m-edge.m-default text,
+div.m-graph svg g.m-node.m-default.m-flat text {
+  fill: #dcdcdc;
+}
+div.m-graph svg g.m-edge.m-default polygon,
+div.m-graph svg g.m-edge.m-default path,
+div.m-graph svg g.m-node.m-default ellipse,
+div.m-graph svg g.m-node.m-default polygon {
+  stroke: #dcdcdc;
+}
+div.m-graph svg g.m-edge.m-primary polygon,
+div.m-graph svg g.m-node.m-primary:not(.m-flat) ellipse,
+div.m-graph svg g.m-node.m-primary:not(.m-flat) polygon,
+div.m-graph svg g.m-edge.m-primary text,
+div.m-graph svg g.m-node.m-primary.m-flat text {
+  fill: #a5c9ea;
+}
+div.m-graph svg g.m-edge.m-primary polygon,
+div.m-graph svg g.m-edge.m-primary path,
+div.m-graph svg g.m-node.m-primary ellipse,
+div.m-graph svg g.m-node.m-primary polygon {
+  stroke: #a5c9ea;
+}
+div.m-graph svg g.m-edge.m-success polygon,
+div.m-graph svg g.m-node.m-success:not(.m-flat) ellipse,
+div.m-graph svg g.m-node.m-success:not(.m-flat) polygon,
+div.m-graph svg g.m-edge.m-success text,
+div.m-graph svg g.m-node.m-success.m-flat text {
+  fill: #3bd267;
+}
+div.m-graph svg g.m-edge.m-success polygon,
+div.m-graph svg g.m-edge.m-success path,
+div.m-graph svg g.m-node.m-success ellipse,
+div.m-graph svg g.m-node.m-success polygon {
+  stroke: #3bd267;
+}
+div.m-graph svg g.m-edge.m-warning polygon,
+div.m-graph svg g.m-node.m-warning:not(.m-flat) ellipse,
+div.m-graph svg g.m-node.m-warning:not(.m-flat) polygon,
+div.m-graph svg g.m-edge.m-warning text,
+div.m-graph svg g.m-node.m-warning.m-flat text {
+  fill: #c7cf2f;
+}
+div.m-graph svg g.m-edge.m-warning polygon,
+div.m-graph svg g.m-edge.m-warning path,
+div.m-graph svg g.m-node.m-warning ellipse,
+div.m-graph svg g.m-node.m-warning polygon {
+  stroke: #c7cf2f;
+}
+div.m-graph svg g.m-edge.m-danger polygon,
+div.m-graph svg g.m-node.m-danger:not(.m-flat) ellipse,
+div.m-graph svg g.m-node.m-danger:not(.m-flat) polygon,
+div.m-graph svg g.m-edge.m-danger text,
+div.m-graph svg g.m-node.m-danger.m-flat text {
+  fill: #cd3431;
+}
+div.m-graph svg g.m-edge.m-danger polygon,
+div.m-graph svg g.m-edge.m-danger path,
+div.m-graph svg g.m-node.m-danger ellipse,
+div.m-graph svg g.m-node.m-danger polygon {
+  stroke: #cd3431;
+}
+div.m-graph svg g.m-edge.m-info polygon,
+div.m-graph svg g.m-node.m-info:not(.m-flat) ellipse,
+div.m-graph svg g.m-node.m-info:not(.m-flat) polygon,
+div.m-graph svg g.m-edge.m-info text,
+div.m-graph svg g.m-node.m-info.m-flat text {
+  fill: #2f83cc;
+}
+div.m-graph svg g.m-edge.m-info polygon,
+div.m-graph svg g.m-edge.m-info path,
+div.m-graph svg g.m-node.m-info ellipse,
+div.m-graph svg g.m-node.m-info polygon {
+  stroke: #2f83cc;
+}
+div.m-graph svg g.m-edge.m-dim polygon,
+div.m-graph svg g.m-node.m-dim:not(.m-flat) ellipse,
+div.m-graph svg g.m-node.m-dim:not(.m-flat) polygon,
+div.m-graph svg g.m-edge.m-dim text,
+div.m-graph svg g.m-node.m-dim.m-flat text {
+  fill: #747474;
+}
+div.m-graph svg g.m-edge.m-dim polygon,
+div.m-graph svg g.m-edge.m-dim path,
+div.m-graph svg g.m-node.m-dim ellipse,
+div.m-graph svg g.m-node.m-dim polygon {
+  stroke: #747474;
+}
 p, ul, ol, dl, blockquote, pre, figure.m-code-figure, figure.m-console-figure,
 hr, .m-note, .m-frame, .m-block, div.m-button, div.m-scroll, table.m-table,
 div.m-image, img.m-image, svg.m-image, figure.m-figure, .m-imagegrid, div.m-math {
index 67517091e81b58f7e62f5422c87fc409a0b62aad..30e657e3d26d270c93ab50cce7de0190f7eea2b4 100644 (file)
@@ -1268,12 +1268,9 @@ div.m-button.m-flat a:hover svg.m-math, div.m-button.m-default a:focus svg.m-mat
 div.m-button.m-default a:active svg.m-math {
   fill: #cb4b16;
 }
-div.m-plot svg {
-  text-align: center;
-}
-div.m-plot .m-background {
-  fill: #fbf0ec;
-}
+div.m-plot, div.m-graph { text-align: center; }
+div.m-plot svg, div.m-graph svg { max-width: 100%; }
+div.m-plot .m-background { fill: #fbf0ec; }
 div.m-plot svg .m-label { font-size: 11px; }
 div.m-plot svg .m-title { font-size: 13px; }
 div.m-plot svg .m-label, div.m-plot svg .m-title { fill: #000000; }
@@ -1286,49 +1283,233 @@ div.m-plot svg .m-error {
   stroke-width: 1.5;
 }
 div.m-plot svg .m-label.m-dim { fill: #bdbdbd; }
+div.m-graph svg g.m-edge path, div.m-graph svg g.m-node.m-flat ellipse,
+div.m-graph svg g.m-node.m-flat polygon {
+  fill: none;
+}
+div.m-graph svg g.m-node:not(.m-flat) text {
+  fill: #ffffff;
+}
 div.m-math svg, svg.m-math { fill: #000000; }
 div.m-math.m-default svg, svg.m-math.m-default,
 div.m-math svg g.m-default, svg.m-math g.m-default,
 div.m-math svg rect.m-default, svg.m-math rect.m-default,
-div.m-plot svg .m-bar.m-default {
+div.m-plot svg .m-bar.m-default,
+div.m-graph svg g.m-edge polygon,
+div.m-graph svg g.m-node:not(.m-flat) ellipse,
+div.m-graph svg g.m-node:not(.m-flat) polygon,
+div.m-graph svg g.m-edge text,
+div.m-graph svg g.m-node.m-flat text,
+div.m-graph.m-default svg g.m-edge polygon,
+div.m-graph.m-default svg g.m-node:not(.m-flat) ellipse,
+div.m-graph.m-default svg g.m-node:not(.m-flat) polygon,
+div.m-graph.m-default svg g.m-edge text,
+div.m-graph.m-default svg g.m-node.m-flat text {
   fill: #000000;
 }
+div.m-graph svg g.m-edge polygon,
+div.m-graph svg g.m-edge path,
+div.m-graph svg g.m-node ellipse,
+div.m-graph svg g.m-node polygon,
+div.m-graph.m-default svg g.m-edge polygon,
+div.m-graph.m-default svg g.m-edge path,
+div.m-graph.m-default svg g.m-node ellipse,
+div.m-graph.m-default svg g.m-node polygon {
+  stroke: #000000;
+}
 div.m-math.m-primary svg, svg.m-math.m-primary,
 div.m-math svg g.m-primary, svg.m-math g.m-primary,
 div.m-math svg rect.m-primary, svg.m-math rect.m-primary,
-div.m-plot svg .m-bar.m-primary {
+div.m-plot svg .m-bar.m-primary,
+div.m-graph.m-primary svg g.m-edge polygon,
+div.m-graph.m-primary svg g.m-node:not(.m-flat) ellipse,
+div.m-graph.m-primary svg g.m-node:not(.m-flat) polygon,
+div.m-graph.m-primary svg g.m-edge text,
+div.m-graph.m-primary svg g.m-node.m-flat text {
   fill: #cb4b16;
 }
+div.m-graph.m-primary svg g.m-edge polygon,
+div.m-graph.m-primary svg g.m-edge path,
+div.m-graph.m-primary svg g.m-node ellipse,
+div.m-graph.m-primary svg g.m-node polygon {
+  stroke: #cb4b16;
+}
 div.m-math.m-success svg, svg.m-math.m-success,
 div.m-math svg g.m-success, svg.m-math g.m-success,
 div.m-math svg rect.m-success, svg.m-math rect.m-success,
-div.m-plot svg .m-bar.m-success {
+div.m-plot svg .m-bar.m-success,
+div.m-graph.m-success svg g.m-edge polygon,
+div.m-graph.m-success svg g.m-node:not(.m-flat) ellipse,
+div.m-graph.m-success svg g.m-node:not(.m-flat) polygon,
+div.m-graph.m-success svg g.m-edge text,
+div.m-graph.m-success svg g.m-node.m-flat text {
   fill: #31c25d;
 }
+div.m-graph.m-success svg g.m-edge polygon,
+div.m-graph.m-success svg g.m-edge path,
+div.m-graph.m-success svg g.m-node ellipse,
+div.m-graph.m-success svg g.m-node polygon {
+  stroke: #31c25d;
+}
 div.m-math.m-warning svg, svg.m-math.m-warning,
 div.m-math svg g.m-warning, svg.m-math g.m-warning,
 div.m-math svg rect.m-warning, svg.m-math rect.m-warning,
-div.m-plot svg .m-bar.m-warning {
+div.m-plot svg .m-bar.m-warning,
+div.m-graph.m-warning svg g.m-edge polygon,
+div.m-graph.m-warning svg g.m-node:not(.m-flat) ellipse,
+div.m-graph.m-warning svg g.m-node:not(.m-flat) polygon,
+div.m-graph.m-warning svg g.m-edge text,
+div.m-graph.m-warning svg g.m-node.m-flat text {
   fill: #c7cf2f;
 }
+div.m-graph.m-warning svg g.m-edge polygon,
+div.m-graph.m-warning svg g.m-edge path,
+div.m-graph.m-warning svg g.m-node ellipse,
+div.m-graph.m-warning svg g.m-node polygon {
+  stroke: #c7cf2f;
+}
 div.m-math.m-danger svg, svg.m-math.m-danger,
 div.m-math svg g.m-danger, svg.m-math g.m-danger,
 div.m-math svg rect.m-danger, svg.m-math rect.m-danger,
-div.m-plot svg .m-bar.m-danger {
+div.m-plot svg .m-bar.m-danger,
+div.m-graph.m-danger svg g.m-edge polygon,
+div.m-graph.m-danger svg g.m-node:not(.m-flat) ellipse,
+div.m-graph.m-danger svg g.m-node:not(.m-flat) polygon,
+div.m-graph.m-danger svg g.m-edge text,
+div.m-graph.m-danger svg g.m-node.m-flat text {
   fill: #f60000;
 }
+div.m-graph.m-danger svg g.m-edge polygon,
+div.m-graph.m-danger svg g.m-edge path,
+div.m-graph.m-danger svg g.m-node ellipse,
+div.m-graph.m-danger svg g.m-node polygon {
+  stroke: #f60000;
+}
 div.m-math.m-info svg, svg.m-math.m-info,
 div.m-math svg g.m-info, svg.m-math g.m-info,
 div.m-math svg rect.m-info, svg.m-math rect.m-info,
-div.m-plot svg .m-bar.m-info {
+div.m-plot svg .m-bar.m-info,
+div.m-graph.m-info svg g.m-edge polygon,
+div.m-graph.m-info svg g.m-node:not(.m-flat) ellipse,
+div.m-graph.m-info svg g.m-node:not(.m-flat) polygon,
+div.m-graph.m-info svg g.m-edge text,
+div.m-graph.m-info svg g.m-node.m-flat text {
   fill: #2e7dc5;
 }
+div.m-graph.m-info svg g.m-edge polygon,
+div.m-graph.m-info svg g.m-edge path,
+div.m-graph.m-info svg g.m-node ellipse,
+div.m-graph.m-info svg g.m-node polygon {
+  stroke: #2e7dc5;
+}
 div.m-math.m-dim svg, svg.m-math.m-dim,
 div.m-math svg g.m-dim, svg.m-math g.m-dim,
 div.m-math svg rect.m-dim, svg.m-math rect.m-dim,
-div.m-plot svg .m-bar.m-dim {
+div.m-plot svg .m-bar.m-dim,
+div.m-graph.m-dim svg g.m-edge polygon,
+div.m-graph.m-dim svg g.m-node:not(.m-flat) ellipse,
+div.m-graph.m-dim svg g.m-node:not(.m-flat) polygon,
+div.m-graph.m-dim svg g.m-edge text,
+div.m-graph.m-dim svg g.m-node.m-flat text {
   fill: #bdbdbd;
 }
+div.m-graph.m-dim svg g.m-edge polygon,
+div.m-graph.m-dim svg g.m-edge path,
+div.m-graph.m-dim svg g.m-node ellipse,
+div.m-graph.m-dim svg g.m-node polygon {
+  stroke: #bdbdbd;
+}
+div.m-graph svg g.m-edge.m-default polygon,
+div.m-graph svg g.m-node.m-default:not(.m-flat) ellipse,
+div.m-graph svg g.m-node.m-default:not(.m-flat) polygon,
+div.m-graph svg g.m-edge.m-default text,
+div.m-graph svg g.m-node.m-default.m-flat text {
+  fill: #000000;
+}
+div.m-graph svg g.m-edge.m-default polygon,
+div.m-graph svg g.m-edge.m-default path,
+div.m-graph svg g.m-node.m-default ellipse,
+div.m-graph svg g.m-node.m-default polygon {
+  stroke: #000000;
+}
+div.m-graph svg g.m-edge.m-primary polygon,
+div.m-graph svg g.m-node.m-primary:not(.m-flat) ellipse,
+div.m-graph svg g.m-node.m-primary:not(.m-flat) polygon,
+div.m-graph svg g.m-edge.m-primary text,
+div.m-graph svg g.m-node.m-primary.m-flat text {
+  fill: #cb4b16;
+}
+div.m-graph svg g.m-edge.m-primary polygon,
+div.m-graph svg g.m-edge.m-primary path,
+div.m-graph svg g.m-node.m-primary ellipse,
+div.m-graph svg g.m-node.m-primary polygon {
+  stroke: #cb4b16;
+}
+div.m-graph svg g.m-edge.m-success polygon,
+div.m-graph svg g.m-node.m-success:not(.m-flat) ellipse,
+div.m-graph svg g.m-node.m-success:not(.m-flat) polygon,
+div.m-graph svg g.m-edge.m-success text,
+div.m-graph svg g.m-node.m-success.m-flat text {
+  fill: #31c25d;
+}
+div.m-graph svg g.m-edge.m-success polygon,
+div.m-graph svg g.m-edge.m-success path,
+div.m-graph svg g.m-node.m-success ellipse,
+div.m-graph svg g.m-node.m-success polygon {
+  stroke: #31c25d;
+}
+div.m-graph svg g.m-edge.m-warning polygon,
+div.m-graph svg g.m-node.m-warning:not(.m-flat) ellipse,
+div.m-graph svg g.m-node.m-warning:not(.m-flat) polygon,
+div.m-graph svg g.m-edge.m-warning text,
+div.m-graph svg g.m-node.m-warning.m-flat text {
+  fill: #c7cf2f;
+}
+div.m-graph svg g.m-edge.m-warning polygon,
+div.m-graph svg g.m-edge.m-warning path,
+div.m-graph svg g.m-node.m-warning ellipse,
+div.m-graph svg g.m-node.m-warning polygon {
+  stroke: #c7cf2f;
+}
+div.m-graph svg g.m-edge.m-danger polygon,
+div.m-graph svg g.m-node.m-danger:not(.m-flat) ellipse,
+div.m-graph svg g.m-node.m-danger:not(.m-flat) polygon,
+div.m-graph svg g.m-edge.m-danger text,
+div.m-graph svg g.m-node.m-danger.m-flat text {
+  fill: #f60000;
+}
+div.m-graph svg g.m-edge.m-danger polygon,
+div.m-graph svg g.m-edge.m-danger path,
+div.m-graph svg g.m-node.m-danger ellipse,
+div.m-graph svg g.m-node.m-danger polygon {
+  stroke: #f60000;
+}
+div.m-graph svg g.m-edge.m-info polygon,
+div.m-graph svg g.m-node.m-info:not(.m-flat) ellipse,
+div.m-graph svg g.m-node.m-info:not(.m-flat) polygon,
+div.m-graph svg g.m-edge.m-info text,
+div.m-graph svg g.m-node.m-info.m-flat text {
+  fill: #2e7dc5;
+}
+div.m-graph svg g.m-edge.m-info polygon,
+div.m-graph svg g.m-edge.m-info path,
+div.m-graph svg g.m-node.m-info ellipse,
+div.m-graph svg g.m-node.m-info polygon {
+  stroke: #2e7dc5;
+}
+div.m-graph svg g.m-edge.m-dim polygon,
+div.m-graph svg g.m-node.m-dim:not(.m-flat) ellipse,
+div.m-graph svg g.m-node.m-dim:not(.m-flat) polygon,
+div.m-graph svg g.m-edge.m-dim text,
+div.m-graph svg g.m-node.m-dim.m-flat text {
+  fill: #bdbdbd;
+}
+div.m-graph svg g.m-edge.m-dim polygon,
+div.m-graph svg g.m-edge.m-dim path,
+div.m-graph svg g.m-node.m-dim ellipse,
+div.m-graph svg g.m-node.m-dim polygon {
+  stroke: #bdbdbd;
+}
 p, ul, ol, dl, blockquote, pre, figure.m-code-figure, figure.m-console-figure,
 hr, .m-note, .m-frame, .m-block, div.m-button, div.m-scroll, table.m-table,
 div.m-image, img.m-image, svg.m-image, figure.m-figure, .m-imagegrid, div.m-math {
index ace533f74997f09f8512c625194b81bc849477a0..a2ef11c8b931aec960033b79fbbc218d8010fd43 100644 (file)
@@ -1268,12 +1268,9 @@ div.m-button.m-flat a:hover svg.m-math, div.m-button.m-default a:focus svg.m-mat
 div.m-button.m-default a:active svg.m-math {
   fill: #cb4b16;
 }
-div.m-plot svg {
-  text-align: center;
-}
-div.m-plot .m-background {
-  fill: #fbf0ec;
-}
+div.m-plot, div.m-graph { text-align: center; }
+div.m-plot svg, div.m-graph svg { max-width: 100%; }
+div.m-plot .m-background { fill: #fbf0ec; }
 div.m-plot svg .m-label { font-size: 11px; }
 div.m-plot svg .m-title { font-size: 13px; }
 div.m-plot svg .m-label, div.m-plot svg .m-title { fill: #000000; }
@@ -1286,49 +1283,233 @@ div.m-plot svg .m-error {
   stroke-width: 1.5;
 }
 div.m-plot svg .m-label.m-dim { fill: #bdbdbd; }
+div.m-graph svg g.m-edge path, div.m-graph svg g.m-node.m-flat ellipse,
+div.m-graph svg g.m-node.m-flat polygon {
+  fill: none;
+}
+div.m-graph svg g.m-node:not(.m-flat) text {
+  fill: #ffffff;
+}
 div.m-math svg, svg.m-math { fill: #000000; }
 div.m-math.m-default svg, svg.m-math.m-default,
 div.m-math svg g.m-default, svg.m-math g.m-default,
 div.m-math svg rect.m-default, svg.m-math rect.m-default,
-div.m-plot svg .m-bar.m-default {
+div.m-plot svg .m-bar.m-default,
+div.m-graph svg g.m-edge polygon,
+div.m-graph svg g.m-node:not(.m-flat) ellipse,
+div.m-graph svg g.m-node:not(.m-flat) polygon,
+div.m-graph svg g.m-edge text,
+div.m-graph svg g.m-node.m-flat text,
+div.m-graph.m-default svg g.m-edge polygon,
+div.m-graph.m-default svg g.m-node:not(.m-flat) ellipse,
+div.m-graph.m-default svg g.m-node:not(.m-flat) polygon,
+div.m-graph.m-default svg g.m-edge text,
+div.m-graph.m-default svg g.m-node.m-flat text {
   fill: #000000;
 }
+div.m-graph svg g.m-edge polygon,
+div.m-graph svg g.m-edge path,
+div.m-graph svg g.m-node ellipse,
+div.m-graph svg g.m-node polygon,
+div.m-graph.m-default svg g.m-edge polygon,
+div.m-graph.m-default svg g.m-edge path,
+div.m-graph.m-default svg g.m-node ellipse,
+div.m-graph.m-default svg g.m-node polygon {
+  stroke: #000000;
+}
 div.m-math.m-primary svg, svg.m-math.m-primary,
 div.m-math svg g.m-primary, svg.m-math g.m-primary,
 div.m-math svg rect.m-primary, svg.m-math rect.m-primary,
-div.m-plot svg .m-bar.m-primary {
+div.m-plot svg .m-bar.m-primary,
+div.m-graph.m-primary svg g.m-edge polygon,
+div.m-graph.m-primary svg g.m-node:not(.m-flat) ellipse,
+div.m-graph.m-primary svg g.m-node:not(.m-flat) polygon,
+div.m-graph.m-primary svg g.m-edge text,
+div.m-graph.m-primary svg g.m-node.m-flat text {
   fill: #cb4b16;
 }
+div.m-graph.m-primary svg g.m-edge polygon,
+div.m-graph.m-primary svg g.m-edge path,
+div.m-graph.m-primary svg g.m-node ellipse,
+div.m-graph.m-primary svg g.m-node polygon {
+  stroke: #cb4b16;
+}
 div.m-math.m-success svg, svg.m-math.m-success,
 div.m-math svg g.m-success, svg.m-math g.m-success,
 div.m-math svg rect.m-success, svg.m-math rect.m-success,
-div.m-plot svg .m-bar.m-success {
+div.m-plot svg .m-bar.m-success,
+div.m-graph.m-success svg g.m-edge polygon,
+div.m-graph.m-success svg g.m-node:not(.m-flat) ellipse,
+div.m-graph.m-success svg g.m-node:not(.m-flat) polygon,
+div.m-graph.m-success svg g.m-edge text,
+div.m-graph.m-success svg g.m-node.m-flat text {
   fill: #31c25d;
 }
+div.m-graph.m-success svg g.m-edge polygon,
+div.m-graph.m-success svg g.m-edge path,
+div.m-graph.m-success svg g.m-node ellipse,
+div.m-graph.m-success svg g.m-node polygon {
+  stroke: #31c25d;
+}
 div.m-math.m-warning svg, svg.m-math.m-warning,
 div.m-math svg g.m-warning, svg.m-math g.m-warning,
 div.m-math svg rect.m-warning, svg.m-math rect.m-warning,
-div.m-plot svg .m-bar.m-warning {
+div.m-plot svg .m-bar.m-warning,
+div.m-graph.m-warning svg g.m-edge polygon,
+div.m-graph.m-warning svg g.m-node:not(.m-flat) ellipse,
+div.m-graph.m-warning svg g.m-node:not(.m-flat) polygon,
+div.m-graph.m-warning svg g.m-edge text,
+div.m-graph.m-warning svg g.m-node.m-flat text {
   fill: #c7cf2f;
 }
+div.m-graph.m-warning svg g.m-edge polygon,
+div.m-graph.m-warning svg g.m-edge path,
+div.m-graph.m-warning svg g.m-node ellipse,
+div.m-graph.m-warning svg g.m-node polygon {
+  stroke: #c7cf2f;
+}
 div.m-math.m-danger svg, svg.m-math.m-danger,
 div.m-math svg g.m-danger, svg.m-math g.m-danger,
 div.m-math svg rect.m-danger, svg.m-math rect.m-danger,
-div.m-plot svg .m-bar.m-danger {
+div.m-plot svg .m-bar.m-danger,
+div.m-graph.m-danger svg g.m-edge polygon,
+div.m-graph.m-danger svg g.m-node:not(.m-flat) ellipse,
+div.m-graph.m-danger svg g.m-node:not(.m-flat) polygon,
+div.m-graph.m-danger svg g.m-edge text,
+div.m-graph.m-danger svg g.m-node.m-flat text {
   fill: #f60000;
 }
+div.m-graph.m-danger svg g.m-edge polygon,
+div.m-graph.m-danger svg g.m-edge path,
+div.m-graph.m-danger svg g.m-node ellipse,
+div.m-graph.m-danger svg g.m-node polygon {
+  stroke: #f60000;
+}
 div.m-math.m-info svg, svg.m-math.m-info,
 div.m-math svg g.m-info, svg.m-math g.m-info,
 div.m-math svg rect.m-info, svg.m-math rect.m-info,
-div.m-plot svg .m-bar.m-info {
+div.m-plot svg .m-bar.m-info,
+div.m-graph.m-info svg g.m-edge polygon,
+div.m-graph.m-info svg g.m-node:not(.m-flat) ellipse,
+div.m-graph.m-info svg g.m-node:not(.m-flat) polygon,
+div.m-graph.m-info svg g.m-edge text,
+div.m-graph.m-info svg g.m-node.m-flat text {
   fill: #2e7dc5;
 }
+div.m-graph.m-info svg g.m-edge polygon,
+div.m-graph.m-info svg g.m-edge path,
+div.m-graph.m-info svg g.m-node ellipse,
+div.m-graph.m-info svg g.m-node polygon {
+  stroke: #2e7dc5;
+}
 div.m-math.m-dim svg, svg.m-math.m-dim,
 div.m-math svg g.m-dim, svg.m-math g.m-dim,
 div.m-math svg rect.m-dim, svg.m-math rect.m-dim,
-div.m-plot svg .m-bar.m-dim {
+div.m-plot svg .m-bar.m-dim,
+div.m-graph.m-dim svg g.m-edge polygon,
+div.m-graph.m-dim svg g.m-node:not(.m-flat) ellipse,
+div.m-graph.m-dim svg g.m-node:not(.m-flat) polygon,
+div.m-graph.m-dim svg g.m-edge text,
+div.m-graph.m-dim svg g.m-node.m-flat text {
   fill: #bdbdbd;
 }
+div.m-graph.m-dim svg g.m-edge polygon,
+div.m-graph.m-dim svg g.m-edge path,
+div.m-graph.m-dim svg g.m-node ellipse,
+div.m-graph.m-dim svg g.m-node polygon {
+  stroke: #bdbdbd;
+}
+div.m-graph svg g.m-edge.m-default polygon,
+div.m-graph svg g.m-node.m-default:not(.m-flat) ellipse,
+div.m-graph svg g.m-node.m-default:not(.m-flat) polygon,
+div.m-graph svg g.m-edge.m-default text,
+div.m-graph svg g.m-node.m-default.m-flat text {
+  fill: #000000;
+}
+div.m-graph svg g.m-edge.m-default polygon,
+div.m-graph svg g.m-edge.m-default path,
+div.m-graph svg g.m-node.m-default ellipse,
+div.m-graph svg g.m-node.m-default polygon {
+  stroke: #000000;
+}
+div.m-graph svg g.m-edge.m-primary polygon,
+div.m-graph svg g.m-node.m-primary:not(.m-flat) ellipse,
+div.m-graph svg g.m-node.m-primary:not(.m-flat) polygon,
+div.m-graph svg g.m-edge.m-primary text,
+div.m-graph svg g.m-node.m-primary.m-flat text {
+  fill: #cb4b16;
+}
+div.m-graph svg g.m-edge.m-primary polygon,
+div.m-graph svg g.m-edge.m-primary path,
+div.m-graph svg g.m-node.m-primary ellipse,
+div.m-graph svg g.m-node.m-primary polygon {
+  stroke: #cb4b16;
+}
+div.m-graph svg g.m-edge.m-success polygon,
+div.m-graph svg g.m-node.m-success:not(.m-flat) ellipse,
+div.m-graph svg g.m-node.m-success:not(.m-flat) polygon,
+div.m-graph svg g.m-edge.m-success text,
+div.m-graph svg g.m-node.m-success.m-flat text {
+  fill: #31c25d;
+}
+div.m-graph svg g.m-edge.m-success polygon,
+div.m-graph svg g.m-edge.m-success path,
+div.m-graph svg g.m-node.m-success ellipse,
+div.m-graph svg g.m-node.m-success polygon {
+  stroke: #31c25d;
+}
+div.m-graph svg g.m-edge.m-warning polygon,
+div.m-graph svg g.m-node.m-warning:not(.m-flat) ellipse,
+div.m-graph svg g.m-node.m-warning:not(.m-flat) polygon,
+div.m-graph svg g.m-edge.m-warning text,
+div.m-graph svg g.m-node.m-warning.m-flat text {
+  fill: #c7cf2f;
+}
+div.m-graph svg g.m-edge.m-warning polygon,
+div.m-graph svg g.m-edge.m-warning path,
+div.m-graph svg g.m-node.m-warning ellipse,
+div.m-graph svg g.m-node.m-warning polygon {
+  stroke: #c7cf2f;
+}
+div.m-graph svg g.m-edge.m-danger polygon,
+div.m-graph svg g.m-node.m-danger:not(.m-flat) ellipse,
+div.m-graph svg g.m-node.m-danger:not(.m-flat) polygon,
+div.m-graph svg g.m-edge.m-danger text,
+div.m-graph svg g.m-node.m-danger.m-flat text {
+  fill: #f60000;
+}
+div.m-graph svg g.m-edge.m-danger polygon,
+div.m-graph svg g.m-edge.m-danger path,
+div.m-graph svg g.m-node.m-danger ellipse,
+div.m-graph svg g.m-node.m-danger polygon {
+  stroke: #f60000;
+}
+div.m-graph svg g.m-edge.m-info polygon,
+div.m-graph svg g.m-node.m-info:not(.m-flat) ellipse,
+div.m-graph svg g.m-node.m-info:not(.m-flat) polygon,
+div.m-graph svg g.m-edge.m-info text,
+div.m-graph svg g.m-node.m-info.m-flat text {
+  fill: #2e7dc5;
+}
+div.m-graph svg g.m-edge.m-info polygon,
+div.m-graph svg g.m-edge.m-info path,
+div.m-graph svg g.m-node.m-info ellipse,
+div.m-graph svg g.m-node.m-info polygon {
+  stroke: #2e7dc5;
+}
+div.m-graph svg g.m-edge.m-dim polygon,
+div.m-graph svg g.m-node.m-dim:not(.m-flat) ellipse,
+div.m-graph svg g.m-node.m-dim:not(.m-flat) polygon,
+div.m-graph svg g.m-edge.m-dim text,
+div.m-graph svg g.m-node.m-dim.m-flat text {
+  fill: #bdbdbd;
+}
+div.m-graph svg g.m-edge.m-dim polygon,
+div.m-graph svg g.m-edge.m-dim path,
+div.m-graph svg g.m-node.m-dim ellipse,
+div.m-graph svg g.m-node.m-dim polygon {
+  stroke: #bdbdbd;
+}
 p, ul, ol, dl, blockquote, pre, figure.m-code-figure, figure.m-console-figure,
 hr, .m-note, .m-frame, .m-block, div.m-button, div.m-scroll, table.m-table,
 div.m-image, img.m-image, svg.m-image, figure.m-figure, .m-imagegrid, div.m-math {
index 8980414db3f5e77e8469bfd22fdfd0aaf84cf022..cd8d1e0b542f410cab8bc3dc4dfaf090763f4b0b 100644 (file)
@@ -1102,12 +1102,90 @@ with :css:`.m-line`, error bars with :css:`.m-error`. Use
         .. raw:: html
             :file: components-plot.svg
 
-.. note-success::
+.. note-info::
 
     Plot styling is designed to be used with extenal tools, for example Python
-    Matplotlib. If you use Pelican, m.css has a `Plots <{filename}/plugins/plots.rst>`__
-    plugin that allows you to produce plots using :rst:`.. plot::` directives
-    directly in your :abbr:`reST <reStructuredText>` markup.
+    Matplotlib. If you use Pelican, m.css has a
+    `m.plots <{filename}/plugins/plots-and-graphs.rst#plots>`__ plugin that
+    allows you to produce plots using :rst:`.. plot::` directives directly in
+    your :abbr:`reST <reStructuredText>` markup.
+
+`Graphs`_
+=========
+
+Wrap a :html:`<svg>` element in a :html:`<div class="m-graph">` to make it
+centered and occupying full width at most. Wrap edge :html:`<path>`,
+:html:`<polygon>` and :html:`<text>` elements in :html:`<g class="m-edge">` to
+style them as edges, wrap node :html:`<polygon>`, :html:`<ellipse>` and
+:html:`<text>` elements in :html:`<g class="m-node">` to style them as nodes.
+You can use `CSS color classes <#colors>`_ on either the wrapper :html:`<div>`
+or on the :html:`<g>` to color the whole graph or its parts. Use :css:`.m-flat`
+on a :css:`.m-node` to make it just an outline instead of filled.
+
+.. code-figure::
+
+    .. code:: html
+
+        <div class="m-graph m-info"><svg>
+          <g class="m-node">
+            <ellipse cx="27.5772" cy="-27.5772" rx="27.6545" ry="27.6545"/>
+            <text text-anchor="middle" x="27.5772" y="-23.7772">yes</text>
+          </g>
+          <g class="m-node m-flat">
+            <ellipse cx="134.9031" cy="-27.5772" rx="25" ry="25"/>
+            <text text-anchor="middle" x="134.9031" y="-23.7772">no</text>
+          </g>
+          <g class="m-edge">
+            <path d="M55.2163,-27.5772C68.8104,-27.5772 85.3444,-27.5772 99.8205,-27.5772"/>
+            <polygon points="99.9261,-31.0773 109.9261,-27.5772 99.9261,-24.0773 99.9261,-31.0773"/>
+            <text text-anchor="middle" x="82.6543" y="-32.7772">no</text>
+          </g>
+          <g class="m-edge m-dim">
+            <path d="M125.3459,-50.4471C124.3033,-61.0564 127.489,-70.3259 134.9031,-70.3259 139.7685,-70.3259 142.813,-66.3338 144.0365,-60.5909"/>
+            <polygon points="147.5398,-60.5845 144.4603,-50.4471 140.5459,-60.2923 147.5398,-60.5845"/>
+            <text text-anchor="middle" x="134.9031" y="-75.5259">no</text>
+          </g>
+        </svg></div>
+
+    .. raw:: html
+
+        <div class="m-graph m-info">
+        <svg style="width: 10.500rem; height: 6.000rem;" viewBox="0.00 0.00 167.65 96.33">
+        <g transform="scale(1 1) rotate(0) translate(4 92.3259)">
+        <title>FSM</title>
+        <g class="m-node">
+        <title>yes</title>
+        <ellipse cx="27.5772" cy="-27.5772" rx="27.6545" ry="27.6545"/>
+        <text text-anchor="middle" x="27.5772" y="-23.7772">yes</text>
+        </g>
+        <g class="m-node m-flat">
+        <title>no</title>
+        <ellipse cx="134.9031" cy="-27.5772" rx="25" ry="25"/>
+        <text text-anchor="middle" x="134.9031" y="-23.7772">no</text>
+        </g>
+        <g class="m-edge">
+        <title>yes&#45;&gt;no</title>
+        <path d="M55.2163,-27.5772C68.8104,-27.5772 85.3444,-27.5772 99.8205,-27.5772"/>
+        <polygon points="99.9261,-31.0773 109.9261,-27.5772 99.9261,-24.0773 99.9261,-31.0773"/>
+        <text text-anchor="middle" x="82.6543" y="-32.7772">no</text>
+        </g>
+        <g class="m-edge m-dim">
+        <title>no&#45;&gt;no</title>
+        <path d="M125.3459,-50.4471C124.3033,-61.0564 127.489,-70.3259 134.9031,-70.3259 139.7685,-70.3259 142.813,-66.3338 144.0365,-60.5909"/>
+        <polygon points="147.5398,-60.5845 144.4603,-50.4471 140.5459,-60.2923 147.5398,-60.5845"/>
+        <text text-anchor="middle" x="134.9031" y="-75.5259">no</text>
+        </g>
+        </g>
+        </svg>
+        </div>
+
+.. note-primary::
+
+    Similarly to plot styling, graph styling is designed to be used with
+    external tools, for example Graphviz. If you use Pelican, m.css has a
+    `m.dot <{filename}/plugins/plots-and-graphs.rst#graphs>`__ plugin that
+    allows you to produce plots using :rst:`.. graph::` directives directly in
+    your :abbr:`reST <reStructuredText>` markup.
 
 `Padding`_
 ==========
index 9a4de1efd578030a1b6fe68358f3258d7467cdf6..1ab7289f35826a96cf39847a2efa2fc7b33ec797 100644 (file)
@@ -45,7 +45,8 @@ and restart Pelican. Download the plugins below or
 -   :gh:`m.images <mosra/m.css$master/pelican-plugins/m/images.py>`
 -   :gh:`m.math  <mosra/m.css$master/pelican-plugins/m/math.py>` (needs also :gh:`latex2svg <mosra/m.css$master/pelican-plugins/latex2svg.py>`),
     :gh:`m.code <mosra/m.css$master/pelican-plugins/m/code.py>` (needs also :gh:`ansilexer <mosra/m.css$master/pelican-plugins/ansilexer.py>`)
--   :gh:`m.plots <mosra/m.css$master/pelican-plugins/m/plots.py>`
+-   :gh:`m.plots <mosra/m.css$master/pelican-plugins/m/plots.py>`,
+    :gh:`m.dot <mosra/m.css$master/pelican-plugins/m/dot.py>`
 -   :gh:`m.gh <mosra/m.css$master/pelican-plugins/m/gh.py>`,
     :gh:`m.dox <mosra/m.css$master/pelican-plugins/m/dox.py>`,
     :gh:`m.gl <mosra/m.css$master/pelican-plugins/m/gl.py>`,
@@ -88,12 +89,13 @@ rendering and syntax highlighting, so they are provided as separate packages
 that you can but don't have to use. With these, math and code snippets can be
 entered directly in your :abbr:`reST <reStructuredText>` sources.
 
-`Plots » <{filename}/plugins/plots.rst>`_
-===================================================
+`Plots and graphs » <{filename}/plugins/plots-and-graphs.rst>`_
+===============================================================
 
-With :py:`m.plots` you can render various graphs and charts directly from
-values in your :abbr:`reST <reStructuredText>` sources. The result is embedded
-as an inline SVG and can be styled using CSS like everything else.
+With :py:`m.plots` and :py:`m.dot` you can render various graphs and charts
+directly from values in your :abbr:`reST <reStructuredText>` sources. The
+result is embedded as an inline SVG and can be styled using CSS like everything
+else.
 
 `Links and other » <{filename}/plugins/links.rst>`_
 ===================================================
index 6ee440009f1153d8a46ad8f2b7cb8451a6e97d44..bd355ac3ca5a0d460daa54a8e65db9edf366179c 100644 (file)
@@ -30,7 +30,7 @@ Links and other
     .. note-dim::
         :class: m-text-center
 
-        `« Plots <{filename}/plugins/plots.rst>`_ | `Pelican plugins <{filename}/plugins.rst>`_ | `Metadata » <{filename}/plugins/metadata.rst>`_
+        `« Plots and graphs <{filename}/plugins/plots-and-graphs.rst>`_ | `Pelican plugins <{filename}/plugins.rst>`_ | `Metadata » <{filename}/plugins/metadata.rst>`_
 
 .. role:: py(code)
     :language: py
index 711784428e32b789d8f6295b4d6ba00a88e6938b..69014ab5f685b0c4c1bb0483251683e796aa8d1f 100644 (file)
@@ -30,7 +30,7 @@ Math and code
     .. note-dim::
         :class: m-text-center
 
-        `« Images <{filename}/plugins/images.rst>`_ | `Pelican plugins <{filename}/plugins.rst>`_ | `Plots » <{filename}/plugins/plots.rst>`_
+        `« Images <{filename}/plugins/images.rst>`_ | `Pelican plugins <{filename}/plugins.rst>`_ | `Plots and graphs » <{filename}/plugins/plots-and-graphs.rst>`_
 
 .. role:: css(code)
     :language: css
diff --git a/doc/plugins/plots-and-graphs-test.rst b/doc/plugins/plots-and-graphs-test.rst
new file mode 100644 (file)
index 0000000..cc2f448
--- /dev/null
@@ -0,0 +1,292 @@
+..
+    This file is part of m.css.
+
+    Copyright © 2017, 2018 Vladimír Vondruš <mosra@centrum.cz>
+
+    Permission is hereby granted, free of charge, to any person obtaining a
+    copy of this software and associated documentation files (the "Software"),
+    to deal in the Software without restriction, including without limitation
+    the rights to use, copy, modify, merge, publish, distribute, sublicense,
+    and/or sell copies of the Software, and to permit persons to whom the
+    Software is furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice shall be included
+    in all copies or substantial portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+    DEALINGS IN THE SOFTWARE.
+..
+
+Test
+####
+
+:save_as: plugins/plots-and-graphs/test/index.html
+:breadcrumb: {filename}/plugins.rst Pelican plugins
+             {filename}/plugins/plots-and-graphs.rst Plots and graphs
+
+Plots
+=====
+
+.. container:: m-row
+
+    .. container:: m-col-m-6
+
+        .. plot:: Fastest animals
+            :type: barh
+            :labels:
+                Cheetah
+                Pronghorn
+            :units: km/h
+            :values: 109.4 88.5
+            :colors: warning primary
+            :errors: 14.32 5.5
+
+    .. container:: m-col-m-6
+
+        .. plot:: Fastest animals
+            :type: barh
+            :labels:
+                Cheetah
+                Pronghorn
+                Springbok
+                Wildebeest
+            :units: km/h
+            :values: 109.4 88.5 88 80.5
+            :colors: warning primary danger info
+
+Graphs
+======
+
+First is colored except the self-pointing "no", second is colored globally,
+third is colored globally with overrides except for for the self-pointing "no".
+
+.. container:: m-row
+
+    .. container:: m-col-m-4
+
+        .. digraph:: FSM
+
+            rankdir=LR
+            yes [shape=circle, class="m-default", style=filled]
+            no [shape=circle, class="m-default"]
+            yes -> no [label="no", class="m-default"]
+            no -> no [label="no"]
+
+    .. container:: m-col-m-4
+
+        .. digraph:: FSM
+            :class: m-default
+
+            rankdir=LR
+            yes [shape=circle, style=filled]
+            no [shape=circle]
+            yes -> no [label="no"]
+            no -> no [label="no"]
+
+    .. container:: m-col-m-4
+
+        .. digraph:: FSM
+            :class: m-danger
+
+            rankdir=LR
+            yes [shape=circle, class="m-default", style=filled]
+            no [shape=circle, class="m-default"]
+            yes -> no [label="no", class="m-default"]
+            no -> no [label="no"]
+
+    .. container:: m-col-m-4
+
+        .. digraph:: FSM
+
+            rankdir=LR
+            yes [shape=circle, class="m-primary", style=filled]
+            no [shape=circle, class="m-primary"]
+            yes -> no [label="no", class="m-primary"]
+            no -> no [label="no"]
+
+    .. container:: m-col-m-4
+
+        .. digraph:: FSM
+            :class: m-primary
+
+            rankdir=LR
+            yes [shape=circle, style=filled]
+            no [shape=circle]
+            yes -> no [label="no"]
+            no -> no [label="no"]
+
+    .. container:: m-col-m-4
+
+        .. digraph:: FSM
+            :class: m-danger
+
+            rankdir=LR
+            yes [shape=circle, class="m-primary", style=filled]
+            no [shape=circle, class="m-primary"]
+            yes -> no [label="no", class="m-primary"]
+            no -> no [label="no"]
+
+    .. container:: m-col-m-4
+
+        .. digraph:: FSM
+
+            rankdir=LR
+            yes [shape=circle, class="m-success", style=filled]
+            no [shape=circle, class="m-success"]
+            yes -> no [label="no", class="m-success"]
+            no -> no [label="no"]
+
+    .. container:: m-col-m-4
+
+        .. digraph:: FSM
+            :class: m-success
+
+            rankdir=LR
+            yes [shape=circle, style=filled]
+            no [shape=circle]
+            yes -> no [label="no"]
+            no -> no [label="no"]
+
+    .. container:: m-col-m-4
+
+        .. digraph:: FSM
+            :class: m-danger
+
+            rankdir=LR
+            yes [shape=circle, class="m-success", style=filled]
+            no [shape=circle, class="m-success"]
+            yes -> no [label="no", class="m-success"]
+            no -> no [label="no"]
+
+    .. container:: m-col-m-4
+
+        .. digraph:: FSM
+
+            rankdir=LR
+            yes [shape=circle, class="m-warning", style=filled]
+            no [shape=circle, class="m-warning"]
+            yes -> no [label="no", class="m-warning"]
+            no -> no [label="no"]
+
+    .. container:: m-col-m-4
+
+        .. digraph:: FSM
+            :class: m-warning
+
+            rankdir=LR
+            yes [shape=circle, style=filled]
+            no [shape=circle]
+            yes -> no [label="no"]
+            no -> no [label="no"]
+
+    .. container:: m-col-m-4
+
+        .. digraph:: FSM
+            :class: m-danger
+
+            rankdir=LR
+            yes [shape=circle, class="m-warning", style=filled]
+            no [shape=circle, class="m-warning"]
+            yes -> no [label="no", class="m-warning"]
+            no -> no [label="no"]
+
+    .. container:: m-col-m-4
+
+        .. digraph:: FSM
+
+            rankdir=LR
+            yes [shape=circle, class="m-danger", style=filled]
+            no [shape=circle, class="m-danger"]
+            yes -> no [label="no", class="m-danger"]
+            no -> no [label="no"]
+
+    .. container:: m-col-m-4
+
+        .. digraph:: FSM
+            :class: m-danger
+
+            rankdir=LR
+            yes [shape=circle, style=filled]
+            no [shape=circle]
+            yes -> no [label="no"]
+            no -> no [label="no"]
+
+    .. container:: m-col-m-4
+
+        .. digraph:: FSM
+            :class: m-success
+
+            rankdir=LR
+            yes [shape=circle, class="m-danger", style=filled]
+            no [shape=circle, class="m-danger"]
+            yes -> no [label="no", class="m-danger"]
+            no -> no [label="no"]
+
+    .. container:: m-col-m-4
+
+        .. digraph:: FSM
+
+            rankdir=LR
+            yes [shape=circle, class="m-info", style=filled]
+            no [shape=circle, class="m-info"]
+            yes -> no [label="no", class="m-info"]
+            no -> no [label="no"]
+
+    .. container:: m-col-m-4
+
+        .. digraph:: FSM
+            :class: m-info
+
+            rankdir=LR
+            yes [shape=circle, style=filled]
+            no [shape=circle]
+            yes -> no [label="no"]
+            no -> no [label="no"]
+
+    .. container:: m-col-m-4
+
+        .. digraph:: FSM
+            :class: m-danger
+
+            rankdir=LR
+            yes [shape=circle, class="m-info", style=filled]
+            no [shape=circle, class="m-info"]
+            yes -> no [label="no", class="m-info"]
+            no -> no [label="no"]
+
+    .. container:: m-col-m-4
+
+        .. digraph:: FSM
+
+            rankdir=LR
+            yes [shape=circle, class="m-dim", style=filled]
+            no [shape=circle, class="m-dim"]
+            yes -> no [label="no", class="m-dim"]
+            no -> no [label="no"]
+
+    .. container:: m-col-m-4
+
+        .. digraph:: FSM
+            :class: m-dim
+
+            rankdir=LR
+            yes [shape=circle, style=filled]
+            no [shape=circle]
+            yes -> no [label="no"]
+            no -> no [label="no"]
+
+    .. container:: m-col-m-4
+
+        .. digraph:: FSM
+            :class: m-danger
+
+            rankdir=LR
+            yes [shape=circle, class="m-dim", style=filled]
+            no [shape=circle, class="m-dim"]
+            yes -> no [label="no", class="m-dim"]
+            no -> no [label="no"]
similarity index 53%
rename from doc/plugins/plots.rst
rename to doc/plugins/plots-and-graphs.rst
index 8733ea65e2620845d492ff447f1db531550961d8..a05aec77a53b1c37df799e8944e821f78d9b31f4 100644 (file)
@@ -22,8 +22,8 @@
     DEALINGS IN THE SOFTWARE.
 ..
 
-Plots
-#####
+Plots and graphs
+################
 
 :breadcrumb: {filename}/plugins.rst Pelican plugins
 :footer:
@@ -32,15 +32,24 @@ Plots
 
         `« Math and code <{filename}/plugins/math-and-code.rst>`_ | `Pelican plugins <{filename}/plugins.rst>`_ | `Links and other » <{filename}/plugins/math-and-code.rst>`_
 
-Allows you to render plots directly from data specified inline in the page
-source. Similarly to `math rendering <{filename}/admire/math.rst>`_, the plots
-are rendered to a SVG that's embedded directly in the HTML markup.
+.. role:: dot(code)
+    :language: dot
+
+These plugin allow you to render plots and graphs directly from data specified
+inline in the page source. Similarly to `math rendering <{filename}/admire/math.rst>`_,
+the graphics is rendered to a SVG that's embedded directly in the HTML markup.
+
+.. note-danger:: Experimental features
+
+    Please note that these plugins are highly experimental and at the moment
+    created to fulfill a particular immediate need of the author. They might
+    not work reliably on general input.
 
 .. contents::
     :class: m-block m-default
 
-`How to use`_
-=============
+`Plots`_
+========
 
 Download the `m/plots.py <{filename}/plugins.rst>`_ file, put it including the
 ``m/`` directory into one of your :py:`PLUGIN_PATHS` and add ``m.plots``
@@ -66,11 +75,11 @@ or your distribution package manager:
 The plugin produces SVG plots that make use of the
 `CSS plot styling <{filename}/css/components.rst#plots>`_.
 
-`Bar graphs`_
-=============
+`Bar charts`_
+-------------
 
-Currently the only supported plot type is a horizontal bar graph, denoted by
-:rst:`:type: hbar`:
+Currently the only supported plot type is a horizontal bar chart, denoted by
+:rst:`.. plot::` directive with :rst:`:type: hbar`:
 
 .. code-figure::
 
@@ -105,7 +114,7 @@ It's also optionally possible to add error bars using :rst:`:error:` and
 configure bar colors using :rst:`:colors:`. The colors correspond to m.css
 `color classes <{filename}/css/components.rst#colors>`_ and you can either
 use one color for all or one for each value, separated by whitespace. It's
-possible to add an extra line of labels using :rst:`:labels_extra:`. Bar graph
+possible to add an extra line of labels using :rst:`:labels_extra:`. Bar chart
 height is calculated automatically based on amount of values, you can adjust
 the bar height using :rst:`:bar_height:`. Default value is :py:`0.4`.
 
@@ -148,3 +157,119 @@ the bar height using :rst:`:bar_height:`. Default value is :py:`0.4`.
         :errors: 0.74 3.65 9.45 25.66
         :colors: success info danger dim
         :bar_height: 0.6
+
+`Graphs`_
+=========
+
+Download the `m/dot.py <{filename}/plugins.rst>`_ file, put it including the
+``m/`` directory into one of your :py:`PLUGIN_PATHS` and add ``m.dot``
+package to your :py:`PLUGINS` in ``pelicanconf.py``.
+
+.. note-danger::
+
+    Note that this plugin, unlike most of the others, requires at least Python
+    3.5 to run properly.
+
+.. code:: python
+
+    PLUGINS += ['m.dot']
+    M_DOT_FONT = 'Source Sans Pro'
+
+Set :py:`M_DOT_FONT` to a font that matches your CSS theme (it's Source Sans
+Pro for `builtin m.css themes <{filename}/css/themes.rst>`_), note that you
+*need to have the font installed* on your system, otherwise it will fall back
+to whatever system font it finds instead (for example DejaVu Sans) and the
+output won't look as expected. In addition you need the
+`Graphviz <https://graphviz.org/>`_ library installed. Get it via your
+distribution package manager, for example on Ubuntu:
+
+.. code:: sh
+
+    sudo apt install graphviz
+
+The plugin produces SVG graphcs that make use of the
+`CSS graph styling <{filename}/css/components.rst#graphs>`_.
+
+`Directed graphs`_
+--------------------
+
+The :rst:`.. digraph::` directive uses the ``dot`` tool to produce directed
+graphs. The required directive argument is graph title, contents is whatever
+you would put inside the :dot:`digraph` block. Use the :rst:`:class:` to
+specify a `CSS color class <{filename}/css/components.rst#colors>`_ for the
+whole graph, it's also possible to color particular nodes and edges using the
+(currently undocumented) ``class`` attribute.
+
+.. code-figure::
+
+    .. code:: rst
+
+        .. digraph:: Finite state machine
+
+            rankdir=LR
+
+            S₁ [shape=circle, class="m-primary", peripheries=2]
+            S₂ [shape=circle]
+            _  [style=invis]
+
+            _  -> S₁ [class="m-warning"]
+            S₁ -> S₂ [label="0"]
+            S₂ -> S₁ [label="0"]
+            S₁ -> S₁ [label="1"]
+            S₂ -> S₂ [label="1"]
+
+    .. digraph:: Finite state machine
+
+        rankdir=LR
+
+        S₁ [shape=circle, class="m-primary", peripheries=2]
+        S₂ [shape=circle]
+        _  [style=invis]
+        b  [style=invis]
+
+        _  -> S₁ [class="m-warning"]
+        S₂ -> b  [style=invis]
+        S₁ -> S₂ [label="0"]
+        S₂ -> S₁ [label="0"]
+        S₁ -> S₁ [label="1"]
+        S₂ -> S₂ [label="1"]
+
+For more information check the official
+`GraphViz Reference <http://www.graphviz.org/doc/info/>`_, in particular the
+extensive `attribute documentation <http://www.graphviz.org/doc/info/attrs.html>`_.
+
+.. note-warning::
+
+    Note that currently all styling is discarded and only the
+    ``class`` and ``fontsize`` attributes are taken into account.
+
+`Undirected graphs`_
+--------------------
+
+The :rst:`.. graph::` and :rst:`.. strict-graph::` directives are similar to
+:rst:`.. digraph::`, but allow undirected graphs only. Again these are
+equivalent to :dot:`graph` and :dot:`strict graph` in the DOT language:
+
+.. code-figure::
+
+    .. code:: rst
+
+        .. graph:: A house
+            :class: m-success
+
+            { rank=same 0 1 }
+            { rank=same 2 4 }
+
+            0 -- 1 -- 2 -- 3 -- 4 -- 0 -- 2 -- 4 --1
+            3 [style=solid]
+
+    .. graph:: A house
+        :class: m-success
+
+        rankdir=BT
+
+        { rank=same 0 1 }
+        { rank=same 2 4 }
+
+        0 -- 1 -- 2 -- 3 -- 4 -- 0 -- 2 -- 4 --1
+        3 [style=filled]
diff --git a/doc/plugins/plots-test.rst b/doc/plugins/plots-test.rst
deleted file mode 100644 (file)
index a99935e..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-..
-    This file is part of m.css.
-
-    Copyright © 2017, 2018 Vladimír Vondruš <mosra@centrum.cz>
-
-    Permission is hereby granted, free of charge, to any person obtaining a
-    copy of this software and associated documentation files (the "Software"),
-    to deal in the Software without restriction, including without limitation
-    the rights to use, copy, modify, merge, publish, distribute, sublicense,
-    and/or sell copies of the Software, and to permit persons to whom the
-    Software is furnished to do so, subject to the following conditions:
-
-    The above copyright notice and this permission notice shall be included
-    in all copies or substantial portions of the Software.
-
-    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-    DEALINGS IN THE SOFTWARE.
-..
-
-Test
-####
-
-:save_as: plugins/plots/test/index.html
-:breadcrumb: {filename}/plugins.rst Pelican plugins
-             {filename}/plugins/plots.rst Plots
-
-.. container:: m-row
-
-    .. container:: m-col-m-6
-
-        .. plot:: Fastest animals
-            :type: barh
-            :labels:
-                Cheetah
-                Pronghorn
-            :units: km/h
-            :values: 109.4 88.5
-            :colors: warning primary
-            :errors: 14.32 5.5
-
-    .. container:: m-col-m-6
-
-        .. plot:: Fastest animals
-            :type: barh
-            :labels:
-                Cheetah
-                Pronghorn
-                Springbok
-                Wildebeest
-            :units: km/h
-            :values: 109.4 88.5 88 80.5
-            :colors: warning primary danger info
index 7a73243cca2c918a0fb9bde69acb1db7abcaa92b..9ae50ced08c6f54c279f12933113d9dbbfbc8cd6 100644 (file)
@@ -12,6 +12,10 @@ matrix:
       - JOBID=py34
     - language: python
       python: 3.5
+      addons:
+        apt:
+          packages:
+          - graphviz
       env:
       - WITH_THEME=ON
       - WITH_DOXYGEN=OFF
@@ -19,6 +23,10 @@ matrix:
       - JOBID=py35
     - language: python
       python: 3.6
+      addons:
+        apt:
+          packages:
+          - graphviz
       env:
       - WITH_THEME=ON
       - WITH_DOXYGEN=ON
diff --git a/pelican-plugins/m/dot.py b/pelican-plugins/m/dot.py
new file mode 100644 (file)
index 0000000..62dff88
--- /dev/null
@@ -0,0 +1,162 @@
+#
+#   This file is part of m.css.
+#
+#   Copyright © 2017, 2018 Vladimír Vondruš <mosra@centrum.cz>
+#
+#   Permission is hereby granted, free of charge, to any person obtaining a
+#   copy of this software and associated documentation files (the "Software"),
+#   to deal in the Software without restriction, including without limitation
+#   the rights to use, copy, modify, merge, publish, distribute, sublicense,
+#   and/or sell copies of the Software, and to permit persons to whom the
+#   Software is furnished to do so, subject to the following conditions:
+#
+#   The above copyright notice and this permission notice shall be included
+#   in all copies or substantial portions of the Software.
+#
+#   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+#   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+#   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+#   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+#   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+#   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+#   DEALINGS IN THE SOFTWARE.
+#
+
+import pelican
+import re
+import subprocess
+
+from docutils import nodes
+from docutils.parsers import rst
+from docutils.parsers.rst import directives
+from docutils.parsers.rst.roles import set_classes
+
+_patch_src = re.compile(r"""<\?xml version="1\.0" encoding="UTF-8" standalone="no"\?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1\.1//EN"
+ "http://www\.w3\.org/Graphics/SVG/1\.1/DTD/svg11\.dtd">
+<svg width="(?P<width>\d+)pt" height="(?P<height>\d+)pt"
+ viewBox="(?P<viewBox>[^"]+)" xmlns="http://www\.w3\.org/2000/svg" xmlns:xlink="http://www\.w3\.org/1999/xlink">
+<g id="graph0" class="graph" """)
+
+_patch_dst = r"""<svg style="width: {width:.3f}rem; height: {height:.3f}rem;" viewBox="{viewBox}">
+<g """
+
+_comment_src = re.compile(r"""<!--[^-]+-->\n""")
+
+_class_src = re.compile(r"""<g id="(edge|node)\d+" class="(?P<type>edge|node)(?P<classes>[^"]*)">
+<title>(?P<title>[^<]*)</title>
+<(?P<element>ellipse|polygon|path) fill="(?P<fill>[^"]+)" stroke="[^"]+" """)
+
+_class_dst = r"""<g class="{classes}">
+<title>{title}</title>
+<{element} """
+
+_attributes_src = re.compile(r"""<(?P<element>ellipse|polygon) fill="[^"]+" stroke="[^"]+" """)
+
+_attributes_dst = r"""<\g<element> """
+
+# re.compile() is called after replacing {font} in configure()
+_text_src_src = ' font-family="{font}" font-size="(?P<size>[^"]+)" fill="[^"]+"'
+
+_text_dst = ' style="font-size: {size}px;"'
+
+_font = ''
+_font_size = 16.0 # TODO: avoid hardcoding this
+
+# The pt are actually px (16pt font is the same size as 16px), so just
+# converting to rem here
+_pt2em = 1.0/_font_size
+
+class Dot(rst.Directive):
+    has_content = True
+    required_arguments = 1
+    final_argument_whitespace = True
+    option_spec = {'class': directives.class_option,
+                   'name': directives.unchanged}
+
+    def run(self, source):
+        set_classes(self.options)
+
+        title_text = self.arguments[0]
+
+        try:
+            ret = subprocess.run(['dot', '-Tsvg',
+                '-Gfontname={}'.format(_font),
+                '-Nfontname={}'.format(_font),
+                '-Efontname={}'.format(_font),
+                '-Gfontsize={}'.format(_font_size),
+                '-Nfontsize={}'.format(_font_size),
+                '-Efontsize={}'.format(_font_size),
+                '-Gbgcolor=transparent',
+                ], input=source.encode('utf-8'), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+            if ret.returncode: print(ret.stderr.decode('utf-8'))
+            ret.check_returncode()
+        except FileNotFoundError: # pragma: no cover
+            raise RuntimeError("dot not found")
+
+        # First Remove comments
+        svg = _comment_src.sub('', ret.stdout.decode('utf-8'))
+
+        # Remove preamble and fixed size
+        def patch_repl(match): return _patch_dst.format(
+            width=_pt2em*float(match.group('width')),
+            height=_pt2em*float(match.group('height')),
+            viewBox=match.group('viewBox'))
+        svg = _patch_src.sub(patch_repl, svg)
+
+        # Remove unnecessary IDs and attributes, replace classes for elements
+        def element_repl(match):
+            classes = ['m-' + match.group('type')] + match.group('classes').replace('&#45;', '-').split()
+            # distinguish between solid and filled nodes
+            if match.group('type') == 'node' and match.group('fill') == 'none':
+                classes += ['m-flat']
+
+            return _class_dst.format(
+                classes=' '.join(classes),
+                title=match.group('title'),
+                element=match.group('element'))
+        svg = _class_src.sub(element_repl, svg)
+
+        # Remove unnecessary fill and stroke attributes
+        svg = _attributes_src.sub(_attributes_dst, svg)
+
+        # Remove unnecessary text attributes. Keep font size only if nondefault
+        def text_repl(match):
+            if float(match.group('size')) != _font_size:
+                return _text_dst.format(size=float(match.group('size')))
+            return ''
+        svg = _text_src.sub(text_repl, svg)
+
+        container = nodes.container(**self.options)
+        container['classes'] = ['m-graph'] + container['classes']
+        node = nodes.raw('', svg, format='html')
+        container.append(node)
+        return [container]
+
+class Digraph(Dot):
+    def run(self):
+        return Dot.run(self, 'digraph "{}" {{\n{}}}'.format(self.arguments[0], '\n'.join(self.content)))
+
+class StrictDigraph(Dot):
+    def run(self):
+        return Dot.run(self, 'strict digraph "{}" {{\n{}}}'.format(self.arguments[0], '\n'.join(self.content)))
+
+class Graph(Dot):
+    def run(self):
+        return Dot.run(self, 'graph "{}" {{\n{}}}'.format(self.arguments[0], '\n'.join(self.content)))
+
+class StrictGraph(Dot):
+    def run(self):
+        return Dot.run(self, 'strict graph "{}" {{\n{}}}'.format(self.arguments[0], '\n'.join(self.content)))
+
+def configure(pelicanobj):
+    global _font, _text_src
+    _font = pelicanobj.settings.get('M_DOT_FONT', 'Source Sans Pro')
+    _text_src = re.compile(_text_src_src.format(font=_font))
+
+def register():
+    pelican.signals.initialized.connect(configure)
+    rst.directives.register_directive('digraph', Digraph)
+    rst.directives.register_directive('strict-digraph', StrictDigraph)
+    rst.directives.register_directive('graph', Graph)
+    rst.directives.register_directive('strict-graph', StrictGraph)
diff --git a/pelican-plugins/m/test/dot/page.html b/pelican-plugins/m/test/dot/page.html
new file mode 100644 (file)
index 0000000..41b0f52
--- /dev/null
@@ -0,0 +1,177 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8" />
+  <title>m.dot | A Pelican Blog</title>
+  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i" />
+  <link rel="stylesheet" href="static/m-dark.css" />
+  <link rel="canonical" href="page.html" />
+  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+</head>
+<body>
+<header><nav id="navigation">
+  <div class="m-container">
+    <div class="m-row">
+      <a href="./" id="m-navbar-brand" class="m-col-t-9 m-col-m-none m-left-m">A Pelican Blog</a>
+    </div>
+  </div>
+</nav></header>
+<main>
+<article>
+  <div class="m-container m-container-inflatable">
+    <div class="m-row">
+      <div class="m-col-l-10 m-push-l-1">
+        <h1>m.dot</h1>
+<!-- content -->
+<p>Note: the test uses DejaVu Sans instead of Source Sans Pro in order to have
+predictable rendering on the CIs.</p>
+<p>Different shapes, fills etc. All default colors, filled only the first node
+and the arrowheads, nothing else. Non-default font size should be preserved.</p>
+<div class="m-graph">
+<svg style="width: 16.250rem; height: 5.312rem;" viewBox="0.00 0.00 259.77 84.77">
+<g transform="scale(1 1) rotate(0) translate(4 80.7696)">
+<title>Basics</title>
+<g class="m-node">
+<title>a</title>
+<polygon points="54,-40.3848 0,-40.3848 0,-4.3848 54,-4.3848 54,-40.3848"/>
+<text text-anchor="middle" x="27" y="-18.5848">a</text>
+</g>
+<g class="m-node m-flat">
+<title>b</title>
+<ellipse cx="113.3848" cy="-22.3848" rx="18.2906" ry="18.2906"/>
+<ellipse cx="113.3848" cy="-22.3848" rx="22.2701" ry="22.2701"/>
+<text text-anchor="middle" x="113.3848" y="-18.5848">b</text>
+</g>
+<g class="m-edge">
+<title>a&#45;&gt;b</title>
+<path d="M54.3327,-22.3848C62.6964,-22.3848 71.9814,-22.3848 80.6653,-22.3848"/>
+<polygon points="80.8574,-25.8849 90.8574,-22.3848 80.8574,-18.8849 80.8574,-25.8849"/>
+</g>
+<g class="m-node m-flat">
+<title>c</title>
+<ellipse cx="224.7696" cy="-22.3848" rx="27" ry="18.2703"/>
+<text text-anchor="middle" x="224.7696" y="-18.5848">c</text>
+</g>
+<g class="m-edge">
+<title>b&#45;&gt;c</title>
+<path d="M135.9251,-22.3848C150.665,-22.3848 170.2762,-22.3848 187.3232,-22.3848"/>
+<polygon points="187.5396,-25.8849 197.5396,-22.3848 187.5396,-18.8849 187.5396,-25.8849"/>
+<text text-anchor="middle" x="166.7696" y="-34.3848" style="font-size: 40.0px;">0</text>
+</g>
+<g class="m-edge">
+<title>c&#45;&gt;c</title>
+<path d="M214.4919,-39.6042C212.3945,-49.5298 215.8203,-58.7696 224.7696,-58.7696 230.5026,-58.7696 233.969,-54.9775 235.1685,-49.6425"/>
+<polygon points="238.6679,-49.5611 235.0472,-39.6042 231.6684,-49.6458 238.6679,-49.5611"/>
+<text text-anchor="middle" x="224.7696" y="-63.9696">1</text>
+</g>
+</g>
+</svg>
+</div>
+<p>Colors:</p>
+<div class="m-graph">
+<svg style="width: 5.688rem; height: 8.500rem;" viewBox="0.00 0.00 91.38 135.54">
+<g transform="scale(1 1) rotate(0) translate(4 131.5391)">
+<title>Colors</title>
+<g class="m-node m-success m-flat">
+<title>a</title>
+<ellipse cx="27" cy="-109.1543" rx="27" ry="18.2703"/>
+<text text-anchor="middle" x="27" y="-105.3543">a</text>
+</g>
+<g class="m-node m-dim">
+<title>b</title>
+<ellipse cx="27" cy="-18.3848" rx="18.2703" ry="18.2703"/>
+<text text-anchor="middle" x="27" y="-14.5848">b</text>
+</g>
+<g class="m-edge m-warning">
+<title>a&#45;&gt;b</title>
+<path d="M27,-90.3468C27,-77.8501 27,-61.2025 27,-47.0671"/>
+<polygon points="30.5001,-46.8576 27,-36.8576 23.5001,-46.8577 30.5001,-46.8576"/>
+<text text-anchor="middle" x="41" y="-59.9696">yes</text>
+</g>
+<g class="m-edge m-primary">
+<title>b&#45;&gt;b</title>
+<path d="M43.8422,-26.1192C53.9096,-27.8379 63.3848,-25.2598 63.3848,-18.3848 63.3848,-13.9805 59.4961,-11.3396 54.0544,-10.4622"/>
+<polygon points="53.776,-6.9666 43.8422,-10.6504 53.905,-13.9655 53.776,-6.9666"/>
+<text text-anchor="middle" x="73.3848" y="-14.5848">no</text>
+</g>
+</g>
+</svg>
+</div>
+<p>Unoriented graph:</p>
+<div class="m-graph m-success">
+<svg style="width: 3.875rem; height: 7.375rem;" viewBox="0.00 0.00 62.00 117.54">
+<g transform="scale(1 1) rotate(0) translate(4 113.5391)">
+<title>A to B</title>
+<g class="m-node m-flat">
+<title>a</title>
+<ellipse cx="27" cy="-91.1543" rx="27" ry="18.2703"/>
+<text text-anchor="middle" x="27" y="-87.3543">a</text>
+</g>
+<g class="m-node m-flat">
+<title>b</title>
+<ellipse cx="27" cy="-18.3848" rx="27" ry="18.2703"/>
+<text text-anchor="middle" x="27" y="-14.5848">b</text>
+</g>
+<g class="m-edge">
+<title>a&#45;&#45;b</title>
+<path d="M21.0843,-73.1663C19.9734,-61.9709 19.9719,-47.622 21.0798,-36.418"/>
+</g>
+<g class="m-edge">
+<title>a&#45;&#45;b</title>
+<path d="M32.9157,-73.1663C34.0266,-61.9709 34.0281,-47.622 32.9202,-36.418"/>
+</g>
+</g>
+</svg>
+</div>
+<p>Strict graphs:</p>
+<div class="m-graph">
+<svg style="width: 3.875rem; height: 7.375rem;" viewBox="0.00 0.00 62.00 117.54">
+<g transform="scale(1 1) rotate(0) translate(4 113.5391)">
+<title>A to B</title>
+<g class="m-node m-flat">
+<title>a</title>
+<ellipse cx="27" cy="-91.1543" rx="27" ry="18.2703"/>
+<text text-anchor="middle" x="27" y="-87.3543">a</text>
+</g>
+<g class="m-node m-flat">
+<title>b</title>
+<ellipse cx="27" cy="-18.3848" rx="27" ry="18.2703"/>
+<text text-anchor="middle" x="27" y="-14.5848">b</text>
+</g>
+<g class="m-edge">
+<title>a&#45;&gt;b</title>
+<path d="M27,-72.4144C27,-64.6303 27,-55.4246 27,-46.8383"/>
+<polygon points="30.5001,-46.8093 27,-36.8093 23.5001,-46.8094 30.5001,-46.8093"/>
+</g>
+</g>
+</svg>
+</div>
+<div class="m-graph">
+<svg style="width: 3.875rem; height: 7.375rem;" viewBox="0.00 0.00 62.00 117.54">
+<g transform="scale(1 1) rotate(0) translate(4 113.5391)">
+<title>A to B</title>
+<g class="m-node m-flat">
+<title>a</title>
+<ellipse cx="27" cy="-91.1543" rx="27" ry="18.2703"/>
+<text text-anchor="middle" x="27" y="-87.3543">a</text>
+</g>
+<g class="m-node m-flat">
+<title>b</title>
+<ellipse cx="27" cy="-18.3848" rx="27" ry="18.2703"/>
+<text text-anchor="middle" x="27" y="-14.5848">b</text>
+</g>
+<g class="m-edge">
+<title>a&#45;&#45;b</title>
+<path d="M27,-72.4144C27,-61.4654 27,-47.7036 27,-36.8093"/>
+</g>
+</g>
+</svg>
+</div>
+<!-- /content -->
+      </div>
+    </div>
+  </div>
+</article>
+</main>
+</body>
+</html>
diff --git a/pelican-plugins/m/test/dot/page.rst b/pelican-plugins/m/test/dot/page.rst
new file mode 100644 (file)
index 0000000..2961be1
--- /dev/null
@@ -0,0 +1,48 @@
+m.dot
+#####
+
+Note: the test uses DejaVu Sans instead of Source Sans Pro in order to have
+predictable rendering on the CIs.
+
+Different shapes, fills etc. All default colors, filled only the first node
+and the arrowheads, nothing else. Non-default font size should be preserved.
+
+.. digraph:: Basics
+
+    rankdir=LR
+
+    a [style=filled shape=rect]
+    b [peripheries=2 shape=circle]
+    c [shape=ellipse]
+    a -> b
+    b -> c [label="0" fontsize=40]
+    c -> c [label="1"]
+
+Colors:
+
+.. digraph:: Colors
+
+    a [class="m-success"]
+    b [style=filled shape=circle class="m-dim"]
+    a -> b [class="m-warning" label="yes"]
+    b -> b [class="m-primary" label="no"]
+
+Unoriented graph:
+
+.. graph:: A to B
+    :class: m-success
+
+    a -- b
+    a -- b
+
+Strict graphs:
+
+.. strict-digraph:: A to B
+
+    a -> b
+    a -> b
+
+.. strict-graph:: A to B
+
+    a -- b
+    a -- b
diff --git a/pelican-plugins/m/test/test_dot.py b/pelican-plugins/m/test/test_dot.py
new file mode 100644 (file)
index 0000000..5938a1a
--- /dev/null
@@ -0,0 +1,44 @@
+#
+#   This file is part of m.css.
+#
+#   Copyright © 2017, 2018 Vladimír Vondruš <mosra@centrum.cz>
+#
+#   Permission is hereby granted, free of charge, to any person obtaining a
+#   copy of this software and associated documentation files (the "Software"),
+#   to deal in the Software without restriction, including without limitation
+#   the rights to use, copy, modify, merge, publish, distribute, sublicense,
+#   and/or sell copies of the Software, and to permit persons to whom the
+#   Software is furnished to do so, subject to the following conditions:
+#
+#   The above copyright notice and this permission notice shall be included
+#   in all copies or substantial portions of the Software.
+#
+#   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+#   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+#   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+#   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+#   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+#   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+#   DEALINGS IN THE SOFTWARE.
+#
+
+import sys
+import unittest
+
+from distutils.version import LooseVersion
+
+from m.test import PluginTestCase
+
+class Dot(PluginTestCase):
+    def __init__(self, *args, **kwargs):
+        super().__init__(__file__, '', *args, **kwargs)
+
+    @unittest.skipUnless(LooseVersion(sys.version) >= LooseVersion("3.5"),
+                         "The math plugin requires at least Python 3.5 installed")
+    def test(self):
+        self.run_pelican({
+            'PLUGINS': ['m.htmlsanity', 'm.dot'],
+            'M_DOT_FONT': 'DejaVu Sans'
+        })
+
+        self.assertEqual(*self.actual_expected_contents('page.html'))
index 5493bdc7cac4e419e0a5ca5366f652838f784175..de0ebdbc948c520b4be61013c4968da6657217ad 100644 (file)
@@ -88,7 +88,7 @@ M_LINKS_NAVBAR2 = [('Pelican plugins', 'plugins/', 'plugins', [
                         ('Images', 'plugins/images/', 'plugins/images'),
                         ('Math and code', 'plugins/math-and-code/', 'plugins/math-and-code'),
                         ('Links and other', 'plugins/links/', 'plugins/links'),
-                        ('Plots', 'plugins/plots/', 'plugins/plots'),
+                        ('Plots and graphs', 'plugins/plots-and-graphs/', 'plugins/plots-and-graphs'),
                         ('Metadata', 'plugins/metadata/', 'plugins/metadata')]),
                    ('Doxygen theme', 'doxygen/', 'doxygen', []),
                    ('GitHub', 'https://github.com/mosra/m.css', '', [])]
@@ -119,7 +119,7 @@ M_LINKS_FOOTER4 = [('Pelican plugins', 'plugins/'),
                    ('Components', 'plugins/components/'),
                    ('Images', 'plugins/images/'),
                    ('Math and code', 'plugins/math-and-code/'),
-                   ('Plots', 'plugins/plots/'),
+                   ('Plots and graphs', 'plugins/plots-and-graphs/'),
                    ('Links and other', 'plugins/links/'),
                    ('Metadata', 'plugins/metadata/')]
 
@@ -141,6 +141,7 @@ PLUGINS = ['m.abbr',
            'm.code',
            'm.components',
            'm.dox',
+           'm.dot',
            'm.filesize',
            'm.gl',
            'm.gh',