]
# Titles for bars
-_bar_titles_src = '<g id="plot{}-value{}">'
-_bar_titles_dst = '<g id="plot{}-value{}"><title>{} {}</title>'
-_bar_titles_dst_error = '<g id="plot{}-value{}"><title>{} ± {} {}</title>'
+_bar_titles_src = '<g id="plot{}-value{}-{}">'
+_bar_titles_dst = '<g id="plot{}-value{}-{}"><title>{} {}</title>'
+_bar_titles_dst_error = '<g id="plot{}-value{}-{}"><title>{} ± {} {}</title>'
class Plot(rst.Directive):
required_arguments = 1
else:
labels_extra = None
- # Values. Should be one for each label.
- values = [float(v) for v in self.options['values'].split()]
- assert len(values) == len(labels)
+ # Values. Should be one for each label, if there are multiple lines
+ # then the values get stacked.
+ value_sets = []
+ for row in self.options['values'].split('\n'):
+ values = [float(v) for v in row.split()]
+ assert len(values) == len(labels)
+ value_sets += [values]
# Optional errors
if 'errors' in self.options:
- errors = [float(e) for e in self.options['errors'].split()]
+ error_sets = []
+ for row in self.options['errors'].split('\n'):
+ errors = [float(e) for e in row.split()]
+ assert len(errors) == len(values)
+ error_sets += [errors]
+ assert len(error_sets) == len(value_sets)
else:
- errors = None
+ error_sets = [None]*len(value_sets)
# Colors. Should be either one for all or one for every value
- colors = [style_mapping[c] for c in self.options.get('colors', 'default').split()]
- if len(colors) == 1: colors = colors[0]
- else: assert len(colors) == len(labels)
+ if 'colors' in self.options:
+ color_sets = []
+ for row in self.options['colors'].split('\n'):
+ colors = [style_mapping[c] for c in row.split()]
+ if len(colors) == 1: colors = colors[0]
+ else: assert len(colors) == len(labels)
+ color_sets += [colors]
+ assert len(color_sets) == len(value_sets)
+ else:
+ color_sets = [style_mapping['default']]*len(value_sets)
# Bar height
bar_height = float(self.options.get('bar_height', '0.4'))
# Setup the graph
fig, ax = plt.subplots()
# TODO: let matplotlib calculate the height somehow
- fig.set_size_inches(8, 0.78 + len(values)*bar_height)
+ fig.set_size_inches(8, 0.78 + len(labels)*bar_height)
yticks = np.arange(len(labels))
- plot = ax.barh(yticks, values, xerr=errors,
- align='center', color=colors, ecolor='#cafe0a', capsize=5*bar_height/0.4)
- for i, v in enumerate(plot):
- v.set_gid('plot{}-value{}'.format(mpl.rcParams['svg.hashsalt'], i))
+ left = np.array([0.0]*len(labels))
+ for i in range(len(value_sets)):
+ plot = ax.barh(yticks, value_sets[i], xerr=error_sets[i],
+ align='center', color=color_sets[i], ecolor='#cafe0a', capsize=5*bar_height/0.4, left=left)
+ left += np.array(value_sets[i])
+ for j, v in enumerate(plot):
+ v.set_gid('plot{}-value{}-{}'.format(mpl.rcParams['svg.hashsalt'], i, j))
ax.set_yticks(yticks)
ax.invert_yaxis() # top-to-bottom
ax.set_xlabel(units)
# Replace color codes with CSS classes
for src, dst in _class_mapping: imgdata = imgdata.replace(src, dst)
# Add titles for bars
- for i in range(len(values)):
- if errors: imgdata = imgdata.replace(
- _bar_titles_src.format(mpl.rcParams['svg.hashsalt'], i),
- _bar_titles_dst_error.format(mpl.rcParams['svg.hashsalt'], i, values[i], errors[i], units))
- else: imgdata = imgdata.replace(
- _bar_titles_src.format(mpl.rcParams['svg.hashsalt'], i),
- _bar_titles_dst.format(mpl.rcParams['svg.hashsalt'], i, values[i], units))
+ for i in range(len(value_sets)):
+ for j in range(len(labels)):
+ id = i*len(labels) + j
+ if error_sets[i]: imgdata = imgdata.replace(
+ _bar_titles_src.format(mpl.rcParams['svg.hashsalt'], i, j),
+ _bar_titles_dst_error.format(mpl.rcParams['svg.hashsalt'], i, j, value_sets[i][j], error_sets[i][j], units))
+ else: imgdata = imgdata.replace(
+ _bar_titles_src.format(mpl.rcParams['svg.hashsalt'], i, j),
+ _bar_titles_dst.format(mpl.rcParams['svg.hashsalt'], i, j, value_sets[i][j], units))
container = nodes.container(**self.options)
container['classes'] += ['m-plot']
<g id="patch_1">
<path d="M 59.365156 69.588125 L 560.62 69.588125 L 560.62 27.757969 L 59.365156 27.757969 z" class="m-background"/>
</g>
- <g id="plot1-value0"><title>15.0 meters, i guess?</title>
+ <g id="plot1-value0-0"><title>15.0 meters, i guess?</title>
<path clip-path="url(#p2abd2612b1)" d="M 59.365156 29.659339 L 298.057939 29.659339 L 298.057939 46.560413 L 59.365156 46.560413 z" class="m-bar m-success"/>
</g>
- <g id="plot1-value1"><title>30.0 meters, i guess?</title>
+ <g id="plot1-value0-1"><title>30.0 meters, i guess?</title>
<path clip-path="url(#p2abd2612b1)" d="M 59.365156 50.785681 L 536.750722 50.785681 L 536.750722 67.686754 L 59.365156 67.686754 z" class="m-bar m-success"/>
</g>
<g id="matplotlib.axis_1">
<g id="patch_1">
<path d="M 68.216719 173.988125 L 558.482422 173.988125 L 558.482422 27.757969 L 68.216719 27.757969 z" class="m-background"/>
</g>
- <g id="plot2-value0"><title>3.0 ± 0.1 Mondays</title>
+ <g id="plot2-value0-0"><title>3.0 ± 0.1 Mondays</title>
<path clip-path="url(#p1198f4ed7e)" d="M 68.216719 34.404794 L 297.849367 34.404794 L 297.849367 72.386653 L 68.216719 72.386653 z" class="m-bar m-success"/>
</g>
- <g id="plot2-value1"><title>4.0 ± 2.1 Mondays</title>
+ <g id="plot2-value0-1"><title>4.0 ± 2.1 Mondays</title>
<path clip-path="url(#p1198f4ed7e)" d="M 68.216719 81.882117 L 374.393583 81.882117 L 374.393583 119.863976 L 68.216719 119.863976 z" class="m-bar m-info"/>
</g>
- <g id="plot2-value2"><title>5.0 ± 1.0 Mondays</title>
+ <g id="plot2-value0-2"><title>5.0 ± 1.0 Mondays</title>
<path clip-path="url(#p1198f4ed7e)" d="M 68.216719 129.359441 L 450.937798 129.359441 L 450.937798 167.3413 L 68.216719 167.3413 z" class="m-bar m-danger"/>
</g>
<g id="matplotlib.axis_1">
</defs>
</svg>
</div>
+<div class="m-plot">
+<svg viewBox="0 0 576 142.56">
+ <defs>
+ <style type="text/css">
+*{stroke-linecap:butt;stroke-linejoin:round;}
+ </style>
+ </defs>
+ <g id="figure_1">
+ <g id="axes_1">
+ <g id="patch_1">
+ <path d="M 26.561094 98.388125 L 560.62 98.388125 L 560.62 27.757969 L 26.561094 27.757969 z" class="m-background"/>
+ </g>
+ <g id="plot3-value0-0"><title>111.9 kB</title>
+ <path clip-path="url(#pd6a36f6853)" d="M 26.561094 30.96843 L 94.068413 30.96843 L 94.068413 49.313926 L 26.561094 49.313926 z" class="m-bar m-success"/>
+ </g>
+ <g id="plot3-value0-1"><title>74.4 kB</title>
+ <path clip-path="url(#pd6a36f6853)" d="M 26.561094 53.900299 L 71.445317 53.900299 L 71.445317 72.245794 L 26.561094 72.245794 z" class="m-bar m-success"/>
+ </g>
+ <g id="plot3-value0-2"><title>52.1 kB</title>
+ <path clip-path="url(#pd6a36f6853)" d="M 26.561094 76.832168 L 57.992115 76.832168 L 57.992115 95.177663 L 26.561094 95.177663 z" class="m-bar m-success"/>
+ </g>
+ <g id="plot3-value1-0"><title>731.2 kB</title>
+ <path clip-path="url(#pd6a36f6853)" d="M 94.068413 30.96843 L 535.188624 30.96843 L 535.188624 49.313926 L 94.068413 49.313926 z" class="m-bar m-info"/>
+ </g>
+ <g id="plot3-value1-1"><title>226.3 kB</title>
+ <path clip-path="url(#pd6a36f6853)" d="M 71.445317 53.900299 L 207.968161 53.900299 L 207.968161 72.245794 L 71.445317 72.245794 z" class="m-bar m-info"/>
+ </g>
+ <g id="plot3-value1-2"><title>226.0 kB</title>
+ <path clip-path="url(#pd6a36f6853)" d="M 57.992115 76.832168 L 194.333975 76.832168 L 194.333975 95.177663 L 57.992115 95.177663 z" class="m-bar m-info"/>
+ </g>
+ <g id="matplotlib.axis_1">
+ <g id="xtick_1">
+ <g id="line2d_1">
+ <defs>
+ <path d="M 0 0 L 0 3.5" id="m230bf1d664" class="m-line"/>
+ </defs>
+ <g>
+ <use x="26.561094" xlink:href="#m230bf1d664" y="98.388125"/>
+ </g>
+ </g>
+ <g id="text_1">
+ <text class="m-label" style="text-anchor:middle;" transform="rotate(-0, 26.561094, 113.746406)" x="26.561094" y="113.746406">0</text>
+ </g>
+ </g>
+ <g id="xtick_2">
+ <g id="line2d_2">
+ <g>
+ <use x="86.88935" xlink:href="#m230bf1d664" y="98.388125"/>
+ </g>
+ </g>
+ <g id="text_2">
+ <text class="m-label" style="text-anchor:middle;" transform="rotate(-0, 86.88935, 113.746406)" x="86.88935" y="113.746406">100</text>
+ </g>
+ </g>
+ <g id="xtick_3">
+ <g id="line2d_3">
+ <g>
+ <use x="147.217607" xlink:href="#m230bf1d664" y="98.388125"/>
+ </g>
+ </g>
+ <g id="text_3">
+ <text class="m-label" style="text-anchor:middle;" transform="rotate(-0, 147.217607, 113.746406)" x="147.217607" y="113.746406">200</text>
+ </g>
+ </g>
+ <g id="xtick_4">
+ <g id="line2d_4">
+ <g>
+ <use x="207.545863" xlink:href="#m230bf1d664" y="98.388125"/>
+ </g>
+ </g>
+ <g id="text_4">
+ <text class="m-label" style="text-anchor:middle;" transform="rotate(-0, 207.545863, 113.746406)" x="207.545863" y="113.746406">300</text>
+ </g>
+ </g>
+ <g id="xtick_5">
+ <g id="line2d_5">
+ <g>
+ <use x="267.874119" xlink:href="#m230bf1d664" y="98.388125"/>
+ </g>
+ </g>
+ <g id="text_5">
+ <text class="m-label" style="text-anchor:middle;" transform="rotate(-0, 267.874119, 113.746406)" x="267.874119" y="113.746406">400</text>
+ </g>
+ </g>
+ <g id="xtick_6">
+ <g id="line2d_6">
+ <g>
+ <use x="328.202376" xlink:href="#m230bf1d664" y="98.388125"/>
+ </g>
+ </g>
+ <g id="text_6">
+ <text class="m-label" style="text-anchor:middle;" transform="rotate(-0, 328.202376, 113.746406)" x="328.202376" y="113.746406">500</text>
+ </g>
+ </g>
+ <g id="xtick_7">
+ <g id="line2d_7">
+ <g>
+ <use x="388.530632" xlink:href="#m230bf1d664" y="98.388125"/>
+ </g>
+ </g>
+ <g id="text_7">
+ <text class="m-label" style="text-anchor:middle;" transform="rotate(-0, 388.530632, 113.746406)" x="388.530632" y="113.746406">600</text>
+ </g>
+ </g>
+ <g id="xtick_8">
+ <g id="line2d_8">
+ <g>
+ <use x="448.858889" xlink:href="#m230bf1d664" y="98.388125"/>
+ </g>
+ </g>
+ <g id="text_8">
+ <text class="m-label" style="text-anchor:middle;" transform="rotate(-0, 448.858889, 113.746406)" x="448.858889" y="113.746406">700</text>
+ </g>
+ </g>
+ <g id="xtick_9">
+ <g id="line2d_9">
+ <g>
+ <use x="509.187145" xlink:href="#m230bf1d664" y="98.388125"/>
+ </g>
+ </g>
+ <g id="text_9">
+ <text class="m-label" style="text-anchor:middle;" transform="rotate(-0, 509.187145, 113.746406)" x="509.187145" y="113.746406">800</text>
+ </g>
+ </g>
+ <g id="text_10">
+ <text class="m-label" style="text-anchor:middle;" transform="rotate(-0, 293.590547, 128.392344)" x="293.590547" y="128.392344">kB</text>
+ </g>
+ </g>
+ <g id="matplotlib.axis_2">
+ <g id="ytick_1">
+ <g id="line2d_10">
+ <defs>
+ <path d="M 0 0 L -3.5 0" id="m1924854559" class="m-line"/>
+ </defs>
+ <g>
+ <use x="26.561094" xlink:href="#m1924854559" y="40.141178"/>
+ </g>
+ </g>
+ <g id="text_11">
+ <text class="m-label" style="text-anchor:end;" transform="rotate(-0, 19.561094, 44.320319)" x="19.561094" y="44.320319">A</text>
+ </g>
+ </g>
+ <g id="ytick_2">
+ <g id="line2d_11">
+ <g>
+ <use x="26.561094" xlink:href="#m1924854559" y="63.073047"/>
+ </g>
+ </g>
+ <g id="text_12">
+ <text class="m-label" style="text-anchor:end;" transform="rotate(-0, 19.561094, 67.252188)" x="19.561094" y="67.252188">B</text>
+ </g>
+ </g>
+ <g id="ytick_3">
+ <g id="line2d_12">
+ <g>
+ <use x="26.561094" xlink:href="#m1924854559" y="86.004916"/>
+ </g>
+ </g>
+ <g id="text_13">
+ <text class="m-label" style="text-anchor:end;" transform="rotate(-0, 19.561094, 90.184056)" x="19.561094" y="90.184056">C</text>
+ </g>
+ </g>
+ </g>
+ <g id="text_14">
+ <text class="m-title" style="text-anchor:middle;" transform="rotate(-0, 293.590547, 21.757969)" x="293.590547" y="21.757969">Stacked plot</text>
+ </g>
+ </g>
+ </g>
+ <defs>
+ <clipPath id="pd6a36f6853">
+ <rect height="70.630156" width="534.058906" x="26.561094" y="27.757969"/>
+ </clipPath>
+ </defs>
+</svg>
+</div>
+<div class="m-plot">
+<svg viewBox="0 0 576 113.76">
+ <defs>
+ <style type="text/css">
+*{stroke-linecap:butt;stroke-linejoin:round;}
+ </style>
+ </defs>
+ <g id="figure_1">
+ <g id="axes_1">
+ <g id="patch_1">
+ <path d="M 26.427031 69.588125 L 560.62 69.588125 L 560.62 27.757969 L 26.427031 27.757969 z" class="m-background"/>
+ </g>
+ <g id="plot4-value0-0"><title>111.9 ± 25.0 kB</title>
+ <path clip-path="url(#pf9f5e4e753)" d="M 26.427031 29.659339 L 81.004452 29.659339 L 81.004452 46.560413 L 26.427031 46.560413 z" class="m-bar m-success"/>
+ </g>
+ <g id="plot4-value0-1"><title>74.4 ± 15.3 kB</title>
+ <path clip-path="url(#pf9f5e4e753)" d="M 26.427031 50.785681 L 62.714432 50.785681 L 62.714432 67.686754 L 26.427031 67.686754 z" class="m-bar m-danger"/>
+ </g>
+ <g id="plot4-value1-0"><title>731.2 ± 200.0 kB</title>
+ <path clip-path="url(#pf9f5e4e753)" d="M 81.004452 29.659339 L 437.635464 29.659339 L 437.635464 46.560413 L 81.004452 46.560413 z" class="m-bar m-info"/>
+ </g>
+ <g id="plot4-value1-1"><title>226.3 ± 5.0 kB</title>
+ <path clip-path="url(#pf9f5e4e753)" d="M 62.714432 50.785681 L 173.088608 50.785681 L 173.088608 67.686754 L 62.714432 67.686754 z" class="m-bar m-primary"/>
+ </g>
+ <g id="matplotlib.axis_1">
+ <g id="xtick_1">
+ <g id="line2d_1">
+ <defs>
+ <path d="M 0 0 L 0 3.5" id="med42be8496" class="m-line"/>
+ </defs>
+ <g>
+ <use x="26.427031" xlink:href="#med42be8496" y="69.588125"/>
+ </g>
+ </g>
+ <g id="text_1">
+ <text class="m-label" style="text-anchor:middle;" transform="rotate(-0, 26.427031, 84.946406)" x="26.427031" y="84.946406">0</text>
+ </g>
+ </g>
+ <g id="xtick_2">
+ <g id="line2d_2">
+ <g>
+ <use x="123.973807" xlink:href="#med42be8496" y="69.588125"/>
+ </g>
+ </g>
+ <g id="text_2">
+ <text class="m-label" style="text-anchor:middle;" transform="rotate(-0, 123.973807, 84.946406)" x="123.973807" y="84.946406">200</text>
+ </g>
+ </g>
+ <g id="xtick_3">
+ <g id="line2d_3">
+ <g>
+ <use x="221.520583" xlink:href="#med42be8496" y="69.588125"/>
+ </g>
+ </g>
+ <g id="text_3">
+ <text class="m-label" style="text-anchor:middle;" transform="rotate(-0, 221.520583, 84.946406)" x="221.520583" y="84.946406">400</text>
+ </g>
+ </g>
+ <g id="xtick_4">
+ <g id="line2d_4">
+ <g>
+ <use x="319.067358" xlink:href="#med42be8496" y="69.588125"/>
+ </g>
+ </g>
+ <g id="text_4">
+ <text class="m-label" style="text-anchor:middle;" transform="rotate(-0, 319.067358, 84.946406)" x="319.067358" y="84.946406">600</text>
+ </g>
+ </g>
+ <g id="xtick_5">
+ <g id="line2d_5">
+ <g>
+ <use x="416.614134" xlink:href="#med42be8496" y="69.588125"/>
+ </g>
+ </g>
+ <g id="text_5">
+ <text class="m-label" style="text-anchor:middle;" transform="rotate(-0, 416.614134, 84.946406)" x="416.614134" y="84.946406">800</text>
+ </g>
+ </g>
+ <g id="xtick_6">
+ <g id="line2d_6">
+ <g>
+ <use x="514.160909" xlink:href="#med42be8496" y="69.588125"/>
+ </g>
+ </g>
+ <g id="text_6">
+ <text class="m-label" style="text-anchor:middle;" transform="rotate(-0, 514.160909, 84.946406)" x="514.160909" y="84.946406">1000</text>
+ </g>
+ </g>
+ <g id="text_7">
+ <text class="m-label" style="text-anchor:middle;" transform="rotate(-0, 293.523516, 99.592344)" x="293.523516" y="99.592344">kB</text>
+ </g>
+ </g>
+ <g id="matplotlib.axis_2">
+ <g id="ytick_1">
+ <g id="line2d_7">
+ <defs>
+ <path d="M 0 0 L -3.5 0" id="m786f014bed" class="m-line"/>
+ </defs>
+ <g>
+ <use x="26.427031" xlink:href="#m786f014bed" y="38.109876"/>
+ </g>
+ </g>
+ <g id="text_8">
+ <text class="m-label" style="text-anchor:end;" transform="rotate(-0, 19.427031, 42.289017)" x="19.427031" y="42.289017">A</text>
+ </g>
+ </g>
+ <g id="ytick_2">
+ <g id="line2d_8">
+ <g>
+ <use x="26.427031" xlink:href="#m786f014bed" y="59.236218"/>
+ </g>
+ </g>
+ <g id="text_9">
+ <text class="m-label" style="text-anchor:end;" transform="rotate(-0, 19.427031, 63.415358)" x="19.427031" y="63.415358">B</text>
+ </g>
+ </g>
+ </g>
+ <g id="LineCollection_1">
+ <path clip-path="url(#pf9f5e4e753)" d="M 68.811105 38.109876 L 93.197799 38.109876" class="m-error"/>
+ <path clip-path="url(#pf9f5e4e753)" d="M 55.252103 59.236218 L 70.17676 59.236218" class="m-error"/>
+ </g>
+ <g id="LineCollection_2">
+ <path clip-path="url(#pf9f5e4e753)" d="M 340.088688 38.109876 L 535.18224 38.109876" class="m-error"/>
+ <path clip-path="url(#pf9f5e4e753)" d="M 170.649939 59.236218 L 175.527278 59.236218" class="m-error"/>
+ </g>
+ <g id="line2d_9">
+ <defs>
+ <path d="M 0 5 L 0 -5" id="m1e7a6d6b54" class="m-error"/>
+ </defs>
+ <g clip-path="url(#pf9f5e4e753)">
+ <use x="68.811105" xlink:href="#m1e7a6d6b54" y="38.109876"/>
+ <use x="55.252103" xlink:href="#m1e7a6d6b54" y="59.236218"/>
+ </g>
+ </g>
+ <g id="line2d_10">
+ <g clip-path="url(#pf9f5e4e753)">
+ <use x="93.197799" xlink:href="#m1e7a6d6b54" y="38.109876"/>
+ <use x="70.17676" xlink:href="#m1e7a6d6b54" y="59.236218"/>
+ </g>
+ </g>
+ <g id="line2d_11">
+ <g clip-path="url(#pf9f5e4e753)">
+ <use x="340.088688" xlink:href="#m1e7a6d6b54" y="38.109876"/>
+ <use x="170.649939" xlink:href="#m1e7a6d6b54" y="59.236218"/>
+ </g>
+ </g>
+ <g id="line2d_12">
+ <g clip-path="url(#pf9f5e4e753)">
+ <use x="535.18224" xlink:href="#m1e7a6d6b54" y="38.109876"/>
+ <use x="175.527278" xlink:href="#m1e7a6d6b54" y="59.236218"/>
+ </g>
+ </g>
+ <g id="text_10">
+ <text class="m-title" style="text-anchor:middle;" transform="rotate(-0, 293.523516, 21.757969)" x="293.523516" y="21.757969">Stacked plot with errors and full colors</text>
+ </g>
+ </g>
+ </g>
+ <defs>
+ <clipPath id="pf9f5e4e753">
+ <rect height="41.830156" width="534.192969" x="26.427031" y="27.757969"/>
+ </clipPath>
+ </defs>
+</svg>
+</div>
<!-- /content -->
</div>
</div>