[Git][NTPsec/ntpsec][master] ntpviz: Improve html formatting. Make code my Python-ish

Gary E. Miller gitlab at mg.gitlab.com
Fri Oct 14 03:58:53 UTC 2016


Gary E. Miller pushed to branch master at NTPsec / ntpsec


Commits:
d44853f5 by Gary E. Miller at 2016-10-13T20:54:11-07:00
ntpviz: Improve html formatting.  Make code my Python-ish

Python string formatting fails on nested objects.  So change
the code to use special purpose dictionaries.  It looks more
Python-ish, but about the same lines of code, and those lines
are more complex. Maybe just a tiny win on style points and
encapsulation, but a loss on complexity.

- - - - -


2 changed files:

- ntpstats/ntpviz
- pylib/statfiles.py


Changes:

=====================================
ntpstats/ntpviz
=====================================
--- a/ntpstats/ntpviz
+++ b/ntpstats/ntpviz
@@ -72,21 +72,9 @@ class VizStats(NTPStats):
     title       = ''          # title
     unit        = 's'         # display units: s, ppm, etc.
     multiplier  = 1
-    pmax        = 0     # 100%, can't use max, reserved word
-    ninetynine  = 0     #  99%
-    ninetyfive  = 0     #  90%
-    fifty       = 0     #  50%
-    five        = 0     #  5%
-    one         = 0     #  1%
-    pmin        = 0     #  0%, can't use min, reserved word
-
-    nf_m_f      = 0     # 95% - 5%
-    nn_m_o      = 0     # 99% - 1%
-
-    mu          = 0     # arithmetic mean
-    pstd        = 0     # population standard distribution, one sigma
+
     csv_head =  """\
-Name, Min, 1%, 5%, 50%, 95%, 99%, Max, 90% Range, 98% Range, StdDev, \
+Name, Min, 1%, 5%, 50%, 95%, 99%, Max,, 90% Range, 98% Range, StdDev,, \
 Mean, Units
 """
 
@@ -95,25 +83,17 @@ Mean, Units
 <thead>
   <tr style="font-weight:bold;text-align:left;">
     <td ></td>
-    <td colspan=7>  Percentiles......</td>
-    <td colspan=2>  Ranges......</td>
+    <td colspan=8> Percentiles......</td>
+    <td colspan=3> Ranges......</td>
     <td colspan=2></td>
     <td ></td>
   </tr>
