blob: 6bcacd93246b777bed6c6175516baf43a31ef7f8 (
plain)
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
|
package plot
import (
"bytes"
"math"
"github.com/sgreben/jp/pkg/draw"
)
// BarChart is a bar chart
type BarChart struct {
draw.Canvas
BarPaddingX int
}
// NewBarChart returns a new bar chart
func NewBarChart(canvas draw.Canvas) *BarChart {
chart := new(BarChart)
chart.Canvas = canvas
chart.BarPaddingX = 1
return chart
}
// Draw implements Chart
func (c *BarChart) Draw(data *DataTable) string {
minY := math.Inf(1)
maxY := math.Inf(-1)
for _, row := range data.Rows {
for _, y := range row {
if y < minY {
minY = y
}
if y > maxY {
maxY = y
}
}
}
paddingX := 4
paddingY := 3
chartHeight := c.Size().Height - paddingY*c.RuneSize().Height
chartWidth := c.Size().Width - 2*paddingX*c.RuneSize().Width
scaleY := float64(chartHeight) / maxY
barPaddedWidth := chartWidth / len(data.Columns)
barWidth := barPaddedWidth - (c.BarPaddingX * c.RuneSize().Width)
if barPaddedWidth < c.RuneSize().Width {
barPaddedWidth = c.RuneSize().Width
}
if barWidth < c.RuneSize().Width {
barWidth = c.RuneSize().Width
}
scaleY = float64(chartHeight) / maxY
for i, group := range data.Columns {
barLeft := paddingX*c.RuneSize().Width + barPaddedWidth*i
barRight := barLeft + barWidth
y := data.Rows[0][i]
barHeight := y * scaleY
barBottom := (paddingY - 1) * c.RuneSize().Height
barTop := barBottom + int(barHeight)
for x := barLeft; x < barRight; x++ {
for y := barBottom; y < barTop; y++ {
c.Set(y, x)
}
}
// Group label
barMiddle := int(math.Floor(float64(barLeft+barRight) / float64(2*c.RuneSize().Width)))
c.GetBuffer().WriteCenter(0, barMiddle, []rune(group))
// Count label
countLabelY := int(math.Ceil(float64(barTop)/float64(c.RuneSize().Height))) * c.RuneSize().Height
if countLabelY <= barBottom && y > 0 {
c.GetBuffer().SetRow(barTop/c.RuneSize().Height, barLeft/c.RuneSize().Width, barRight/c.RuneSize().Width, '▁')
countLabelY = 3 * c.RuneSize().Height
}
c.GetBuffer().WriteCenter(countLabelY/c.RuneSize().Height, barMiddle, Ff(y))
}
b := bytes.NewBuffer(nil)
c.GetBuffer().Render(b)
return b.String()
}
|