From e9ab28bbda73529292fdc4e38a3fbc102d317938 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 15 May 2018 23:52:58 +0200 Subject: [PATCH] plugins: new m.plots plugin for rendering inline SVG plots. --- CONTRIBUTING.rst | 4 +- css/m-components.css | 51 +++- css/m-dark+doxygen.compiled.css | 46 +++- css/m-dark.compiled.css | 46 +++- css/m-dark.css | 4 + css/m-light+doxygen.compiled.css | 46 +++- css/m-light.compiled.css | 46 +++- css/m-light.css | 4 + doc/css/components-plot.svg | 40 +++ doc/css/components.rst | 41 +++ doc/plugins.rst | 8 + doc/plugins/links.rst | 2 +- doc/plugins/math-and-code.rst | 2 +- doc/plugins/plots-test.rst | 57 ++++ doc/plugins/plots.rst | 144 ++++++++++ pelican-plugins/m/plots.py | 244 +++++++++++++++++ pelican-plugins/m/test/plots/page.html | 349 +++++++++++++++++++++++++ pelican-plugins/m/test/plots/page.rst | 27 ++ pelican-plugins/m/test/test_plots.py | 36 +++ site/pelicanconf.py | 5 +- 20 files changed, 1161 insertions(+), 41 deletions(-) create mode 100644 doc/css/components-plot.svg create mode 100644 doc/plugins/plots-test.rst create mode 100644 doc/plugins/plots.rst create mode 100644 pelican-plugins/m/plots.py create mode 100644 pelican-plugins/m/test/plots/page.html create mode 100644 pelican-plugins/m/test/plots/page.rst create mode 100644 pelican-plugins/m/test/test_plots.py diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 01dc38b3..5751a2d3 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -53,14 +53,14 @@ On ArchLinux: .. code:: sh - sudo pacman -S texlive-most pelican python-pillow + sudo pacman -S texlive-most pelican python-pillow python-matplotlib cower -d python-pyphen # Build the python-pyphen package from AUR On Ubuntu you need these: .. code:: sh - sudo apt-get install texlive-base texlive-latex-extra texlive-fonts-extra + sudo apt-get install texlive-base texlive-latex-extra texlive-fonts-extra python3-matplotlib pip3 install pelican Pyphen Pillow Once you have all the dependencies, simply go to the ``site/`` subdirectory and diff --git a/css/m-components.css b/css/m-components.css index 928e159b..11316542 100644 --- a/css/m-components.css +++ b/css/m-components.css @@ -1434,15 +1434,50 @@ div.m-math { text-align: center; } -/* Colored math block, inline math */ +/* Plots */ +div.m-plot svg { + text-align: center; +} +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; } +div.m-plot svg .m-label, div.m-plot svg .m-title { fill: var(--color); } +div.m-plot svg .m-line { + stroke: var(--color); + stroke-width: 0.8; +} +div.m-plot svg .m-error { + stroke: var(--plot-error-color); + stroke-width: 1.5; +} +div.m-plot svg .m-label.m-dim { fill: var(--dim-color); } + +/* Colored math block, inline math, plots */ div.m-math svg, svg.m-math { fill: var(--color); } -div.m-math.m-default svg, svg.m-math.m-default { fill: var(--default-color); } -div.m-math.m-primary svg, svg.m-math.m-primary { fill: var(--primary-color); } -div.m-math.m-success svg, svg.m-math.m-success { fill: var(--success-color); } -div.m-math.m-warning svg, svg.m-math.m-warning { fill: var(--warning-color); } -div.m-math.m-danger svg, svg.m-math.m-danger { fill: var(--danger-color); } -div.m-math.m-info svg, svg.m-math.m-info { fill: var(--info-color); } -div.m-math.m-dim svg, svg.m-math.m-dim { fill: var(--dim-color); } +div.m-math.m-default svg, svg.m-math.m-default, div.m-plot svg .m-bar.m-default { + fill: var(--default-color); +} +div.m-math.m-primary svg, svg.m-math.m-primary, div.m-plot svg .m-bar.m-primary { + fill: var(--primary-color); +} +div.m-math.m-success svg, svg.m-math.m-success, div.m-plot svg .m-bar.m-success { + fill: var(--success-color); +} +div.m-math.m-warning svg, svg.m-math.m-warning, div.m-plot svg .m-bar.m-warning { + fill: var(--warning-color); +} +div.m-math.m-danger svg, svg.m-math.m-danger, div.m-plot svg .m-bar.m-danger { + fill: var(--danger-color); +} +div.m-math.m-info svg, svg.m-math.m-info, div.m-plot svg .m-bar.m-info { + fill: var(--info-color); +} +div.m-math.m-dim svg, svg.m-math.m-dim, div.m-plot svg .m-bar.m-dim { + fill: var(--dim-color); +} /* Spacing after every block element, but not after the last */ p, ul, ol, dl, blockquote, pre, figure.m-code-figure, figure.m-console-figure, diff --git a/css/m-dark+doxygen.compiled.css b/css/m-dark+doxygen.compiled.css index 9d8436ed..c99320ab 100644 --- a/css/m-dark+doxygen.compiled.css +++ b/css/m-dark+doxygen.compiled.css @@ -1709,14 +1709,46 @@ div.m-math { overflow-y: hidden; text-align: center; } +div.m-plot svg { + text-align: center; +} +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; } +div.m-plot svg .m-line { + stroke: #dcdcdc; + stroke-width: 0.8; +} +div.m-plot svg .m-error { + stroke: #ffffff; + stroke-width: 1.5; +} +div.m-plot svg .m-label.m-dim { fill: #747474; } div.m-math svg, svg.m-math { fill: #dcdcdc; } -div.m-math.m-default svg, svg.m-math.m-default { fill: #dcdcdc; } -div.m-math.m-primary svg, svg.m-math.m-primary { fill: #a5c9ea; } -div.m-math.m-success svg, svg.m-math.m-success { fill: #3bd267; } -div.m-math.m-warning svg, svg.m-math.m-warning { fill: #c7cf2f; } -div.m-math.m-danger svg, svg.m-math.m-danger { fill: #cd3431; } -div.m-math.m-info svg, svg.m-math.m-info { fill: #2f83cc; } -div.m-math.m-dim svg, svg.m-math.m-dim { fill: #747474; } +div.m-math.m-default svg, svg.m-math.m-default, div.m-plot svg .m-bar.m-default { + fill: #dcdcdc; +} +div.m-math.m-primary svg, svg.m-math.m-primary, div.m-plot svg .m-bar.m-primary { + fill: #a5c9ea; +} +div.m-math.m-success svg, svg.m-math.m-success, div.m-plot svg .m-bar.m-success { + fill: #3bd267; +} +div.m-math.m-warning svg, svg.m-math.m-warning, div.m-plot svg .m-bar.m-warning { + fill: #c7cf2f; +} +div.m-math.m-danger svg, svg.m-math.m-danger, div.m-plot svg .m-bar.m-danger { + fill: #cd3431; +} +div.m-math.m-info svg, svg.m-math.m-info, div.m-plot svg .m-bar.m-info { + fill: #2f83cc; +} +div.m-math.m-dim svg, svg.m-math.m-dim, div.m-plot svg .m-bar.m-dim { + fill: #747474; +} p, ul, ol, dl, blockquote, pre, figure.m-code-figure, figure.m-console-figure, hr, article, article > header, article section, .m-note, .m-frame, .m-block, div.m-button, diff --git a/css/m-dark.compiled.css b/css/m-dark.compiled.css index 8dd12f7e..bece9102 100644 --- a/css/m-dark.compiled.css +++ b/css/m-dark.compiled.css @@ -1709,14 +1709,46 @@ div.m-math { overflow-y: hidden; text-align: center; } +div.m-plot svg { + text-align: center; +} +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; } +div.m-plot svg .m-line { + stroke: #dcdcdc; + stroke-width: 0.8; +} +div.m-plot svg .m-error { + stroke: #ffffff; + stroke-width: 1.5; +} +div.m-plot svg .m-label.m-dim { fill: #747474; } div.m-math svg, svg.m-math { fill: #dcdcdc; } -div.m-math.m-default svg, svg.m-math.m-default { fill: #dcdcdc; } -div.m-math.m-primary svg, svg.m-math.m-primary { fill: #a5c9ea; } -div.m-math.m-success svg, svg.m-math.m-success { fill: #3bd267; } -div.m-math.m-warning svg, svg.m-math.m-warning { fill: #c7cf2f; } -div.m-math.m-danger svg, svg.m-math.m-danger { fill: #cd3431; } -div.m-math.m-info svg, svg.m-math.m-info { fill: #2f83cc; } -div.m-math.m-dim svg, svg.m-math.m-dim { fill: #747474; } +div.m-math.m-default svg, svg.m-math.m-default, div.m-plot svg .m-bar.m-default { + fill: #dcdcdc; +} +div.m-math.m-primary svg, svg.m-math.m-primary, div.m-plot svg .m-bar.m-primary { + fill: #a5c9ea; +} +div.m-math.m-success svg, svg.m-math.m-success, div.m-plot svg .m-bar.m-success { + fill: #3bd267; +} +div.m-math.m-warning svg, svg.m-math.m-warning, div.m-plot svg .m-bar.m-warning { + fill: #c7cf2f; +} +div.m-math.m-danger svg, svg.m-math.m-danger, div.m-plot svg .m-bar.m-danger { + fill: #cd3431; +} +div.m-math.m-info svg, svg.m-math.m-info, div.m-plot svg .m-bar.m-info { + fill: #2f83cc; +} +div.m-math.m-dim svg, svg.m-math.m-dim, div.m-plot svg .m-bar.m-dim { + fill: #747474; +} p, ul, ol, dl, blockquote, pre, figure.m-code-figure, figure.m-console-figure, hr, article, article > header, article section, .m-note, .m-frame, .m-block, div.m-button, diff --git a/css/m-dark.css b/css/m-dark.css index 6ca682f9..5f9bacea 100644 --- a/css/m-dark.css +++ b/css/m-dark.css @@ -96,6 +96,10 @@ --navpanel-link-color: #ffffff; --navpanel-link-active-color: #a5c9ea; + /* Plots */ + --plot-background-color: #34424d; + --plot-error-color: #ffffff; + /* Colored components */ --default-color: #dcdcdc; --default-filled-color: #dcdcdc; diff --git a/css/m-light+doxygen.compiled.css b/css/m-light+doxygen.compiled.css index 36626c43..fa022b3f 100644 --- a/css/m-light+doxygen.compiled.css +++ b/css/m-light+doxygen.compiled.css @@ -1709,14 +1709,46 @@ div.m-math { overflow-y: hidden; text-align: center; } +div.m-plot svg { + text-align: center; +} +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; } +div.m-plot svg .m-line { + stroke: #000000; + stroke-width: 0.8; +} +div.m-plot svg .m-error { + stroke: #000000; + stroke-width: 1.5; +} +div.m-plot svg .m-label.m-dim { fill: #bdbdbd; } div.m-math svg, svg.m-math { fill: #000000; } -div.m-math.m-default svg, svg.m-math.m-default { fill: #000000; } -div.m-math.m-primary svg, svg.m-math.m-primary { fill: #cb4b16; } -div.m-math.m-success svg, svg.m-math.m-success { fill: #31c25d; } -div.m-math.m-warning svg, svg.m-math.m-warning { fill: #c7cf2f; } -div.m-math.m-danger svg, svg.m-math.m-danger { fill: #f60000; } -div.m-math.m-info svg, svg.m-math.m-info { fill: #2e7dc5; } -div.m-math.m-dim svg, svg.m-math.m-dim { fill: #bdbdbd; } +div.m-math.m-default svg, svg.m-math.m-default, div.m-plot svg .m-bar.m-default { + fill: #000000; +} +div.m-math.m-primary svg, svg.m-math.m-primary, div.m-plot svg .m-bar.m-primary { + fill: #cb4b16; +} +div.m-math.m-success svg, svg.m-math.m-success, div.m-plot svg .m-bar.m-success { + fill: #31c25d; +} +div.m-math.m-warning svg, svg.m-math.m-warning, div.m-plot svg .m-bar.m-warning { + fill: #c7cf2f; +} +div.m-math.m-danger svg, svg.m-math.m-danger, div.m-plot svg .m-bar.m-danger { + fill: #f60000; +} +div.m-math.m-info svg, svg.m-math.m-info, div.m-plot svg .m-bar.m-info { + fill: #2e7dc5; +} +div.m-math.m-dim svg, svg.m-math.m-dim, div.m-plot svg .m-bar.m-dim { + fill: #bdbdbd; +} p, ul, ol, dl, blockquote, pre, figure.m-code-figure, figure.m-console-figure, hr, article, article > header, article section, .m-note, .m-frame, .m-block, div.m-button, diff --git a/css/m-light.compiled.css b/css/m-light.compiled.css index 5c576956..9ed3bd3c 100644 --- a/css/m-light.compiled.css +++ b/css/m-light.compiled.css @@ -1709,14 +1709,46 @@ div.m-math { overflow-y: hidden; text-align: center; } +div.m-plot svg { + text-align: center; +} +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; } +div.m-plot svg .m-line { + stroke: #000000; + stroke-width: 0.8; +} +div.m-plot svg .m-error { + stroke: #000000; + stroke-width: 1.5; +} +div.m-plot svg .m-label.m-dim { fill: #bdbdbd; } div.m-math svg, svg.m-math { fill: #000000; } -div.m-math.m-default svg, svg.m-math.m-default { fill: #000000; } -div.m-math.m-primary svg, svg.m-math.m-primary { fill: #cb4b16; } -div.m-math.m-success svg, svg.m-math.m-success { fill: #31c25d; } -div.m-math.m-warning svg, svg.m-math.m-warning { fill: #c7cf2f; } -div.m-math.m-danger svg, svg.m-math.m-danger { fill: #f60000; } -div.m-math.m-info svg, svg.m-math.m-info { fill: #2e7dc5; } -div.m-math.m-dim svg, svg.m-math.m-dim { fill: #bdbdbd; } +div.m-math.m-default svg, svg.m-math.m-default, div.m-plot svg .m-bar.m-default { + fill: #000000; +} +div.m-math.m-primary svg, svg.m-math.m-primary, div.m-plot svg .m-bar.m-primary { + fill: #cb4b16; +} +div.m-math.m-success svg, svg.m-math.m-success, div.m-plot svg .m-bar.m-success { + fill: #31c25d; +} +div.m-math.m-warning svg, svg.m-math.m-warning, div.m-plot svg .m-bar.m-warning { + fill: #c7cf2f; +} +div.m-math.m-danger svg, svg.m-math.m-danger, div.m-plot svg .m-bar.m-danger { + fill: #f60000; +} +div.m-math.m-info svg, svg.m-math.m-info, div.m-plot svg .m-bar.m-info { + fill: #2e7dc5; +} +div.m-math.m-dim svg, svg.m-math.m-dim, div.m-plot svg .m-bar.m-dim { + fill: #bdbdbd; +} p, ul, ol, dl, blockquote, pre, figure.m-code-figure, figure.m-console-figure, hr, article, article > header, article section, .m-note, .m-frame, .m-block, div.m-button, diff --git a/css/m-light.css b/css/m-light.css index d1e742dd..57908116 100644 --- a/css/m-light.css +++ b/css/m-light.css @@ -94,6 +94,10 @@ --navpanel-link-color: #292929; --navpanel-link-active-color: #cb4b16; + /* Plots */ + --plot-background-color: #fbf0ec; + --plot-error-color: #000000; + /* Colored components */ --default-color: #000000; --default-filled-color: #000000; diff --git a/doc/css/components-plot.svg b/doc/css/components-plot.svg new file mode 100644 index 00000000..f9cc68ef --- /dev/null +++ b/doc/css/components-plot.svg @@ -0,0 +1,40 @@ + + + + + + + + + 0 + + 20 + + 40 + + 60 + + 80 + + 100 + + 120 + + km/h + + + + Cheetah + + Pronghorn + + + + + + + + + + Fastest animals + diff --git a/doc/css/components.rst b/doc/css/components.rst index 25f8637a..fc340fec 100644 --- a/doc/css/components.rst +++ b/doc/css/components.rst @@ -1064,6 +1064,47 @@ the ``depth`` value returned on stderr can be taken as a base for the integrates LaTeX math directly into your :abbr:`reST ` markup for convenient content authoring. +`Plots`_ +======== + +Wrap a :html:`` element in a :html:`
` to make it +centered and occupying full width. Mark plot axes background with +:css:`.m-background`, bars can be styled using :css:`.m-bar` and a +corresponding `CSS color class <#colors>`_. Mark ticks and various other lines +with :css:`.m-line`, error bars with :css:`.m-error`. Use +:html:`` for tick and axes labels and +:html:`` for graph title. + +.. code-figure:: + + .. code:: html + +
+ + + + ... + + + Cheetah + ... + + ... + Fastest animals +
+ + .. container:: m-plot + + .. raw:: html + :file: components-plot.svg + +.. note-success:: + + 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 ` markup. + `Padding`_ ========== diff --git a/doc/plugins.rst b/doc/plugins.rst index b216fad3..afb54bbd 100644 --- a/doc/plugins.rst +++ b/doc/plugins.rst @@ -45,6 +45,7 @@ and restart Pelican. Download the plugins below or - :gh:`m.images ` - :gh:`m.math ` (needs also :gh:`latex2svg `), :gh:`m.code ` (needs also :gh:`ansilexer `) +- :gh:`m.plots ` - :gh:`m.gh `, :gh:`m.dox `, :gh:`m.gl `, @@ -86,6 +87,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 ` sources. +`Plots » <{filename}/plugins/plots.rst>`_ +=================================================== + +With :py:`m.plots` you can render various graphs and charts directly from +values in your :abbr:`reST ` 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>`_ =================================================== diff --git a/doc/plugins/links.rst b/doc/plugins/links.rst index a9fb8899..eb57a94d 100644 --- a/doc/plugins/links.rst +++ b/doc/plugins/links.rst @@ -30,7 +30,7 @@ Links and other .. note-dim:: :class: m-text-center - `« Math and code <{filename}/plugins/math-and-code.rst>`_ | `Pelican plugins <{filename}/plugins.rst>`_ | `Metadata » <{filename}/plugins/metadata.rst>`_ + `« Plots <{filename}/plugins/plots.rst>`_ | `Pelican plugins <{filename}/plugins.rst>`_ | `Metadata » <{filename}/plugins/metadata.rst>`_ .. role:: py(code) :language: py diff --git a/doc/plugins/math-and-code.rst b/doc/plugins/math-and-code.rst index a3210ea6..09b4e568 100644 --- a/doc/plugins/math-and-code.rst +++ b/doc/plugins/math-and-code.rst @@ -30,7 +30,7 @@ Math and code .. note-dim:: :class: m-text-center - `« Images <{filename}/plugins/images.rst>`_ | `Pelican plugins <{filename}/plugins.rst>`_ | `Links and other » <{filename}/plugins/links.rst>`_ + `« Images <{filename}/plugins/images.rst>`_ | `Pelican plugins <{filename}/plugins.rst>`_ | `Plots » <{filename}/plugins/plots.rst>`_ .. role:: css(code) :language: css diff --git a/doc/plugins/plots-test.rst b/doc/plugins/plots-test.rst new file mode 100644 index 00000000..a99935e1 --- /dev/null +++ b/doc/plugins/plots-test.rst @@ -0,0 +1,57 @@ +.. + This file is part of m.css. + + Copyright © 2017, 2018 Vladimír Vondruš + + 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 diff --git a/doc/plugins/plots.rst b/doc/plugins/plots.rst new file mode 100644 index 00000000..1da954ab --- /dev/null +++ b/doc/plugins/plots.rst @@ -0,0 +1,144 @@ +.. + This file is part of m.css. + + Copyright © 2017, 2018 Vladimír Vondruš + + 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. +.. + +Plots +##### + +:breadcrumb: {filename}/plugins.rst Pelican plugins +:footer: + .. note-dim:: + :class: m-text-center + + `« 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. + +.. contents:: + :class: m-block m-default + +`How to use`_ +============= + +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`` +package to your :py:`PLUGINS` in ``pelicanconf.py``. + +.. code:: python + + PLUGINS += ['m.plots'] + +In addition you need the `Matplotlib `_ library +installed. Get it via ``pip`` or your distribution package manager: + +.. code:: sh + + pip3 install matplotlib + +The plugin produces SVG plots that make use of the +`CSS plot styling <{filename}/css/components.rst#plots>`_. + +`Bar graphs`_ +============= + +Currently the only supported plot type is a horizontal bar graph, denoted by +:rst:`:type: hbar`: + +.. code-figure:: + + .. code:: rst + + .. plot:: Fastest animals + :type: barh + :labels: + Cheetah + Pronghorn + Springbok + Wildebeest + :units: km/h + :values: 109.4 88.5 88 80.5 + + .. plot:: Fastest animals + :type: barh + :labels: + Cheetah + Pronghorn + Springbok + Wildebeest + :units: km/h + :values: 109.4 88.5 88 80.5 + +The multi-line :rst:`:labels:` option contain value labels, one per line. You +can specify unit label using :rst:`:units:`, particular values go into +:rst:`:values:` separated by whitespace, there should me as many values as +labels. Hovering over the bars will show the concrete value in a title. + +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 +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`. + +.. code-figure:: + + .. code:: rst + + .. plot:: Runtime cost + :type: barh + :labels: + Ours minimal + Ours default + 3rd party + Full setup + :labels_extra: + 15 modules + 60 modules + 200 modules + for comparison + :units: µs + :values: 15.09 84.98 197.13 934.27 + :errors: 0.74 3.65 9.45 25.66 + :colors: success info danger dim + :bar_height: 0.6 + + .. plot:: Runtime cost + :type: barh + :labels: + Ours minimal + Ours default + 3rd party + Full setup + :labels_extra: + 15 modules + 60 modules + 200 modules + for comparison + :units: µs + :values: 15.09 84.98 197.13 934.27 + :errors: 0.74 3.65 9.45 25.66 + :colors: success info danger dim + :bar_height: 0.6 diff --git a/pelican-plugins/m/plots.py b/pelican-plugins/m/plots.py new file mode 100644 index 00000000..e724a7a3 --- /dev/null +++ b/pelican-plugins/m/plots.py @@ -0,0 +1,244 @@ +# +# This file is part of m.css. +# +# Copyright © 2017, 2018 Vladimír Vondruš +# +# 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 re + +from docutils import nodes, utils +from docutils.parsers import rst +from docutils.parsers.rst import directives +from docutils.parsers.rst.roles import set_classes + +import matplotlib as mpl +import matplotlib.pyplot as plt +import numpy as np +import io + +import pelican.signals + +mpl.rcParams['font.family'] = 'Source Sans Pro' +mpl.rcParams['font.size'] = '11' +mpl.rcParams['axes.titlesize'] = '13' + +# Plot background. Replaced with .m-plot .m-background later, equivalent to +# --default-filled-background-color +mpl.rcParams['axes.facecolor'] = '#cafe01' + +# All of these should match --color, replaced with .m-plot .m-text +mpl.rcParams['text.color'] = '#cafe02' +mpl.rcParams['axes.labelcolor'] = '#cafe02' +mpl.rcParams['xtick.color'] = '#cafe02' +mpl.rcParams['ytick.color'] = '#cafe02' + +# no need to have a border around the plot +mpl.rcParams['axes.spines.left'] = False +mpl.rcParams['axes.spines.right'] = False +mpl.rcParams['axes.spines.top'] = False +mpl.rcParams['axes.spines.bottom'] = False + +mpl.rcParams['svg.fonttype'] = 'none' # otherwise it renders text to paths +mpl.rcParams['figure.autolayout'] = True # so it relayouts everything to fit + +# Gets increased for every graph on a page to (hopefully) ensure unique SVG IDs +mpl.rcParams['svg.hashsalt'] = 0 + +# Color codes for bars +style_mapping = { + 'default': '#cafe03', + 'primary': '#cafe04', + 'success': '#cafe05', + 'warning': '#cafe06', + 'danger': '#cafe07', + 'info': '#cafe08', + 'dim': '#cafe09' +} + +# Patch to remove preamble and hardcoded sizes +_patch_src = re.compile(r"""<\?xml version="1\.0" encoding="utf-8" standalone="no"\?> + + +viewBox="0 0 \d+ \d+(\.\d+)?") width="\d+(\.\d+)?pt" xmlns="http://www\.w3\.org/2000/svg" xmlns:xlink="http://www\.w3\.org/1999/xlink"> +""") +_patch_dst = r"""> +""" + +# Remove needless newlines and trailing space in path data +_path_patch_src = re.compile('(?P[\\dz]) ?\n(?P[LMz])', re.MULTILINE) +_path_patch_dst = '\\g \\g' +_path_patch2_src = re.compile(' ?\n"') +_path_patch2_dst = '"' + +# Mapping from color codes to CSS classes +_class_mapping = [ + # Graph background + ('style="fill:#cafe01;"', 'class="m-background"'), + + # Tick definition in + ('style="stroke:#cafe02;stroke-width:0.8;"', 'class="m-line"'), + # , everything is defined in , no need to repeat + (' definition in + ('style="stroke:#cafe0a;"', 'class="m-error"'), + # , everything is defined in , no need to repeat + (' + + + + m.plots | A Pelican Blog + + + + + + +
+
+
+
+
+
+

m.plots

+ +
+ + + + + + + + + + 15.0 meters, i guess? + + + 30.0 meters, i guess? + + + + + + + + + + + + + + 0 + + + + + + + + + + 5 + + + + + + + + + + 10 + + + + + + + + + + 15 + + + + + + + + + + 20 + + + + + + + + + + 25 + + + + + + + + + + 30 + + + + meters, i guess? + + + + + + + + + + + + + + First + + + + + + + + + + Second + + + + + A plot with a single color + + + + + + + + + +
+
+ + + + + + + + + + 3.0 ± 0.1 Mondays + + + 4.0 ± 2.1 Mondays + + + 5.0 ± 1.0 Mondays + + + + + + + + + + + + + + 0 + + + + + + + + + + 1 + + + + + + + + + + 2 + + + + + + + + + + 3 + + + + + + + + + + 4 + + + + + + + + + + 5 + + + + + + + + + + 6 + + + + Mondays + + + + + + + + + + + + + + January + + + + + + + + + + + February + + + + + + + + + + + March + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a paradise + + + + okay + + + + hell! + + + A plot with separate colors, extra labels, error bars and custom height + + + + + + + + + +
+ +
+
+
+
+
+ + diff --git a/pelican-plugins/m/test/plots/page.rst b/pelican-plugins/m/test/plots/page.rst new file mode 100644 index 00000000..805c81a2 --- /dev/null +++ b/pelican-plugins/m/test/plots/page.rst @@ -0,0 +1,27 @@ +m.plots +####### + +.. plot:: A plot with a single color + :type: barh + :labels: + First + Second + :units: meters, i guess? + :values: 15 30 + :colors: success + +.. plot:: A plot with separate colors, extra labels, error bars and custom height + :type: barh + :labels: + January + February + March + :labels_extra: + a paradise + okay + hell! + :units: Mondays + :values: 3 4 5 + :errors: 0.1 2.1 1.0 + :colors: success info danger + :bar_height: 0.75 diff --git a/pelican-plugins/m/test/test_plots.py b/pelican-plugins/m/test/test_plots.py new file mode 100644 index 00000000..a7d011ac --- /dev/null +++ b/pelican-plugins/m/test/test_plots.py @@ -0,0 +1,36 @@ +# +# This file is part of m.css. +# +# Copyright © 2017, 2018 Vladimír Vondruš +# +# 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. +# + +from . import PluginTestCase + +class Plots(PluginTestCase): + def __init__(self, *args, **kwargs): + super().__init__(__file__, '', *args, **kwargs) + + def test(self): + self.run_pelican({ + 'PLUGINS': ['m.htmlsanity', 'm.plots'] + }) + + self.assertEqual(*self.actual_expected_contents('page.html')) diff --git a/site/pelicanconf.py b/site/pelicanconf.py index 226f3614..55b845bd 100644 --- a/site/pelicanconf.py +++ b/site/pelicanconf.py @@ -88,6 +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'), ('Metadata', 'plugins/metadata/', 'plugins/metadata')]), ('Doxygen theme', 'doxygen/', 'doxygen', []), ('GitHub', 'https://github.com/mosra/m.css', '', [])] @@ -118,6 +119,7 @@ M_LINKS_FOOTER4 = [('Pelican plugins', 'plugins/'), ('Components', 'plugins/components/'), ('Images', 'plugins/images/'), ('Math and code', 'plugins/math-and-code/'), + ('Plots', 'plugins/plots/'), ('Links and other', 'plugins/links/'), ('Metadata', 'plugins/metadata/')] @@ -145,7 +147,8 @@ PLUGINS = ['m.abbr', 'm.htmlsanity', 'm.images', 'm.math', - 'm.metadata'] + 'm.metadata', + 'm.plots'] THEME = '../pelican-theme' THEME_STATIC_DIR = 'static' -- 2.30.2