Skip to content

Commit

Permalink
hplot: properly handle hstacks with bands and log-y
Browse files Browse the repository at this point in the history
Fixes #749.
  • Loading branch information
sbinet committed Jun 5, 2020
1 parent 4cf183c commit 88911b6
Show file tree
Hide file tree
Showing 6 changed files with 158 additions and 16 deletions.
132 changes: 132 additions & 0 deletions hplot/example_hstack_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"go-hep.org/x/hep/hplot"
"golang.org/x/exp/rand"
"gonum.org/v1/gonum/stat/distuv"
"gonum.org/v1/plot"
"gonum.org/v1/plot/vg"
"gonum.org/v1/plot/vg/draw"
)
Expand Down Expand Up @@ -149,6 +150,7 @@ func ExampleHStack_withBand() {
p := tp.Plot(0, 0)
p.Title.Text = "Histos With or Without Band, Stack: OFF"
p.Title.Padding = 10
p.X.Label.Text = "X"
p.Y.Label.Text = "Y"
hstack := hplot.NewHStack(hs, hplot.WithBand(true))
hstack.Stack = hplot.HStackOff
Expand Down Expand Up @@ -181,6 +183,7 @@ func ExampleHStack_withBand() {
p := tp.Plot(1, 0)
p.Title.Text = "Histos With or Without Band, Stack: ON"
p.Title.Padding = 10
p.X.Label.Text = "X"
p.Y.Label.Text = "Y"
hstack := hplot.NewHStack(hs, hplot.WithBand(true))
hstack.Band.FillColor = color.NRGBA{R: 100, G: 100, B: 100, A: 200}
Expand Down Expand Up @@ -214,6 +217,135 @@ func ExampleHStack_withBand() {
}
}

func ExampleHStack_withLogY() {
h1 := hbook.NewH1D(50, -8, 12)
h2 := hbook.NewH1D(50, -8, 12)
h3 := hbook.NewH1D(50, -8, 12)

const seed = 1234
fillH1(h1, 2000, -2, 1, seed)
fillH1(h2, 2000, +3, 3, seed)
fillH1(h3, 2000, +4, 1, seed)

colors := []color.Color{
color.NRGBA{122, 195, 106, 150},
color.NRGBA{90, 155, 212, 150},
color.NRGBA{250, 167, 91, 150},
}
logy := hplot.WithLogY(true)

hh1 := hplot.NewH1D(h1, hplot.WithBand(true), logy)
hh1.FillColor = colors[0]
hh1.LineStyle.Color = color.Black
hh1.Band.FillColor = color.NRGBA{G: 210, A: 200}

hh2 := hplot.NewH1D(h2, hplot.WithBand(false), logy)
hh2.FillColor = colors[1]
hh2.LineStyle.Width = 0

hh3 := hplot.NewH1D(h3, hplot.WithBand(true), logy)
hh3.FillColor = colors[2]
hh3.LineStyle.Color = color.Black
hh3.Band.FillColor = color.NRGBA{R: 220, A: 200}

hs := []*hplot.H1D{hh1, hh2, hh3}

hh4 := hplot.NewH1D(h1, logy)
hh4.FillColor = colors[0]
hh4.LineStyle.Color = color.Black

hh5 := hplot.NewH1D(h2, logy)
hh5.FillColor = colors[1]
hh5.LineStyle.Width = 0

hh6 := hplot.NewH1D(h3, logy)
hh6.FillColor = colors[2]
hh6.LineStyle.Color = color.Black

hsHistoNoBand := []*hplot.H1D{hh4, hh5, hh6}

tp := hplot.NewTiledPlot(draw.Tiles{Cols: 2, Rows: 2})
tp.Align = true

{
p := tp.Plot(0, 0)
p.Title.Text = "Histos With or Without Band, Stack: OFF"
p.Title.Padding = 10
p.Y.Scale = plot.LogScale{}
p.Y.Tick.Marker = plot.LogTicks{}
p.X.Label.Text = "X"
p.Y.Label.Text = "Y"
hstack := hplot.NewHStack(hs, hplot.WithBand(true), logy)
hstack.Stack = hplot.HStackOff
p.Add(hstack, hplot.NewGrid())
p.Legend.Add("h1", hs[0])
p.Legend.Add("h2", hs[1])
p.Legend.Add("h3", hs[2])
p.Legend.Top = true
p.Legend.Left = true
}

{
p := tp.Plot(0, 1)
p.Title.Text = "Histos Without Band, Stack: OFF"
p.Title.Padding = 10
p.Y.Scale = plot.LogScale{}
p.Y.Tick.Marker = plot.LogTicks{}
p.X.Label.Text = "X"
p.Y.Label.Text = "Y"
hstack := hplot.NewHStack(hsHistoNoBand, hplot.WithBand(true), logy)
hstack.Stack = hplot.HStackOff
hstack.Band.FillColor = color.NRGBA{R: 100, G: 100, B: 100, A: 200}
p.Add(hstack, hplot.NewGrid())
p.Legend.Add("h1", hs[0])
p.Legend.Add("h2", hs[1])
p.Legend.Add("h3", hs[2])
p.Legend.Top = true
p.Legend.Left = true
}

{
p := tp.Plot(1, 0)
p.Title.Text = "Histos With or Without Band, Stack: ON"
p.Title.Padding = 10
p.Y.Scale = plot.LogScale{}
p.Y.Tick.Marker = plot.LogTicks{}
p.X.Label.Text = "X"
p.Y.Label.Text = "Y"
hstack := hplot.NewHStack(hs, hplot.WithBand(true), logy)
hstack.Band.FillColor = color.NRGBA{R: 100, G: 100, B: 100, A: 200}
p.Add(hstack, hplot.NewGrid())
p.Legend.Add("h1", hs[0])
p.Legend.Add("h2", hs[1])
p.Legend.Add("h3", hs[2])
p.Legend.Top = true
p.Legend.Left = true
}

{
p := tp.Plot(1, 1)
p.Title.Text = "Histos Without Band, Stack: ON"
p.Title.Padding = 10
p.Y.Scale = plot.LogScale{}
p.Y.Tick.Marker = plot.LogTicks{}
p.X.Label.Text = "X"
p.Y.Label.Text = "Y"
hstack := hplot.NewHStack(hsHistoNoBand, hplot.WithBand(true), logy)
hstack.Band.FillColor = color.NRGBA{R: 100, G: 100, B: 100, A: 200}
p.Add(hstack, hplot.NewGrid())
p.Legend.Add("h1", hs[0])
p.Legend.Add("h2", hs[1])
p.Legend.Add("h3", hs[2])
p.Legend.Top = true
p.Legend.Left = true
}

err := tp.Save(25*vg.Centimeter, 15*vg.Centimeter, "testdata/hstack_logy.png")
if err != nil {
log.Fatalf("error: %+v", err)
}
}

func fillH1(h *hbook.H1D, n int, mu, sigma float64, seed uint64) {
dist := distuv.Normal{
Mu: mu,
Expand Down
35 changes: 21 additions & 14 deletions hplot/h1d.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,25 +171,32 @@ func (h1 *H1D) withBand() error {

bins := h1.Hist.Binning.Bins
var (
top = make(plotter.XYs, 2*len(bins))
bot = make(plotter.XYs, 2*len(bins))
top = make(plotter.XYs, 0, 2*len(bins))
bot = make(plotter.XYs, 0, 2*len(bins))
)

for i := range top {
ibin := i / 2
bin := bins[ibin]
xmin, xmax := bin.XEdges().Min, bin.XEdges().Max
for i := 0; i < 2*len(bins); i++ {
var (
ibin = i / 2
bin = bins[ibin]
xmin = bin.XEdges().Min
xmax = bin.XEdges().Max
sumw = bin.SumW()
errw = bin.ErrW()
ymin = sumw - 0.5*errw
ymax = sumw + 0.5*errw
)
switch {
case h1.LogY && ymin <= 0:
continue
}
switch {
case i%2 != 0:
top[i].X = xmax
top[i].Y = bin.SumW() - 0.5*bin.ErrW()
bot[i].X = xmax
bot[i].Y = bin.SumW() + 0.5*bin.ErrW()
top = append(top, plotter.XY{X: xmax, Y: ymin})
bot = append(bot, plotter.XY{X: xmax, Y: ymax})
default:
top[i].X = xmin
top[i].Y = bin.SumW() - 0.5*bin.ErrW()
bot[i].X = xmin
bot[i].Y = bin.SumW() + 0.5*bin.ErrW()
top = append(top, plotter.XY{X: xmin, Y: ymin})
bot = append(bot, plotter.XY{X: xmin, Y: ymax})
}
}

Expand Down
6 changes: 4 additions & 2 deletions hplot/hstack.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,10 @@ func NewHStack(histos []*H1D, opts ...Options) *HStack {
}

if cfg.band {
plotHtot := NewH1D(hstack.summedH1D(), WithBand(true))
hstack.Band = plotHtot.Band
hstack.Band = NewH1D(hstack.summedH1D(),
WithBand(true),
WithLogY(cfg.log.y),
).Band
}

return hstack
Expand Down
1 change: 1 addition & 0 deletions hplot/hstack_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
func TestHStack(t *testing.T) {
checkPlot(cmpimg.CheckPlot)(ExampleHStack, t, "hstack.png")
checkPlot(cmpimg.CheckPlot)(ExampleHStack_withBand, t, "hstack_band.png")
checkPlot(cmpimg.CheckPlot)(ExampleHStack_withLogY, t, "hstack_logy.png")
}

func TestHStackPanic(t *testing.T) {
Expand Down
Binary file modified hplot/testdata/hstack_band_golden.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added hplot/testdata/hstack_logy_golden.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 88911b6

Please sign in to comment.