1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
|
// Copyright ©2015 The Gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package plotter
import (
"errors"
"gonum.org/v1/plot"
"gonum.org/v1/plot/vg"
"gonum.org/v1/plot/vg/draw"
)
var (
// DefaultFont is the default font for label text.
DefaultFont = plot.DefaultFont
// DefaultFontSize is the default font.
DefaultFontSize = vg.Points(10)
)
// Labels implements the Plotter interface,
// drawing a set of labels at specified points.
type Labels struct {
XYs
// Labels is the set of labels corresponding
// to each point.
Labels []string
// TextStyle is the style of the label text. Each label
// can have a different text style.
TextStyle []draw.TextStyle
// XOffset and YOffset are added directly to the final
// label X and Y location respectively.
XOffset, YOffset vg.Length
}
// NewLabels returns a new Labels using the DefaultFont and
// the DefaultFontSize.
func NewLabels(d XYLabeller) (*Labels, error) {
xys, err := CopyXYs(d)
if err != nil {
return nil, err
}
if d.Len() != len(xys) {
return nil, errors.New("Number of points does not match the number of labels")
}
strs := make([]string, d.Len())
for i := range strs {
strs[i] = d.Label(i)
}
fnt, err := vg.MakeFont(DefaultFont, DefaultFontSize)
if err != nil {
return nil, err
}
styles := make([]draw.TextStyle, d.Len())
for i := range styles {
styles[i] = draw.TextStyle{Font: fnt}
}
return &Labels{
XYs: xys,
Labels: strs,
TextStyle: styles,
}, nil
}
// Plot implements the Plotter interface, drawing labels.
func (l *Labels) Plot(c draw.Canvas, p *plot.Plot) {
trX, trY := p.Transforms(&c)
for i, label := range l.Labels {
pt := vg.Point{X: trX(l.XYs[i].X), Y: trY(l.XYs[i].Y)}
if !c.Contains(pt) {
continue
}
pt.X += l.XOffset
pt.Y += l.YOffset
c.FillText(l.TextStyle[i], pt, label)
}
}
// DataRange returns the minimum and maximum X and Y values
func (l *Labels) DataRange() (xmin, xmax, ymin, ymax float64) {
return XYRange(l)
}
// GlyphBoxes returns a slice of GlyphBoxes,
// one for each of the labels, implementing the
// plot.GlyphBoxer interface.
func (l *Labels) GlyphBoxes(p *plot.Plot) []plot.GlyphBox {
bs := make([]plot.GlyphBox, len(l.Labels))
for i, label := range l.Labels {
bs[i].X = p.X.Norm(l.XYs[i].X)
bs[i].Y = p.Y.Norm(l.XYs[i].Y)
sty := l.TextStyle[i]
bs[i].Rectangle = sty.Rectangle(label)
}
return bs
}
// XYLabeller combines the XYer and Labeller types.
type XYLabeller interface {
XYer
Labeller
}
// XYLabels holds XY data with labels.
// The ith label corresponds to the ith XY.
type XYLabels struct {
XYs
Labels []string
}
// Label returns the label for point index i.
func (l XYLabels) Label(i int) string {
return l.Labels[i]
}
|