jmeter-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Ronan Klyne <>
Subject Re: Minor JMeter GUI annoyances
Date Mon, 30 Jun 2008 11:57:04 GMT
Kristof Jozsa wrote:
> Hi Ronan,
> Ronan Klyne wrote:
>>> - while I woulnd't call the Graph Results component unusable, it's 
>>> far from being very useful when you want quality reports :)
>> I use XML logs and XSL to generate my own reports - I find that I can 
>> get all I need with the mathematical capabilities of XSLT2.0 and 
>> usiogn SVG for my graphs.
> Would you mind sharing your XSL tricks? The SVG graphs sound very good.. 
> I used the CSV logs, preprocessed as described in the wiki and used 
> Excel tricks to generate any decent results, but it was quite a pain to 
> do it, and the results are quite far from being very nice..

This requires XSLT2 - I use Saxon 9 as a processor.

I use this code to generate a tree fragment in memory, which describes 
the graph data:
(You'll certainly have to modify this)

     <xsl:variable name="data">
       <xsl:for-each select="distinct-values($groups/group/*/@lb)">
         <xsl:sort select="." data-type="text"/>
         <xsl:variable name="lb" select="." />
         <node label="{$lb}" value="-1" colour="#BFBFFF"/>
         <xsl:for-each select="$groups/group">
           <xsl:sort select="@threads" data-type="number"/>
           <xsl:variable name="group" select="."/>
           <xsl:variable name="times" select="$group/*[@s='true' and 
@lb=$lb and @t]/@t" />
           <xsl:variable name="perc">
             <xsl:call-template name="percentiles">
               <xsl:with-param name="responsetimes" select="$times" />
               <xsl:with-param name="percentile" select="0.95" />
           <node label="{$group/@threads}" value="0{$perc}"/>


And this template to generate the SVG graph from that data:

<xsl:template name="graph">
   <xsl:param name="data"/>
   <xsl:param name="graph_height" select="$def_graph_height"/>
   <xsl:param name="left_margin" select="20"/>
   <xsl:param name="graph_width" select="$def_graph_width"/>
   <xsl:param name="bar_width" select="2*(($graph_width - 
2*$left_margin) div (3*count($data/node)))"/>
   <xsl:param name="bar_spacing" select="1*(($graph_width - 
2*$left_margin) div (3*count($data/node)))"/>

   <xsl:variable name="bar_count" select="count($data/node)"/>
   <xsl:message select="concat('Graph name: ', $data/node[1]/@label)" />
   <xsl:variable name="max_time" select="max($data/node/@value)" />
   <xsl:message select="concat('$max_time: ', $max_time)" />
   <xsl:variable name="fix_scale" select="55000" />
   <xsl:variable name="max_graph_height">
       <xsl:when test="$fix_scale &gt;= 0">
         <xsl:value-of select="$fix_scale"/>
         <xsl:value-of select="floor(($max_time + 999) div 1000) * 1000"/>
   <xsl:variable name="actual_width" select="($bar_count * ($bar_width + 
$bar_spacing)) + $bar_spacing"/>
   <svg:svg id="body" viewBox="-50 -50 {$graph_width + 100} 
{$graph_height + 100}">
     <svg:title>Some title</svg:title>
     <!-- main graphic -->
     <svg:g id="barChart" transform="translate(10, 10)" 
fill-rule="nonzero" clip-rule="nonzero" stroke="none" class="legend"
       stroke-width="1" stroke-linecap="square" stroke-miterlimit="1" 
style="text-anchor:start" shape-rendering="crispEdges">
         <svg:g id="GridAndLegend" style="stroke:none;" 
shape-rendering="crispEdges" stroke-width="1">
           <!-- back face and surrounding lines -->
           <svg:path fill="lightgray" stroke="black" d="M 
$left_margin,{$graph_height + 20} h{$actual_width} v-{$graph_height} 
h-{$actual_width} v{$graph_height}"/>
           <!-- draw zero mark and legend -->
           <svg:path fill="none" stroke="black" d="M {$left_margin - 
10},{$graph_height + 20} h10"/>
           <svg:text text-anchor="end" baseline-shift="-3" 
transform="matrix(1 0 0 1 {$left_margin - 15} {$graph_height + 
           <xsl:variable name="step" select="$max_graph_height idiv 10"/>
           <xsl:if test="$step = 0">
             <xsl:message select="$data"/>
           <xsl:if test="$step > 0">
           <xsl:for-each select="for $i in 1 to ($max_graph_height idiv 
$step) return $step * $i">
             <xsl:variable name="vert_posn" select="(. div 
$max_graph_height) * $graph_height"/>
             <svg:path fill="none" stroke="black" d="M {$left_margin - 
10},{$graph_height + 20 - floor($vert_posn)} h{$actual_width + 10}"/>
             <svg:text text-anchor="end" baseline-shift="-3" 
transform="matrix(1 0 0 1 {$left_margin - 15} {$graph_height + 20 - 
               <xsl:value-of select="."/>

         <!-- draw the graph bars themselves from data -->
         <xsl:for-each select="$data/node">
           <xsl:variable name="value" select="if (@value >=0) then 
@value else $max_graph_height"/>
           <xsl:variable name="bar_height" select="floor(($value div 
$max_graph_height) * $graph_height)"/>
           <xsl:variable name="bar_left" select="((position() - 1) * 
($bar_width + $bar_spacing)) + $bar_spacing"/>
           <xsl:variable name="colour" select="if (@colour) then @colour 
else 'blue'" />
           <!-- draw the bar -->
           <svg:path fill="{$colour}" stroke="none" d="M {$bar_left + 
$left_margin},{$graph_height + 19} h{$bar_width} v-{$bar_height} 
h-{$bar_width} v{$bar_height}"/>
           <!-- draw the label -->
           <!--xsl:if test="not 
(./preceding-sibling::*[1][substring-after(@label, '-') = 
substring-after(current()/@label, '-')])"-->
             <svg:text text-anchor="left" transform="matrix(0 -1 1 0 
{$left_margin + $bar_left + ($bar_width div 2) + 1} {$graph_height + 40})">
               <xsl:value-of select="@label"/>
       <!--svg:text transform="matrix(2 0 0 2 {$left_margin} 
{$graph_height + 70})">Operation scaling</svg:text-->


Then this code to put the graph in a file.

     <xsl:if test="$data/node">
       <xsl:result-document href="graph-{$graph-name}" format="svg">
         <xsl:call-template name="graph">
           <xsl:with-param name="data" select="$data" />

This depends on having the named output method 'svg' described at the 
top of the document, thusly:

<xsl:output name="svg" method="xml" indent="yes" encoding="UTF-8" />

This will probably need a lot of customisation to produce what you need, 
but should serve as a starting point.
I wouldn't want anyone to have to go through writing a bar chart from 
scratch in XSL again ;)



Ronan Klyne
Business Collaborator Developer
Tel: +44 01189 028518

To unsubscribe, e-mail:
For additional commands, e-mail:

View raw message