-  <tr style="font-weight:bold;">
-    <td style="text-align:left;border-bottom:solid black;">Name</td>
-    <td style="border-bottom:solid black;">Min</td>
-    <td style="border-bottom:solid black;">1%</td>
-    <td style="border-bottom:solid black;">5%</td>
-    <td style="border-bottom:solid black;">50%</td>
-    <td style="border-bottom:solid black;">95%</td>
-    <td style="border-bottom:solid black;">99%</td>
-    <td style="border-bottom:solid black;">Max</td>
-    <td style="border-bottom:solid black;">90%</td>
-    <td style="border-bottom:solid black;">95%</td>
-    <td style="border-bottom:solid black;">StdDev</td>
-    <td style="border-bottom:solid black;">Mean</td>
-    <td style="border-bottom:solid black;">Units</td>
+  <tr style="font-weight:bold;text-align:right;">
+    <td style="text-align:left;">Name</td>
+    <td>Min</td><td>1%</td><td>5%</td><td>50%</td><td>95%</td>
+    <td>99%</td><td>Max</td> <td style="width:10px;"> </td>
+    <td>90%</td><td>95%</td><td>StdDev</td>
+    <td style="width:10px;"> </td><td>Mean</td><td>Units</td>
   </tr>
 </thead>
 """
@@ -129,12 +109,12 @@ Mean, Units
         if args.clip:
             # keep 99% and 1% under 999 in selected units
             # clip to 1% and 99%
-            target = max(self.percs[99], -self.percs[1])
+            target = max(self.percs["p99"], -self.percs["p1"])
         else:
             # keep 99% and 1% under 999 in selected units
             # but do not let 100% and 1% go over 5000 in selected units
-            target = max(self.percs[99], -self.percs[1], self.percs[100]/5,
-                         -self.percs[0]/5)
+            target = max(self.percs["p99"], -self.percs["p1"],
+                         self.percs["p100"]/5, -self.percs["p0"]/5)
 
         if 1 <= target:
             self.multiplier = 1
@@ -170,54 +150,83 @@ Mean, Units
                 # go to nanosec
                 self.unit = "ns"
 
+        self.percs["mu"]      = mean( values )
+        self.percs["pstd"]    = pstdev( values, mu=self.percs["mu"] )
+
+        # range the data
         self.percs.update({k: v * self.multiplier
                      for k, v in list(self.percs.items())})
 
         self.title       = title
-        self.pmax        = self.percs[100]
-        self.ninetynine  = self.percs[99]
-        self.ninetyfive  = self.percs[95]
-        self.fifty       = self.percs[50]
-        self.five        = self.percs[5]
-        self.one         = self.percs[1]
-        self.pmin        = self.percs[0]
-
-        self.nf_m_f     = self.ninetyfive - self.five
-        self.nn_m_o     = self.ninetynine - self.one
-
-        self.mu = mean( values )
-        self.pstd = pstdev( values, mu=self.mu ) * self.multiplier
-        self.mu *= self.multiplier
+
+        # calculate ranges
+        self.percs["r90"] = self.percs["p95"] - self.percs["p5"]
+        self.percs["r98"] = self.percs["p99"] - self.percs["p1"]
+
+        # calculate mean +/- std dev
+        self.percs["m1sigma"] = self.percs["mu"] - self.percs["pstd"]
+        self.percs["p1sigma"] = self.percs["mu"] + self.percs["pstd"]
+
+        # pretty print the values
+        self.percs_f = {}
+        for k, v in self.percs.items():
+            self.percs[k]   = round(v,3)
+            self.percs_f[k] = format(v,",.3f")
+
+        # Python is stupid about nested objects, so add in some other stuff
+        self.percs_f["multiplier"] = self.percs["multiplier"] = self.multiplier
+        self.percs_f["title"]      = self.percs["title"]      = self.title
+        self.percs_f["unit"]       = self.percs["unit"]       = self.unit
+
+        if args.clip:
+            self.percs["min_y"] = self.percs["p1"]
+            self.percs["max_y"] = self.percs["p99"]
+            self.percs["clipped"] = " (clipped)"
+        else:
+            self.percs["min_y"] = self.percs["max_y"] = '*'
+            self.percs["clipped"] = ""
+
         self.stats_html =  ''
         if '' != title:
             self.stats_html =  "<h4>%(title)s</h4>\n" % locals()
+
         self.stats_html +=  """\
