diff options
Diffstat (limited to 'graph.go')
-rw-r--r-- | graph.go | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/graph.go b/graph.go new file mode 100644 index 0000000..955abbd --- /dev/null +++ b/graph.go @@ -0,0 +1,155 @@ +package bookpipeline + +import ( + "fmt" + "io" + "path/filepath" + "sort" + "strconv" + "strings" + + "github.com/wcharczuk/go-chart" + "github.com/wcharczuk/go-chart/drawing" +) + +const maxticks = 40 +const goodCutoff = 70 +const mediumCutoff = 65 +const badCutoff = 60 + +type Conf struct { + Path, Code string + Conf float64 +} + +type GraphConf struct { + Pgnum, Conf float64 +} + +func createLine(xvalues []float64, y float64, c drawing.Color) chart.ContinuousSeries { + var yvalues []float64 + for range xvalues { + yvalues = append(yvalues, y) + } + return chart.ContinuousSeries{ + XValues: xvalues, + YValues: yvalues, + Style: chart.Style{ + StrokeColor: c, + }, + } +} + +func Graph(confs map[string]*Conf, bookname string, w io.Writer) error { + // Organise confs to sort them by page + var graphconf []GraphConf + for _, conf := range confs { + name := filepath.Base(conf.Path) + var numend int + numend = strings.Index(name, "_") + if numend == -1 { + numend = strings.Index(name, ".") + } + pgnum, err := strconv.ParseFloat(name[0:numend], 64) + if err != nil { + continue + } + var c GraphConf + c.Pgnum = pgnum + c.Conf = conf.Conf + graphconf = append(graphconf, c) + } + sort.Slice(graphconf, func(i, j int) bool { return graphconf[i].Pgnum < graphconf[j].Pgnum }) + + // Create main xvalues and yvalues, annotations and ticks + var xvalues, yvalues []float64 + var annotations []chart.Value2 + var ticks []chart.Tick + tickevery := len(graphconf) / maxticks + if tickevery < 1 { + tickevery = 1 + } + for i, c := range graphconf { + xvalues = append(xvalues, c.Pgnum) + yvalues = append(yvalues, c.Conf) + if c.Conf < goodCutoff { + annotations = append(annotations, chart.Value2{Label: fmt.Sprintf("%.0f", c.Pgnum), XValue: c.Pgnum, YValue: c.Conf}) + } + if i%tickevery == 0 { + ticks = append(ticks, chart.Tick{c.Pgnum, fmt.Sprintf("%.0f", c.Pgnum)}) + } + } + // make last tick the final page + final := graphconf[len(graphconf)-1] + ticks[len(ticks)-1] = chart.Tick{final.Pgnum, fmt.Sprintf("%.0f", final.Pgnum)} + mainSeries := chart.ContinuousSeries{ + XValues: xvalues, + YValues: yvalues, + } + + // Create lines + goodCutoffSeries := createLine(xvalues, goodCutoff, chart.ColorAlternateGreen) + mediumCutoffSeries := createLine(xvalues, mediumCutoff, chart.ColorOrange) + badCutoffSeries := createLine(xvalues, badCutoff, chart.ColorRed) + + // Create lines marking top and bottom 10% confidence + sort.Slice(graphconf, func(i, j int) bool { return graphconf[i].Conf < graphconf[j].Conf }) + lowconf := graphconf[int(len(graphconf)/10)].Conf + highconf := graphconf[int((len(graphconf)/10)*9)].Conf + yvalues = []float64{} + for range graphconf { + yvalues = append(yvalues, lowconf) + } + minSeries := &chart.ContinuousSeries{ + Style: chart.Style{ + StrokeColor: chart.ColorAlternateGray, + StrokeDashArray: []float64{5.0, 5.0}, + }, + XValues: xvalues, + YValues: yvalues, + } + yvalues = []float64{} + for _ = range graphconf { + yvalues = append(yvalues, highconf) + } + maxSeries := &chart.ContinuousSeries{ + Style: chart.Style{ + StrokeColor: chart.ColorAlternateGray, + StrokeDashArray: []float64{5.0, 5.0}, + }, + XValues: xvalues, + YValues: yvalues, + } + + graph := chart.Chart{ + Title: bookname, + Width: 3840, + Height: 2160, + XAxis: chart.XAxis{ + Name: "Page number", + Range: &chart.ContinuousRange{ + Min: 0.0, + }, + Ticks: ticks, + }, + YAxis: chart.YAxis{ + Name: "Confidence", + Range: &chart.ContinuousRange{ + Min: 0.0, + Max: 100.0, + }, + }, + Series: []chart.Series{ + mainSeries, + minSeries, + maxSeries, + goodCutoffSeries, + mediumCutoffSeries, + badCutoffSeries, + chart.AnnotationSeries{ + Annotations: annotations, + }, + }, + } + return graph.Render(chart.PNG, w) +} |