Closed sbinet closed 3 years ago
a perhaps better program:
// +build ignore
package main
import (
"image/color"
"log"
"gonum.org/v1/plot"
"gonum.org/v1/plot/plotter"
"gonum.org/v1/plot/vg"
"gonum.org/v1/plot/vg/draw"
"gonum.org/v1/plot/vg/vgimg"
)
func main() {
const dpi = vgimg.DefaultDPI
p, err := plot.New()
if err != nil {
log.Fatalf("could not create plot: %+v", err)
}
p.Title.Text = "Labels"
p.X.Min = -1
p.X.Max = +1
p.Y.Min = -1
p.Y.Max = +1
labels, err := plotter.NewLabels(plotter.XYLabels{
XYs: []plotter.XY{
{X: -0.8 + 0.00, Y: -0.5},
{X: -0.6 + 0.02, Y: -0.5},
{X: -0.4 + 0.04, Y: -0.5},
{X: -0.8 + 0.00, Y: +0.5},
{X: -0.6 + 0.02, Y: +0.5},
{X: -0.4 + 0.04, Y: +0.5},
{X: +0.0 + 0.00, Y: +0},
{X: +0.2 + 0.02, Y: +0},
{X: +0.4 + 0.04, Y: +0},
},
Labels: []string{
"Aq", "Aq", "Aq",
"Aq\nAq", "Aq\nAq", "Aq\nAq",
"Bg\nBg\nBg",
"Bg\nBg\nBg",
"Bg\nBg\nBg",
},
})
if err != nil {
log.Fatalf("could not creates labels plotter: %+v", err)
}
for i := range labels.TextStyle {
sty := &labels.TextStyle[i]
sty.Font.Size = vg.Length(34)
}
labels.TextStyle[0].YAlign = draw.YBottom
labels.TextStyle[1].YAlign = draw.YCenter
labels.TextStyle[2].YAlign = draw.YTop
labels.TextStyle[3].YAlign = draw.YBottom
labels.TextStyle[4].YAlign = draw.YCenter
labels.TextStyle[5].YAlign = draw.YTop
labels.TextStyle[6].YAlign = draw.YBottom
labels.TextStyle[7].YAlign = draw.YCenter
labels.TextStyle[8].YAlign = draw.YTop
m5 := plotter.NewFunction(func(float64) float64 { return -0.5 })
m5.LineStyle.Color = color.RGBA{R: 255, A: 255}
l0 := plotter.NewFunction(func(float64) float64 { return 0 })
l0.LineStyle.Color = color.RGBA{G: 255, A: 255}
p5 := plotter.NewFunction(func(float64) float64 { return +0.5 })
p5.LineStyle.Color = color.RGBA{B: 255, A: 255}
p.Add(labels, m5, l0, p5)
p.Add(plotter.NewGrid())
p.Add(plotter.NewGlyphBoxes())
err = p.Save(15*vg.Centimeter, 15*vg.Centimeter, "labels.png")
if err != nil {
log.Fatalf("could save plot: %+v", err)
}
}
and a possible fix:
diff --git a/vg/draw/text.go b/vg/draw/text.go
index e19ff3e..7f28db6 100644
--- a/vg/draw/text.go
+++ b/vg/draw/text.go
@@ -74,16 +74,17 @@ func (sty TextStyle) Height(txt string) vg.Length {
return vg.Length(0)
}
e := sty.Font.Extents()
- return e.Height*vg.Length(nl-1) + e.Ascent - e.Descent
+ return e.Height * vg.Length(nl)
}
// Rectangle returns a rectangle giving the bounds of
// this text assuming that it is drawn at (0, 0).
func (sty TextStyle) Rectangle(txt string) vg.Rectangle {
+ e := sty.Font.Extents()
w := sty.Width(txt)
h := sty.Height(txt)
xoff := vg.Length(sty.XAlign) * w
- yoff := vg.Length(sty.YAlign) * h
+ yoff := vg.Length(sty.YAlign)*h + e.Descent
// lower left corner
p1 := rotatePoint(sty.Rotation, vg.Point{X: xoff, Y: yoff})
// upper left corner
(there's still this extra head room at the top of the glyphbox. it's the space of the descent of the (possible) line above)
@kortschak what do you think?
it seems our handling of text could be improved.
consider this program:
running it leads to:
we probably still don't handle descent/ascent well, or at least, not in a coherent fashion.
it seems the glyph box of a text symbol is only considering the bounding box of that symbol. I'd argue that's not how the glyph box should be defined: as it's used to determine whether some graphic element is "on the plot", it should take into account the descent of the symbol.
it would also seem we don't have a very consistent definition of the baseline (leading to all that head room in those glyphboxes, especially for the multi-line ones)