-<p style="margin-left:20px;"><b>Percentiles</b>:
- Min: %(pmin).3f,  
- 1%%: %(one).3f,  
- 5%%: %(five).3f,  
- 50%%: %(fifty).3f,  
- 95%%: %(ninetyfive).3f,  
- 99%%: %(ninetynine).3f,  
- Max: %(pmax).3f  
- %(unit)s<br>
-<b>Ranges:</b>
- 90%% (95%% - 5%%) = %(nf_m_f).3f,  
- 98%% (99%% - 1%%) = %(nn_m_o).3f %(unit)s<br>
-<b>Deviation:</b>
- 1σ = %(pstd).3f,  
- Mean = %(mu).3f %(unit)s</p>
-""" % self.__dict__
-
-        self.csv =  """\
-%(title)s, %(pmin).3f, %(one).3f, %(five).3f, %(fifty).3f, %(ninetyfive).3f, \
-%(ninetynine).3f, %(pmax).3f, %(nf_m_f).3f, %(nn_m_o).3f, %(pstd).3f, \
-%(mu).3f, %(unit)s
-""" % self.__dict__
+<table style="margin-left:20px;border-spacing: 10px 0;">
+  <tr style="text-align:left;font-weight:bold;">
+    <td colspan=8> Percentiles......</td>
+    <td colspan=3> Ranges......</td>
+    <td colspan=2></td>
+    <td ></td>
+  </tr>
+  <tr style="font-weight:bold;font-weight:bold;text-align:right;">
+    <td style="min-width:55px;">Min</td><td style="min-width:55px;">1%%</td>
+    <td style="min-width:55px;">5%%</td><td style="min-width:55px;">50%%</td>
+    <td style="min-width:55px;">95%%</td><td style="min-width:55px;">99%%</td>
+    <td style="min-width:55px;">Max</td><td> </td>
+    <td style="min-width:55px;">90%%</td><td style="min-width:55px;">95%%</td>
+    <td style="min-width:55px;">StdDev</td>
+    <td> </td><td style="min-width:55px;">Mean</td><td>Units</td>
+  </tr>
+  <tr style="text-align:right;">
+    <td>%(p0)s</td><td>%(p1)s</td><td>%(p5)s</td><td>%(p50)s</td>
+    <td>%(p95)s</td><td>%(p95)s</td><td>%(p100)s</td><td> </td>
+    <td>%(r90)s</td><td>%(r98)s</td><td>%(pstd)s</td><td> </td>
+    <td>%(mu)s</td><td>%(unit)s</td>
+  </tr>
+</table>
+""" % self.percs_f
+
+        s =  """\
+%(title)s, %(p0)s, %(p1)s, %(p5)s, %(p50)s, %(p95)s, %(p99)s, %(p100)s, , \
+ %(r90)s, %(r98)s, %(pstd)s, , %(mu)s, %(unit)s
+"""
+
+        self.csv   =  s % self.percs    # no commas in the csv
+        self.table =  s % self.percs_f
 
         self.table = '<tr style="vertical-align:top;">' + \
                      '<td style="text-align:left;">' + \
-                            self.csv.replace( ", ", "</td><td>") + \
+                            self.table.replace( ", ", "</td><td>") + \
                            "</td></tr>\n"
 
         return
@@ -293,29 +302,21 @@ set rmargin 12
         if not len( self.loopstats):
             sys.stderr.write("ntpviz: WARNING: no loopstats to graph\n")
             return ''
-        sitename = self.sitename
 
         # compute clock offset
         values = [float(line.split()[1]) for line in self.loopstats]
         stats = VizStats( values, "Local Clock Time Offset")
-        unit = stats.unit
-        multiplier = stats.multiplier
 
         # compute frequency offset
         values_f = [float(line.split()[2]) for line in self.loopstats]
         stats_f = VizStats(values_f, "Local Clock Frequency Offset", freq=1)
-        unit_f = stats_f.unit
-        multiplier_f = stats_f.multiplier
 
-        if args.clip:
-            min_y = stats.one
-            max_y = stats.ninetynine
-            min_y2 = stats_f.one
-            max_y2 = stats_f.ninetynine
-            clipped = " (clipped)"
-        else:
-            min_y = max_y = min_y2 = max_y2 = '*'
-            clipped = ""
+        out = stats.percs
+        out["min_y2"] = stats_f.percs["min_y"]
+        out["max_y2"] = stats_f.percs["max_y"]
+        out["unit_f"] = stats_f.percs["unit"]
+        out["multiplier_f"] = stats_f.percs["multiplier"]
+        out["sitename"] = self.sitename
 
         plot_template = NTPViz.Common + """\
 set title "%(sitename)s: Local Clock Time/Frequency Offsets%(clipped)s"
@@ -329,7 +330,7 @@ set style line 2 lc rgb '#dd181f' lt 1 lw 1 pt 5 ps 0   # --- red
 plot \
  "-" using 1:($2*%(multiplier)s) title "clock offset %(unit)s" with linespoints ls 1, \
  "-" using 1:($3*%(multiplier_f)s) title "frequency offset %(unit_f)s" with linespoints ls 2 axis x1y2
-""" % locals()
+""" % out
 
         exp = """\
 <p>The time and frequency offsets between the ntpd calculated time
