package main import ( "bytes" "fmt" "io/ioutil" "math" ) const ( Color1 = "#F44336" // Red Color2 = "#FF9800" // Orange Color3 = "#FFEB3B" // Yellow Color4 = "#00BCD4" // Cyan Color5 = "#4CAF50" // Green Color6 = "#009688" // Teal Color7 = "#2196F3" // Blue Color8 = "#9C27B0" // Purple ) type Graph struct { XLabel string YLabel string YLabelDY string X0 float64 Y0 float64 X1 float64 Y1 float64 DX float64 DY float64 XMin float64 YMin float64 XMax float64 YMax float64 YLog bool XMarks []Mark YMarks []Mark Lines []Line Labels []Label } type Mark struct { Pos float64 Text string } type Line struct { Label string LabelX float64 LabelY float64 Color string Width float64 Data [][2]float64 } type Label struct { X float64 Y float64 XAlign string YAlign string Text string } func (g *Graph) ToX(v float64) float64 { return g.X0 + (g.X1-g.X0)*((v-g.XMin)/(g.XMax-g.XMin)) } func (g *Graph) ToY(v float64) float64 { if g.YLog { return g.Y0 + (g.Y1-g.Y0)*((math.Log(v)-math.Log(g.YMin))/(math.Log(g.YMax)-math.Log(g.YMin))) } return g.Y0 + (g.Y1-g.Y0)*((v-g.YMin)/(g.YMax-g.YMin)) } func (g *Graph) SVG() []byte { var buf bytes.Buffer fmt.Fprintf(&buf, "\n", int(g.DX), int(g.DY), int(g.DX), int(g.DY)) fmt.Fprintf(&buf, "\n\n", g.X0, g.Y1, g.X1-g.X0, g.Y0-g.Y1) // Axis lines, marks, and mark labels. fmt.Fprintf(&buf, "%s\n", x, g.Y0+d, m.Text) } } for _, m := range g.YMarks { y := g.ToY(m.Pos) d := 5.0 if m.Text == "" { d = 3 } fmt.Fprintf(&buf, "M %.2f %.2f L %.2f %.2f ", g.X0, y, g.X0-d, y) if m.Text != "" { fmt.Fprintf(&text, "%s\n", g.X0-d, y, m.Text) } } fmt.Fprintf(&buf, "\" fill=\"transparent\" stroke=\"black\"/>\n") buf.Write(text.Bytes()) // Axis labels. if g.XLabel != "" { fmt.Fprintf(&buf, "%s\n", (g.X1+g.X0)/2, g.Y0, g.XLabel) } if g.YLabel != "" { dy := "-2em" if g.YLabelDY != "" { dy = g.YLabelDY } fmt.Fprintf(&buf, "%s\n", g.X0, (g.Y1+g.Y0)/2, dy, g.YLabel) } // Lines fmt.Fprintf(&buf, "\n") for _, line := range g.Lines { fmt.Fprintf(&buf, "\n", line.Color, line.Width) } fmt.Fprintf(&buf, "\n") for _, line := range g.Lines { if line.Label == "" { continue } fmt.Fprintf(&buf, "\n", line.Color, line.Width) fmt.Fprintf(&buf, "%s\n", x+Inch/2+Inch/16, y, line.Label) } // Labels for _, label := range g.Labels { fmt.Fprintf(&buf, "%s\n", label.Text) } fmt.Fprintf(&buf, "\n") return buf.Bytes() } func (g *Graph) AutoXMarks() { g.XMarks = autoMarks(g.XMin, g.XMax) } func (g *Graph) AutoYMarks() { g.YMarks = autoMarks(g.YMin, g.YMax) } func autoMarks(min, max float64) []Mark { scale := 1.0 for int(max/scale)-int(min/scale) > 10 { scale *= 10 } for int(max/scale)-int(min/scale) < 1 { scale /= 10 } var marks []Mark for i := int(min / scale); float64(i)*scale <= max; i++ { marks = append(marks, Mark{Text: fmt.Sprint(float64(i) * scale), Pos: float64(i) * scale}) if p := (float64(i) + 0.5) * scale; p <= max && scale > 1 { marks = append(marks, Mark{Pos: p}) } } return marks } const Inch = 72.0 func main() { g := &Graph{ XLabel: "pattern size n", X0: 0.5 * Inch, X1: (0.5 + 2.5) * Inch, Y0: (0.1 + 1.5) * Inch, Y1: 0.1 * Inch, DX: 3.25 * Inch, DY: 2.1 * Inch, XMin: 0, YMin: 0, YMax: 7.25, Lines: []Line{ Line{}, }, Labels: []Label{ { Y: 6, XAlign: "right", YAlign: "center", }, }, } g.YLabel = "time (minutes)" g.Lines[0] = Line{ Color: "#c00", Width: 2.0, Data: [][2]float64{ {0, 4.8911e-05}, {1, 2.90413e-05}, {2, 3.68292e-05}, {3, 7.14572e-05}, {4, 0.000280084}, {5, 0.00265224}, {6, 0.0399743}, {7, 0.588281}, {8, 7.18658}, }, } g.XMax = 8 g.Labels[0].X = 7 g.Labels[0].Text = "ls" g.AutoXMarks() g.AutoYMarks() ioutil.WriteFile("glob1.svg", g.SVG(), 0666) g.YLabel = "time (ms)" g.Lines[0] = Line{ Color: "#00f", Width: 2.0, Data: [][2]float64{ {0, 1.43909}, {1, 1.47637}, {2, 1.48331}, {3, 1.49517}, {4, 1.51284}, {5, 1.52364}, {6, 1.53863}, {7, 1.55547}, {8, 1.57037}, {9, 1.5826}, {10, 1.60071}, {11, 1.6203}, {12, 1.6312}, {13, 1.64203}, {14, 1.66992}, {15, 1.68861}, {16, 1.69519}, {17, 1.7203}, {18, 1.7295}, {19, 1.7554}, {20, 1.7758}, {21, 1.79486}, {22, 1.83495}, {23, 1.85332}, {24, 1.86697}, {25, 1.88521}, {26, 1.89894}, {27, 1.92536}, {28, 1.94536}, {29, 1.99545}, {30, 2.0099}, {31, 2.02431}, {32, 2.05334}, {33, 2.07537}, {34, 2.10333}, {35, 2.13579}, {36, 2.15802}, {37, 2.17934}, {38, 2.20948}, {39, 2.23249}, {40, 2.26358}, {41, 2.28074}, {42, 2.32731}, {43, 2.35436}, {44, 2.39507}, {45, 2.4247}, {46, 2.45651}, {47, 2.47193}, {48, 2.51619}, {49, 2.53839}, {50, 2.58134}, {51, 2.62019}, {52, 2.63301}, {53, 2.6786}, {54, 2.7337}, {55, 2.74277}, {56, 2.77387}, {57, 2.81395}, {58, 2.84587}, {59, 2.91166}, {60, 2.9355}, {61, 2.97022}, {62, 3.00078}, {63, 3.0401}, {64, 3.06739}, {65, 3.13164}, {66, 3.15914}, {67, 3.2148}, {68, 3.26457}, {69, 3.2891}, {70, 3.35357}, {71, 3.38114}, {72, 3.41628}, {73, 3.4704}, {74, 3.51955}, {75, 3.5626}, {76, 3.62813}, {77, 3.66333}, {78, 3.70191}, {79, 3.78555}, {80, 3.82436}, {81, 3.88056}, {82, 3.93706}, {83, 3.94907}, {84, 4.05134}, {85, 4.07482}, {86, 4.1267}, {87, 4.18599}, {88, 4.23299}, {89, 4.31395}, {90, 4.33191}, {91, 4.39525}, {92, 4.42133}, {93, 4.48976}, {94, 4.5401}, {95, 4.58719}, {96, 4.64591}, {97, 4.71859}, {98, 4.76698}, {99, 4.82806}, }, } g.XMax = 100 g.Labels[0].X = 87.5 g.Labels[0].Text = "ls | grep" g.AutoXMarks() g.AutoYMarks() ioutil.WriteFile("glob2.svg", g.SVG(), 0666) const LabelY1 = 4000.0 const LabelYScale = 2.0 g = &Graph{ XLabel: "pattern size n", YLabel: "time", YLabelDY: "-4em", X0: 0.75 * Inch, X1: (0.75 + 5.25) * Inch, Y0: (0.1 + 3.5) * Inch, Y1: 0.1 * Inch, DX: 7.5 * Inch, DY: 4.1 * Inch, XMin: 0, XMax: 20, YMin: 0.00010, YMax: 25000.0, YLog: true, YMarks: []Mark{ {20000, ""}, {10000, "10000 s"}, {9000, ""}, {8000, ""}, {7000, ""}, {6000, ""}, {5000, ""}, {4000, ""}, {3000, ""}, {2000, ""}, {1000, "1000 s"}, {900, ""}, {800, ""}, {700, ""}, {600, ""}, {500, ""}, {400, ""}, {300, ""}, {200, ""}, {100, "100 s"}, {90, ""}, {80, ""}, {70, ""}, {60, ""}, {50, ""}, {40, ""}, {30, ""}, {20, ""}, {10, "10 s"}, {9, ""}, {8, ""}, {7, ""}, {6, ""}, {5, ""}, {4, ""}, {3, ""}, {2, ""}, {1, "1 s"}, {0.9, ""}, {0.8, ""}, {0.7, ""}, {0.6, ""}, {0.5, ""}, {0.4, ""}, {0.3, ""}, {0.2, ""}, {0.1, "100 ms"}, {0.09, ""}, {0.08, ""}, {0.07, ""}, {0.06, ""}, {0.05, ""}, {0.04, ""}, {0.03, ""}, {0.02, ""}, {0.01, "10 ms"}, {0.009, ""}, {0.008, ""}, {0.007, ""}, {0.006, ""}, {0.005, ""}, {0.004, ""}, {0.003, ""}, {0.002, ""}, {0.001, "1 ms"}, {0.0009, ""}, {0.0008, ""}, {0.0007, ""}, {0.0006, ""}, {0.0005, ""}, {0.0004, ""}, {0.0003, ""}, {0.0002, ""}, {0.0001, "100 us"}, }, XMarks: []Mark{ {0, "0"}, {1, ""}, {2, ""}, {3, ""}, {4, ""}, {5, "5"}, {6, ""}, {7, ""}, {8, ""}, {9, ""}, {10, "10"}, {11, ""}, {12, ""}, {13, ""}, {14, ""}, {15, "15"}, {16, ""}, {17, ""}, {18, ""}, {19, ""}, {20, "20"}, }, Lines: []Line{ Line{ Label: "tcsh 6.18.01", Color: Color1, Width: 1.5, Data: [][2]float64{ {0, 0.004448880}, {1, 0.006431193}, {2, 0.005173464}, {3, 0.026750587}, {4, 0.500732081}, {5, 9.015299373}, {6, 142.768890376}, {7, 1952.555767944}, {8, 22940.221333328}, }, }, Line{ Label: "ksh 93u+20120801", LabelY: LabelY1, Color: Color2, Width: 1.5, Data: [][2]float64{ {0, 0.001050163}, {1, 0.000868984}, {2, 0.000975836}, {3, 0.002608253}, {4, 0.045094445}, {5, 0.803450403}, {6, 12.902227738}, {7, 177.752965717}, {8, 2211.436650459}, }, }, Line{ Label: "Plan 9 rc", Color: Color3, LabelY: LabelY1 / LabelYScale, Width: 1.5, Data: [][2]float64{ {0, 0.002205500}, {1, 0.003892799}, {2, 0.003442227}, {3, 0.008466353}, {4, 0.038269247}, {5, 0.516015808}, {6, 7.934463959}, {7, 110.193912116}, {8, 1314.421437116}, }, }, Line{ Label: "zsh 5.0.5", Color: Color4, Width: 1.5, LabelY: LabelY1 / LabelYScale / LabelYScale, Data: [][2]float64{ {0, 0.002088757}, {1, 0.003948585}, {2, 0.003979290}, {3, 0.005602784}, {4, 0.019969921}, {5, 0.323085859}, {6, 5.397274992}, {7, 78.776975755}, {8, 994.699093062}, }, }, Line{ Label: "rc 1.7.1", Color: Color5, Width: 1.5, LabelY: LabelY1 / LabelYScale / LabelYScale / LabelYScale, Data: [][2]float64{ {0, 0.001717890}, {1, 0.001503086}, {2, 0.001356468}, {3, 0.003084504}, {4, 0.019929715}, {5, 0.229489748}, {6, 3.693610576}, {7, 50.476608759}, {8, 601.638436616}, }, }, Line{ Label: "bash 4.3", Color: Color6, Width: 1.5, LabelY: LabelY1 / LabelYScale / LabelYScale / LabelYScale / LabelYScale, Data: [][2]float64{ {0, 0.001744280}, {1, 0.001830546}, {2, 0.002075035}, {3, 0.002840104}, {4, 0.011904460}, {5, 0.138909358}, {6, 2.362099111}, {7, 34.317349065}, {8, 434.075965074}, }, }, Line{ Label: "dash 0.5.7", Color: Color7, Width: 1.5, LabelY: LabelY1 / LabelYScale / LabelYScale / LabelYScale / LabelYScale / LabelYScale, Data: [][2]float64{ {0, 0.000763738}, {1, 0.000554199}, {2, 0.000545408}, {3, 0.000666228}, {4, 0.003953407}, {5, 0.069595180}, {6, 1.092959971}, {7, 15.170743911}, {8, 186.228944198}, }, }, Line{ Label: "csh 20110502", Color: Color8, Width: 1.5, Data: [][2]float64{ {0, 0.021468033}, {1, 0.020593489}, {2, 0.020828153}, {3, 0.028540293}, {4, 0.020789366}, {5, 0.020464942}, {6, 0.020395209}, {7, 0.020762802}, {8, 0.020782494}, {9, 0.020609929}, {10, 0.020973340}, {11, 0.023544593}, {12, 0.032083391}, {13, 0.020648084}, {14, 0.028667412}, {15, 0.020449621}, {16, 0.020676539}, {17, 0.029357040}, {18, 0.020626247}, {19, 0.020780515}, {20, 0.030928707}, }, }, }, } ioutil.WriteFile("glob3.svg", g.SVG(), 0666) g.YMin = 0.00000030 g.YMax = 2000.0 g.YMarks = []Mark{ {2000, ""}, {1000, "1000 s"}, {900, ""}, {800, ""}, {700, ""}, {600, ""}, {500, ""}, {400, ""}, {300, ""}, {200, ""}, {100, "100 s"}, {90, ""}, {80, ""}, {70, ""}, {60, ""}, {50, ""}, {40, ""}, {30, ""}, {20, ""}, {10, "10 s"}, {9, ""}, {8, ""}, {7, ""}, {6, ""}, {5, ""}, {4, ""}, {3, ""}, {2, ""}, {1, "1 s"}, {0.9, ""}, {0.8, ""}, {0.7, ""}, {0.6, ""}, {0.5, ""}, {0.4, ""}, {0.3, ""}, {0.2, ""}, {0.1, "100 ms"}, {0.09, ""}, {0.08, ""}, {0.07, ""}, {0.06, ""}, {0.05, ""}, {0.04, ""}, {0.03, ""}, {0.02, ""}, {0.01, "10 ms"}, {0.009, ""}, {0.008, ""}, {0.007, ""}, {0.006, ""}, {0.005, ""}, {0.004, ""}, {0.003, ""}, {0.002, ""}, {0.001, "1 ms"}, {0.0009, ""}, {0.0008, ""}, {0.0007, ""}, {0.0006, ""}, {0.0005, ""}, {0.0004, ""}, {0.0003, ""}, {0.0002, ""}, {0.0001, "100 us"}, {0.00009, ""}, {0.00008, ""}, {0.00007, ""}, {0.00006, ""}, {0.00005, ""}, {0.00004, ""}, {0.00003, ""}, {0.00002, ""}, {0.00001, "10 us"}, {0.000009, ""}, {0.000008, ""}, {0.000007, ""}, {0.000006, ""}, {0.000005, ""}, {0.000004, ""}, {0.000003, ""}, {0.000002, ""}, {0.000001, "1 us"}, {0.0000009, ""}, {0.0000008, ""}, {0.0000007, ""}, {0.0000006, ""}, {0.0000005, ""}, {0.0000004, ""}, {0.0000003, ""}, } const JavaY = 1824.9 const JavaScale = 2.2 const RustY = 0.00001464445 * 1.48 g.Lines = []Line{ Line{ Label: "Java 8", Color: Color1, Width: 1.5, LabelY: JavaY, Data: [][2]float64{ {0, 0.000065023}, {1, 0.000067364}, {2, 0.000354547}, {3, 0.001225556}, {4, 0.041045420}, {5, 0.522262194}, {6, 11.647746703}, {7, 108.762878663}, {8, 1824.943554702}, }, }, Line{ Label: "Perl 5.18.2", Color: Color2, Width: 1.5, LabelY: JavaY / JavaScale, Data: [][2]float64{ {0, 0.000001979}, {1, 0.000006342}, {2, 0.000030923}, {3, 0.000899100}, {4, 0.021647429}, {5, 0.419456720}, {6, 6.774190903}, {7, 92.677416563}, {8, 1098.529198885}, }, }, Line{ Label: "BSD libc", Color: Color3, Width: 1.5, LabelY: JavaY / JavaScale / JavaScale, Data: [][2]float64{ {0, 0.000001179}, {1, 0.000012861}, {2, 0.000063309}, {3, 0.001470879}, {4, 0.024432457}, {5, 0.414762696}, {6, 6.181407079}, {7, 84.698674273}, {8, 999.673042145}, }, }, Line{ Label: "Python 3.4.3", Color: "#777", Width: 1.5, LabelY: JavaY / JavaScale / JavaScale / JavaScale, Data: [][2]float64{ {0, 0.000012600}, {1, 0.000059500}, {2, 0.000069500}, {3, 0.000541600}, {4, 0.010053500}, {5, 0.140167000}, {6, 1.968111000}, {7, 27.896194000}, {8, 350.594924000}, }, }, Line{ Label: "Tcl 8.6.1", Color: Color4, Width: 1.5, LabelY: JavaY / JavaScale / JavaScale / JavaScale / JavaScale, Data: [][2]float64{ {0, 0.000010}, {1, 0.000014}, {2, 0.000018}, {3, 0.000192}, {4, 0.004870}, {5, 0.103335}, {6, 1.749018}, {7, 24.910158}, {8, 314.548899}, }, }, Line{ Label: "Rust 1.16.0", Color: Color5, Width: 1.5, LabelY: RustY, Data: [][2]float64{ {0, 0.00000366154}, {1, 0.0000137192}, {2, 0.000014104619999999998}, {3, 0.00001453812}, {4, 0.00001362235}, {5, 0.00001377523}, {6, 0.00001383179}, {7, 0.000013869380000000002}, {8, 0.00001422967}, {9, 0.000014255940000000001}, {10, 0.00001406678}, {11, 0.00001431524}, {12, 0.00001376724}, {13, 0.000013525849999999999}, {14, 0.000014945740000000001}, {15, 0.00001364573}, {16, 0.00001391383}, {17, 0.000014074370000000002}, {18, 0.0000141275}, {19, 0.000014247540000000001}, {20, 0.00001464445}, }, }, Line{ Label: "Go 1.8", Color: Color6, Width: 1.5, LabelY: RustY / JavaScale, Data: [][2]float64{ {0, 0.000001152}, {1, 0.000007951}, {2, 0.000006988}, {3, 0.000008592}, {4, 0.000006027}, {5, 0.000007345}, {6, 0.000005920}, {7, 0.000006541}, {8, 0.000008204}, {9, 0.000006657}, {10, 0.000006520}, {11, 0.000006505}, {12, 0.000007225}, {13, 0.000007631}, {14, 0.000006963}, {15, 0.000008565}, {16, 0.000008175}, {17, 0.000007436}, {18, 0.000007050}, {19, 0.000006558}, {20, 0.000007871}, }, }, Line{ Label: "Ruby 1.9.3", Color: Color7, Width: 1.5, LabelY: RustY / JavaScale / JavaScale, Data: [][2]float64{ {0, 0.000001141}, {1, 0.000004713}, {2, 0.000004712}, {3, 0.000004711}, {4, 0.000004733}, {5, 0.000004766}, {6, 0.000004822}, {7, 0.000004841}, {8, 0.000004884}, {9, 0.000004925}, {10, 0.000004904}, {11, 0.000004947}, {12, 0.000005063}, {13, 0.000005085}, {14, 0.000005073}, {15, 0.000005075}, {16, 0.000005115}, {17, 0.000005131}, {18, 0.000005125}, {19, 0.000005164}, {20, 0.000005325}, }, }, Line{ Label: "glibc 2.19", Color: Color8, Width: 1.5, LabelY: RustY / JavaScale / JavaScale / JavaScale, Data: [][2]float64{ {0, 0.000000354}, {1, 0.000002516}, {2, 0.000002521}, {3, 0.000002564}, {4, 0.000002574}, {5, 0.000002606}, {6, 0.000002627}, {7, 0.000002655}, {8, 0.000002679}, {9, 0.000002688}, {10, 0.000002693}, {11, 0.000002746}, {12, 0.000002733}, {13, 0.000002753}, {14, 0.000002797}, {15, 0.000002812}, {16, 0.000002815}, {17, 0.000002831}, {18, 0.000002874}, {19, 0.000002954}, {20, 0.000002885}, }, }, } ioutil.WriteFile("glob4.svg", g.SVG(), 0666) g.YMin = 0.000010 g.YMax = 1000.0 g.YMarks = []Mark{ {1000, "1000 s"}, {900, ""}, {800, ""}, {700, ""}, {600, ""}, {500, ""}, {400, ""}, {300, ""}, {200, ""}, {100, "100 s"}, {90, ""}, {80, ""}, {70, ""}, {60, ""}, {50, ""}, {40, ""}, {30, ""}, {20, ""}, {10, "10 s"}, {9, ""}, {8, ""}, {7, ""}, {6, ""}, {5, ""}, {4, ""}, {3, ""}, {2, ""}, {1, "1 s"}, {0.9, ""}, {0.8, ""}, {0.7, ""}, {0.6, ""}, {0.5, ""}, {0.4, ""}, {0.3, ""}, {0.2, ""}, {0.1, "100 ms"}, {0.09, ""}, {0.08, ""}, {0.07, ""}, {0.06, ""}, {0.05, ""}, {0.04, ""}, {0.03, ""}, {0.02, ""}, {0.01, "10 ms"}, {0.009, ""}, {0.008, ""}, {0.007, ""}, {0.006, ""}, {0.005, ""}, {0.004, ""}, {0.003, ""}, {0.002, ""}, {0.001, "1 ms"}, {0.0009, ""}, {0.0008, ""}, {0.0007, ""}, {0.0006, ""}, {0.0005, ""}, {0.0004, ""}, {0.0003, ""}, {0.0002, ""}, {0.0001, "100 us"}, {0.00009, ""}, {0.00008, ""}, {0.00007, ""}, {0.00006, ""}, {0.00005, ""}, {0.00004, ""}, {0.00003, ""}, {0.00002, ""}, {0.00001, "10 us"}, } const FTPScale = 2.2 g.Lines = []Line{ Line{ Label: "tnftpd (macOS 10.12.4)", Color: Color1, Width: 1.5, Data: [][2]float64{ {0, 0.000726218}, {1, 0.000701438}, {2, 0.000681952}, {3, 0.001169221}, {4, 0.016168262}, {5, 0.279887617}, {6, 5.131108941}, {7, 73.196001685}, {8, 908.508298457}, }, }, Line{ Label: "Pure-FTPd 1.0.36", Color: Color2, Width: 1.5, LabelX: 8, Data: [][2]float64{ {0, 0.000078834}, {1, 0.000087225}, {2, 0.000114032}, {3, 0.001177995}, {4, 0.025545281}, {5, 0.474122740}, {6, 7.175956716}, {7, 17.000464818}, }, }, Line{ Label: "netkit ftpd 0.17", Color: Color3, Width: 1.5, Data: [][2]float64{ {0, 0.039975602}, {1, 0.039978648}, {2, 0.039984980}, {3, 0.040032031}, {4, 0.043969668}, {5, 0.039918785}, {6, 0.040091206}, {7, 0.039898988}, {8, 0.039990887}, {9, 0.040013264}, {10, 0.039972922}, {11, 0.039985223}, {12, 0.039983797}, {13, 0.039964445}, {14, 0.039978644}, {15, 0.039982385}, {16, 0.039990214}, {17, 0.039979283}, {18, 0.039933946}, {19, 0.040045011}, {20, 0.039942230}, }, }, Line{ Label: "Plan 9 ip/ftpd", Color: Color4, Width: 1.5, Data: [][2]float64{ {0, 0.001658756}, {1, 0.001520307}, {2, 0.001400825}, {3, 0.001281890}, {4, 0.001480524}, {5, 0.001331127}, {6, 0.001288928}, {7, 0.001295951}, {8, 0.001275298}, {9, 0.001318116}, {10, 0.001283259}, {11, 0.001276441}, {12, 0.001327904}, {13, 0.001307317}, {14, 0.001277501}, {15, 0.001292110}, {16, 0.001321254}, {17, 0.001333817}, {18, 0.001294728}, {19, 0.001297300}, {20, 0.001286038}, }, }, Line{ Label: "ProFTPD 1.3.5", Color: Color5, Width: 1.5, Data: [][2]float64{ {0, 0.000183692}, {1, 0.000283286}, {2, 0.000277546}, {3, 0.000276985}, {4, 0.000272333}, {5, 0.000267839}, {6, 0.000273773}, {7, 0.000269477}, {8, 0.000266262}, {9, 0.000262938}, {10, 0.000262621}, {11, 0.000272360}, {12, 0.000271251}, {13, 0.000308269}, {14, 0.000271010}, {15, 0.000265288}, {16, 0.000264589}, {17, 0.000275604}, {18, 0.000418055}, {19, 0.000353263}, {20, 0.000341168}, }, }, Line{ Label: "vsftpd 3.0.2", Color: Color6, Width: 1.5, Data: [][2]float64{ {0, 0.000067488}, {1, 0.000061585}, {2, 0.000058776}, {3, 0.000063039}, {4, 0.000053424}, {5, 0.000059835}, {6, 0.000059034}, {7, 0.000055986}, {8, 0.000059693}, {9, 0.000057138}, {10, 0.000056172}, {11, 0.000057901}, {12, 0.000057048}, {13, 0.000057297}, {14, 0.000056441}, {15, 0.000056472}, {16, 0.000055606}, {17, 0.000057615}, {18, 0.000056544}, {19, 0.000056045}, {20, 0.000057401}, }, }, } ioutil.WriteFile("glob5.svg", g.SVG(), 0666) }