@@ -417,7 +418,7 @@ component of frequency drift.</p>
 
         plot_template = NTPViz.Common + """\
 set title "%(sitename)s: Local GPS
-set ytics format "%%1.3f tdop" nomirror textcolor rgb '#0060ad'
+set ytics format "%%1.1f tdop" nomirror textcolor rgb '#0060ad'
 set y2tics format "%%2.0f nSat"  nomirror textcolor rgb '#dd181f'
 set style line 1 lc rgb '#0060ad' lt 1 lw 1 pt 7 ps 0   # --- blue
 set style line 2 lc rgb '#dd181f' lt 1 lw 1 pt 5 ps 0   # --- red
@@ -426,8 +427,8 @@ plot \\
 
         for key in gpslist:
             plot_template += """\
-'-' using 1:3 title '%(key)s tdop' with line, \\
-'-' using 1:4 title '%(key)s nSat' with line axis x1y2, \\
+'-' using 1:3 title '%(key)s tdop' with line ls 1, \\
+'-' using 1:4 title '%(key)s nSat' with line ls 2 axis x1y2, \\
 """ % locals()
 
         # strip the trailing ", \\n"
@@ -448,27 +449,17 @@ gpsd log file is created by the gps-log.py program.</p>
         if not len( self.loopstats):
             sys.stderr.write("ntpviz: WARNING: no loopstats to graph\n")
             return ''
-        sitename = self.sitename
+
         # grab and sort the values, no need for the timestamp, etc.
 
         # compute freqency offset
         values = [float(line.split()[2]) for line in self.loopstats]
         stats = VizStats( values, "Local Clock Frequency Offset", freq=1, )
-        unit = stats.unit
-        multiplier = stats.multiplier
 
-        ninetynine  = stats.ninetynine
-        ninetyfive  = stats.ninetyfive
-        five        = stats.five
-        one         = stats.one
-
-        if args.clip:
-            min_y = stats.one
-            max_y = stats.ninetynine
-            clipped = " (clipped)"
-        else:
-            min_y = max_y = '*'
-            clipped = ""
+        # build the output dictionary, because Python can not format
+        # complex objects.
+        out = stats.percs
+        out["sitename"] = self.sitename
 
         plot_template = NTPViz.Common + """\
 set title "%(sitename)s: Local Clock Frequency Offset%(clipped)s"
@@ -479,11 +470,11 @@ set style line 1 lc rgb '#0060ad' lt 1 lw 1 pt 7 ps 0   # --- blue
 set style line 2 lc rgb '#dd181f' lt 1 lw 1 pt 5 ps 0   # --- red
 plot \
  "-" using 1:($3 * %(multiplier)s) title "local clock error" with linespoints ls 2, \
- %(ninetynine)s title "99th percentile", \
- %(ninetyfive)s title "95th percentile", \
- %(five)s title "5th percentile", \
- %(one)s title "1st percentile"
-""" % locals()
+ %(p99)s title "99th percentile", \
+ %(p95)s title "95th percentile", \
+ %(p5)s title "5th percentile", \
+ %(p1)s title "1st percentile"
+""" % out
 
         exp = """\
 <p>This shows the frequency offset of the local clock (aka drift).  The
@@ -508,25 +499,18 @@ line at 0ppm.  Expected values of 99%-1% percentiles: 0.4ppm</p>
             sys.stderr.write("ntpviz: WARNING: no loopstats to graph\n")
             return ''
 
-        sitename   = self.sitename
         # grab and process the values
         values = [float(line.split()[fld - 1]) for line in self.loopstats]
         stats = VizStats( values, title, freq=freq )
-        unit = stats.unit
-        multiplier = stats.multiplier
 
-        ninetynine  = stats.ninetynine
-        ninetyfive  = stats.ninetyfive
-        five        = stats.five
-        one         = stats.one
+        # build the output dictionary, because Python can not format
+        # complex objects.
+        out = stats.percs
+        out["sitename"] = self.sitename
+        out["fld"]      = fld
+        out["legend"]   = legend
 
-        min_y = '0'
-        if args.clip:
-            max_y = stats.ninetynine
-            clipped = " (clipped)"
-        else:
-            max_y = '*'
-            clipped = ""
+        out["min_y"] = '0'
 
         if freq:
             exp = """\
@@ -558,11 +542,11 @@ set style line 1 lc rgb '#0060ad' lt 1 lw 1 pt 7 ps 0   # --- blue
 set style line 2 lc rgb '#dd181f' lt 1 lw 1 pt 5 ps 0   # --- red
 plot \
  "-" using 1:($%(fld)d*%(multiplier)s) title "%(legend)s" with linespoints ls 1, \
- %(ninetynine)s title "99th percentile", \
- %(ninetyfive)s title "95th percentile", \
- %(five)s title "5th percentile", \
- %(one)s title "1st percentile"
-""" % locals()
+ %(p99)s title "99th percentile", \
+ %(p95)s title "95th percentile", \
+ %(p5)s title "5th percentile", \
+ %(p1)s title "1st percentile"
+""" % out
 
         ret = {'html' : stats.stats_html + exp, 'stats' : [stats],
                'title' : title }
@@ -580,7 +564,7 @@ plot \
 
     def peerstats_gnuplot(self, peerlist, fld, title, type):
         "Plot a specified field from peerstats."
-        sitename = self.sitename
+
         peerdict = self.peersplit()
         if not peerlist:
             peerlist = list(peerdict.keys())
@@ -609,8 +593,6 @@ plot \
         # remove trailing "e\n"
         plot_data = plot_data[:-2]
 
-        unit = "μs"
-        multiplier = 1e6
         rtt = 0
         percentages = ""
         stats = []
@@ -621,17 +603,9 @@ plot \
             values = [float(line.split()[fld - 1]) for line in peerdict[ip]]
 
             stats = VizStats( values, title)
-            unit        = stats.unit
-            multiplier  = stats.multiplier
-
-            ninetynine  = stats.ninetynine
-            ninetyfive  = stats.ninetyfive
-            fifty       = stats.fifty
-            five        = stats.five
-            one         = stats.one
 
-            percentages = " %(fifty)s title '50th percentile', " \
-                           % locals()
+            percentages = " %(p50)s title '50th percentile', " \
+                           % stats.percs
 
             exp = stats.stats_html
 
@@ -651,7 +625,7 @@ at 0s. Typical 90%% ranges may be: local serial GPS 200 ms; local PPS
 20µs</p>
 
 <p>Clock Offset is field 5 in the peerstats log file.</p>
-""" %  locals()
+""" % stats.percs
                 else:
                     title = "Peer Offset " + str(peerlist[0])
                     exp += """\
@@ -704,8 +678,6 @@ at 0s.</p>
             values = [float(line.split()[fld - 1]) for line in self.peerstats]
 
             stats = VizStats( values, title )
-            unit        = stats.unit
-            multiplier  = stats.multiplier
 
             exp = stats.stats_html
             if "offset" == type:
@@ -716,7 +688,7 @@ at 0s.</p>
 a single clock or all clocks together.</p>
 
 <p>Clock Offset is field 5 in the peerstats log file.</p>
-""" % locals()
+""" % stats.percs
             else:
                 title = "Peer Jitters"
                 exp += """\
@@ -730,19 +702,14 @@ at 0s.</p>
 <p>RMS Jitter is field 8 in the peerstats log file.</p>
 """
 
+        out = stats.percs
+        out['sitename'] = self.sitename
+
         if 6 >= len(peerlist):
-            set_key = "set key top right box"
+            out['set_key'] = "set key top right box"
         else:
             # too many keys to show
-            set_key = "set key off"
-
-        if args.clip:
-            min_y = stats.one
-            max_y = stats.ninetynine
-            clipped = " (clipped)"
-        else:
-            min_y = max_y = '*'
-            clipped = ""
+            out['set_key'] = "set key off"
 
         plot_template = NTPViz.Common + """\
 set title "%(sitename)s: %(title)s%(clipped)s"
@@ -751,18 +718,20 @@ set ytics format "%%1.1f %(unit)s" nomirror
 set yrange [%(min_y)s:%(max_y)s]
 %(set_key)s
 plot \
-""" % locals()
+""" % out
+
         plot_template += percentages
+        out['fld'] = fld
         for key in peerlist:
-            label = self.ip_label(key)
+            out['label'] = self.ip_label(key)
             plot_template += "'-' using 1:($%(fld)s*%(multiplier)s) title '%(label)s' with line, \\\n" \
-                 % locals()
+                 % out
 
         if 1 == rtt:
             plot_template += """\
 '-' using 1:(($4+$5/2)*%(multiplier)s) title 'offset+rtt/2' with line, \\
 '-' using 1:(($4-$5/2)*%(multiplier)s) title 'offset-rtt/2' with line
-""" % locals()
+""" % stats.percs
             plot_template += plot_data + "\ne\n" + plot_data + "\ne\n"
         else:
             # strip the trailing ", \n"
@@ -783,29 +752,26 @@ plot \
         if not len( self.loopstats):
             sys.stderr.write("ntpviz: WARNING: no loopstats to graph\n")
             return ''
-        sitename = self.sitename
 
-        # TODO normalize to 0 to 100
+        # TODO normalize to 0 to 100?
 
         # grab and sort the values, no need for the timestamp, etc.
         values = [float(line.split()[1]) for line in self.loopstats]
         stats = VizStats( values, 'Local Clock Offset' )
-        unit        = stats.unit
-        multiplier  = stats.multiplier
-
-        ninetynine  = stats.ninetynine
-        ninetyfive  = stats.ninetyfive
-        fifty       = stats.fifty
-        five        = stats.five
-        one         = stats.one
+        out = stats.percs
+        out['sitename'] = self.sitename
+        # flip the axis
+        out['min_x']    = out['min_y']
+        out['max_x']    = out['max_y']
 
         # fixme, should piggy back on unit
         rnd1 = 7        # round to 100 ns boxes
-        boxwidth = 1e-7
-        if 1e-6 > stats.percs[99] and -1e-6 < stats.percs[1]:
+        out['boxwidth'] = 1e-7
+
+        if 1e-6 > stats.percs["p99"] and -1e-6 < stats.percs["p1"]:
             # go to nanosec
             rnd1 = 9        # round to 1 ns boxes
-            boxwidth = 1e-9
+            out['boxwidth'] = 1e-9
 
         cnt = collections.Counter()
         for value in values:
@@ -813,29 +779,25 @@ plot \
             # for a +/- 50 microSec range that is 1,000 buckets to plot
             cnt[ round( float(value), rnd1)] += 1
 
-        # plus/minus of one sigma range
-        m1sigma = stats.mu - stats.pstd
-        p1sigma = stats.mu + stats.pstd
+        sigma = True
+        if args.clip:
+            if stats.percs['p1sigma'] > stats.percs['p99'] or \
+               stats.percs['m1sigma'] < stats.percs['p1']:
+                # sigma out of range, do not plot
+                sigma = ''
 
-        sigma = """\
+        out['sigma'] = ''
+        if sigma:
+            # plus/minus of one sigma range
+            out['sigma'] = """\
 set style arrow 1 nohead
 set arrow from %(m1sigma)s,graph 0 to %(m1sigma)s,graph 0.90 as 1
 set style arrow 2 nohead
 set arrow from %(p1sigma)s,graph 0 to %(p1sigma)s,graph 0.90 as 2
 set label 1 "-1σ" at %(m1sigma)s, graph 0.96  left front offset -1,-1
 set label 2 "+1σ" at %(p1sigma)s, graph 0.96  left front offset -1,-1
-""" % locals()
+""" % out
 
-        if args.clip:
-            min_x = stats.one
-            max_x = stats.ninetynine
-            clipped = " (clipped)"
-            if p1sigma > ninetynine or m1sigma < one:
-                # sigma out of range, do not plot
-                sigma = ''
-        else:
-            min_x = max_x = '*'
-            clipped = ""
 
         plot_template = '''\
 set terminal png size 900,600
@@ -846,25 +808,26 @@ set title "%(sitename)s: Local Clock Time Offset Histogram%(clipped)s"
 set xtics format "%%1.1f %(unit)s" nomirror
 set xrange [%(min_x)s:%(max_x)s]
 set style arrow 3 nohead
-set arrow from %(ninetynine)s,graph 0 to %(ninetynine)s,graph 0.30 as 3
+set arrow from %(p99)s,graph 0 to %(p99)s,graph 0.30 as 3
 set style arrow 4 nohead
-set arrow from %(ninetyfive)s,graph 0 to %(ninetyfive)s,graph 0.45 as 4
+set arrow from %(p95)s,graph 0 to %(p95)s,graph 0.45 as 4
 set style arrow 5 nohead
-set arrow from %(five)s,graph 0 to %(five)s,graph 0.45 as 5
+set arrow from %(p5)s,graph 0 to %(p5)s,graph 0.45 as 5
 set style arrow 6 nohead
-set arrow from %(one)s,graph 0 to %(one)s,graph 0.30 as 6
+set arrow from %(p1)s,graph 0 to %(p1)s,graph 0.30 as 6
 set key off
 set lmargin 12
 set rmargin 12
 set style fill solid 0.5
-set label 3 "99%%" at %(ninetynine)s, graph 0.35  left front offset -1,-1
-set label 4 "95%%" at %(ninetyfive)s, graph 0.50  left front offset -1,-1
-set label 5 "1%%" at %(one)s, graph 0.35  left front offset -1,-1
-set label 6 "5%%" at %(five)s, graph 0.50  left front offset -1,-1
+set label 3 "99%%" at %(p99)s, graph 0.35  left front offset -1,-1
+set label 4 "95%%" at %(p95)s, graph 0.50  left front offset -1,-1
+set label 5 "1%%" at %(p1)s, graph 0.35  left front offset -1,-1
+set label 6 "5%%" at %(p5)s, graph 0.50  left front offset -1,-1
 %(sigma)s
 plot \
  "-" using ($1 * %(multiplier)s):2 title "histogram" with boxes
-''' % locals()
+''' % out
+
         vals = list(cnt.keys())
         vals.sort()
         histogram_data = ["%s %s\n" % (val, cnt[val]) for val in vals]
@@ -873,8 +836,9 @@ plot \
 <p>This shows the clock offsets of the local clock as a histogram.</p>
 
 <p>The Local Clock Offset is field 3 from the loopstats log file.</p>
-""" % locals()
-        ret = {'html' : stats.stats_html + exp, 'stats' : [stats]}
+"""
+        # don't return stats, it's just a dupe
+        ret = {'html' : stats.stats_html + exp, 'stats' : []}
         ret['title'] = "Local Clock Time Offset Histogram"
         ret['plot'] = plot_template + "".join(histogram_data) + "e\n"
         return ret


=====================================
pylib/statfiles.py
=====================================
--- a/pylib/statfiles.py
+++ b/pylib/statfiles.py
@@ -153,9 +153,9 @@ class NTPStats:
         length = len(values)
         for perc in percents:
             if perc == 100:
-                ret[100] = values[length - 1]
+                ret["p100"] = values[length - 1]
             else:
-                ret[perc] = values[int(length * (perc/100))]
+                ret[ "p" + str(perc)] = values[int(length * (perc/100))]
         return ret
 
     def peersplit(self):



View it on GitLab: https://gitlab.com/NTPsec/ntpsec/commit/d44853f5ecdf9c07313503fcd34dfbba96f5fcb5
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.ntpsec.org/pipermail/vc/attachments/20161014/59b3ed54/attachment.html>


More information about the vc mailing list