hplot

package
v0.36.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 15, 2024 License: BSD-3-Clause Imports: 30 Imported by: 50

README

hplot

GoDoc

hplot is a WIP package relying on gonum/plot to plot histograms, n-tuples and functions.

Installation

$ go get go-hep.org/x/hep/hplot

Documentation

Is available on godoc:

https://godoc.org/go-hep.org/x/hep/hplot

Examples

1D histogram

hist-example

func ExampleH1D() {
	const npoints = 10000

	// Create a normal distribution.
	dist := distuv.Normal{
		Mu:    0,
		Sigma: 1,
		Src:   rand.New(rand.NewSource(0)),
	}

	// Draw some random values from the standard
	// normal distribution.
	hist := hbook.NewH1D(20, -4, +4)
	for i := 0; i < npoints; i++ {
		v := dist.Rand()
		hist.Fill(v, 1)
	}

	// normalize histogram
	area := 0.0
	for _, bin := range hist.Binning.Bins {
		area += bin.SumW() * bin.XWidth()
	}
	hist.Scale(1 / area)

	// Make a plot and set its title.
	p := hplot.New()
	p.Title.Text = "Histogram"
	p.X.Label.Text = "X"
	p.Y.Label.Text = "Y"

	// Create a histogram of our values drawn
	// from the standard normal.
	h := hplot.NewH1D(hist)
	h.Infos.Style = hplot.HInfoSummary
	p.Add(h)

	// The normal distribution function
	norm := hplot.NewFunction(dist.Prob)
	norm.Color = color.RGBA{R: 255, A: 255}
	norm.Width = vg.Points(2)
	p.Add(norm)

	// draw a grid
	p.Add(hplot.NewGrid())

	// Save the plot to a PNG file.
	if err := p.Save(6*vg.Inch, -1, "testdata/h1d_plot.png"); err != nil {
		log.Fatalf("error saving plot: %v\n", err)
	}
}
1D histogram with y-error bars

hist-yerrs-example

func ExampleH1D_withYErrBars() {
	const npoints = 100

	// Create a normal distribution.
	dist := distuv.Normal{
		Mu:    0,
		Sigma: 1,
		Src:   rand.New(rand.NewSource(0)),
	}

	// Draw some random values from the standard
	// normal distribution.
	hist := hbook.NewH1D(20, -4, +4)
	for i := 0; i < npoints; i++ {
		v := dist.Rand()
		hist.Fill(v, 1)
	}

	// normalize histogram
	area := 0.0
	for _, bin := range hist.Binning.Bins {
		area += bin.SumW() * bin.XWidth()
	}
	hist.Scale(1 / area)

	// Make a plot and set its title.
	p := hplot.New()
	p.Title.Text = "Histogram"
	p.X.Label.Text = "X"
	p.Y.Label.Text = "Y"

	// Create a histogram of our values drawn
	// from the standard normal.
	h := hplot.NewH1D(hist,
		hplot.WithHInfo(hplot.HInfoSummary),
		hplot.WithYErrBars(true),
	)
	h.YErrs.LineStyle.Color = color.RGBA{R: 255, A: 255}
	p.Add(h)

	// The normal distribution function
	norm := hplot.NewFunction(dist.Prob)
	norm.Color = color.RGBA{R: 255, A: 255}
	norm.Width = vg.Points(2)
	p.Add(norm)

	// draw a grid
	p.Add(hplot.NewGrid())

	// Save the plot to a PNG file.
	if err := p.Save(6*vg.Inch, -1, "testdata/h1d_yerrs.png"); err != nil {
		log.Fatalf("error saving plot: %v\n", err)
	}
}
1D histogram with y-error bars, no lines

hist-glyphs-example

func ExampleH1D_withYErrBarsAndData() {
	const npoints = 100

	// Create a normal distribution.
	dist := distuv.Normal{
		Mu:    0,
		Sigma: 1,
		Src:   rand.New(rand.NewSource(0)),
	}

	// Draw some random values from the standard
	// normal distribution.
	hist := hbook.NewH1D(20, -4, +4)
	for i := 0; i < npoints; i++ {
		v := dist.Rand()
		hist.Fill(v, 1)
	}

	// normalize histogram
	area := 0.0
	for _, bin := range hist.Binning.Bins {
		area += bin.SumW() * bin.XWidth()
	}
	hist.Scale(1 / area)

	// Make a plot and set its title.
	p := hplot.New()
	p.Title.Text = "Histogram"
	p.X.Label.Text = "X"
	p.Y.Label.Text = "Y"

	p.Legend.Top = true
	p.Legend.Left = true

	// Create a histogram of our values drawn
	// from the standard normal.
	h := hplot.NewH1D(hist,
		hplot.WithHInfo(hplot.HInfoSummary),
		hplot.WithYErrBars(true),
		hplot.WithGlyphStyle(draw.GlyphStyle{
			Shape:  draw.CrossGlyph{},
			Color:  color.Black,
			Radius: vg.Points(2),
		}),
	)
	h.GlyphStyle.Shape = draw.CircleGlyph{}
	h.YErrs.LineStyle.Color = color.Black
	h.LineStyle.Width = 0 // disable histogram lines
	p.Add(h)
	p.Legend.Add("data", h)

	// The normal distribution function
	norm := hplot.NewFunction(dist.Prob)
	norm.Color = color.RGBA{R: 255, A: 255}
	norm.Width = vg.Points(2)
	p.Add(norm)
	p.Legend.Add("model", norm)

	// draw a grid
	p.Add(hplot.NewGrid())

	// Save the plot to a PNG file.
	if err := p.Save(6*vg.Inch, -1, "testdata/h1d_glyphs.png"); err != nil {
		log.Fatalf("error saving plot: %v\n", err)
	}
}
1D histogram with y-error bars and error bands

hist-yerrs-band-example

func ExampleH1D_withYErrBars_withBand() {
	const npoints = 100

	// Create a normal distribution.
	dist := distuv.Normal{
		Mu:    0,
		Sigma: 1,
		Src:   rand.New(rand.NewSource(0)),
	}

	// Draw some random values from the standard
	// normal distribution.
	hist := hbook.NewH1D(20, -4, +4)
	for i := 0; i < npoints; i++ {
		v := dist.Rand()
		hist.Fill(v, 1)
	}

	// normalize histogram
	area := 0.0
	for _, bin := range hist.Binning.Bins {
		area += bin.SumW() * bin.XWidth()
	}
	hist.Scale(1 / area)

	// Make a plot and set its title.
	p := hplot.New()
	p.Title.Text = "Histogram"
	p.X.Label.Text = "X"
	p.Y.Label.Text = "Y"

	// Create a histogram of our values drawn
	// from the standard normal.
	h := hplot.NewH1D(hist,
		hplot.WithHInfo(hplot.HInfoSummary),
		hplot.WithYErrBars(true),
		hplot.WithBand(true),
	)
	h.YErrs.LineStyle.Color = color.RGBA{R: 255, A: 255}
	p.Add(h)

	// The normal distribution function
	norm := hplot.NewFunction(dist.Prob)
	norm.Color = color.RGBA{R: 255, A: 255}
	norm.Width = vg.Points(2)
	p.Add(norm)

	// draw a grid
	p.Add(hplot.NewGrid())

	// Save the plot to a PNG file.
	if err := p.Save(6*vg.Inch, -1, "testdata/h1d_yerrs_band.png"); err != nil {
		log.Fatalf("error saving plot: %v\n", err)
	}
}
Tiles of 1D histograms

tiled-plot

func ExampleTiledPlot() {
	tp := hplot.NewTiledPlot(draw.Tiles{Cols: 3, Rows: 2})

	// Create a normal distribution.
	dist := distuv.Normal{
		Mu:    0,
		Sigma: 1,
		Src:   rand.New(rand.NewSource(0)),
	}

	newHist := func(p *hplot.Plot) {
		const npoints = 10000
		hist := hbook.NewH1D(20, -4, +4)
		for i := 0; i < npoints; i++ {
			v := dist.Rand()
			hist.Fill(v, 1)
		}

		h := hplot.NewH1D(hist)
		p.Add(h)
	}

	for i := 0; i < tp.Tiles.Rows; i++ {
		for j := 0; j < tp.Tiles.Cols; j++ {
			p := tp.Plot(j, i)
			p.X.Min = -5
			p.X.Max = +5
			newHist(p)
			p.Title.Text = fmt.Sprintf("hist - (%02d, %02d)", j, i)
		}
	}

	// remove plot at (1,0)
	tp.Plots[1] = nil

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

tiled-plot-aligned

func ExampleTiledPlot_align() {
	tp := hplot.NewTiledPlot(draw.Tiles{
		Cols: 3, Rows: 3,
		PadX: 20, PadY: 20,
	})
	tp.Align = true

	points := func(i, j int) []hbook.Point2D {
		n := i*tp.Tiles.Cols + j + 1
		i += 1
		j = int(math.Pow(10, float64(n)))

		var pts []hbook.Point2D
		for ii := 0; ii < 10; ii++ {
			pts = append(pts, hbook.Point2D{
				X: float64(i + ii),
				Y: float64(j + ii + 1),
			})
		}
		return pts

	}

	for i := 0; i < tp.Tiles.Rows; i++ {
		for j := 0; j < tp.Tiles.Cols; j++ {
			p := tp.Plot(j, i)
			p.X.Min = -5
			p.X.Max = +5
			s := hplot.NewS2D(hbook.NewS2D(points(i, j)...))
			s.GlyphStyle.Color = color.RGBA{R: 255, A: 255}
			s.GlyphStyle.Radius = vg.Points(4)
			p.Add(s)

			p.Title.Text = fmt.Sprintf("hist - (%02d, %02d)", j, i)
		}
	}

	// remove plot at (1,1)
	tp.Plots[4] = nil

	err := tp.Save(15*vg.Centimeter, -1, "testdata/tiled_plot_aligned_histogram.png")
	if err != nil {
		log.Fatalf("error: %+v\n", err)
	}
}
Subplots

sub-plot

https://godoc.org/go-hep.org/x/hep/hplot#example-package--Subplot

Ratio-plots

ratio-plot

func ExampleRatioPlot() {

	const npoints = 10000

	// Create a normal distribution.
	dist := distuv.Normal{
		Mu:    0,
		Sigma: 1,
		Src:   rand.New(rand.NewSource(0)),
	}

	hist1 := hbook.NewH1D(20, -4, +4)
	hist2 := hbook.NewH1D(20, -4, +4)

	for i := 0; i < npoints; i++ {
		v1 := dist.Rand() - 0.5
		v2 := dist.Rand() + 0.5
		hist1.Fill(v1, 1)
		hist2.Fill(v2, 1)
	}

	rp := hplot.NewRatioPlot()
	rp.Ratio = 0.3

	// Make a plot and set its title.
	rp.Top.Title.Text = "Histos"
	rp.Top.Y.Label.Text = "Y"

	// Create a histogram of our values drawn
	// from the standard normal.
	h1 := hplot.NewH1D(hist1)
	h1.FillColor = color.NRGBA{R: 255, A: 100}
	rp.Top.Add(h1)

	h2 := hplot.NewH1D(hist2)
	h2.FillColor = color.NRGBA{B: 255, A: 100}
	rp.Top.Add(h2)

	rp.Top.Add(hplot.NewGrid())

	hist3 := hbook.NewH1D(20, -4, +4)
	for i := 0; i < hist3.Len(); i++ {
		v1 := hist1.Value(i)
		v2 := hist2.Value(i)
		x1, _ := hist1.XY(i)
		hist3.Fill(x1, v1-v2)
	}

	hdiff := hplot.NewH1D(hist3)

	rp.Bottom.X.Label.Text = "X"
	rp.Bottom.Y.Label.Text = "Delta-Y"
	rp.Bottom.Add(hdiff)
	rp.Bottom.Add(hplot.NewGrid())

	const (
		width  = 15 * vg.Centimeter
		height = width / math.Phi
	)

	err := hplot.Save(rp, width, height, "testdata/diff_plot.png")
	if err != nil {
		log.Fatalf("error: %v\n", err)
	}
}
LaTeX-plots

latex-plot (PDF)

https://godoc.org/go-hep.org/x/hep/hplot#example-package--Latexplot

2D histogram
func ExampleH2D() {
	h := hbook.NewH2D(100, -10, 10, 100, -10, 10)

	const npoints = 10000

	dist, ok := distmv.NewNormal(
		[]float64{0, 1},
		mat.NewSymDense(2, []float64{4, 0, 0, 2}),
		rand.New(rand.NewSource(1234)),
	)
	if !ok {
		log.Fatalf("error creating distmv.Normal")
	}

	v := make([]float64, 2)
	// Draw some random values from the standard
	// normal distribution.
	for i := 0; i < npoints; i++ {
		v = dist.Rand(v)
		h.Fill(v[0], v[1], 1)
	}

	p := hplot.New()
	p.Title.Text = "Hist-2D"
	p.X.Label.Text = "x"
	p.Y.Label.Text = "y"

	p.Add(hplot.NewH2D(h, nil))
	p.Add(plotter.NewGrid())
	err := p.Save(10*vg.Centimeter, 10*vg.Centimeter, "testdata/h2d_plot.png")
	if err != nil {
		log.Fatal(err)
	}
}

h2d-example

Scatter2D
func ExampleS2D() {
	const npoints = 1000

	dist, ok := distmv.NewNormal(
		[]float64{0, 1},
		mat.NewSymDense(2, []float64{4, 0, 0, 2}),
		rand.New(rand.NewSource(1234)),
	)
	if !ok {
		log.Fatalf("error creating distmv.Normal")
	}

	s2d := hbook.NewS2D()

	v := make([]float64, 2)
	// Draw some random values from the standard
	// normal distribution.
	for i := 0; i < npoints; i++ {
		v = dist.Rand(v)
		s2d.Fill(hbook.Point2D{X: v[0], Y: v[1]})
	}

	p := hplot.New()
	p.Title.Text = "Scatter-2D"
	p.X.Label.Text = "X"
	p.Y.Label.Text = "Y"
	p.Add(plotter.NewGrid())

	s := hplot.NewS2D(s2d)
	s.GlyphStyle.Color = color.RGBA{R: 255, A: 255}
	s.GlyphStyle.Radius = vg.Points(2)

	p.Add(s)

	err := p.Save(10*vg.Centimeter, 10*vg.Centimeter, "testdata/s2d.png")
	if err != nil {
		log.Fatal(err)
	}
}

s2d-example s2d-errbars-example s2d-band-example s2d-steps-example s2d-steps-band-example

Vertical lines
func ExampleVLine() {
	p := hplot.New()
	p.Title.Text = "vlines"
	p.X.Min = 0
	p.X.Max = 10
	p.Y.Min = 0
	p.Y.Max = 10

	var (
		left  = color.RGBA{B: 255, A: 255}
		right = color.RGBA{R: 255, A: 255}
	)

	p.Add(
		hplot.VLine(2.5, left, nil),
		hplot.VLine(5, nil, nil),
		hplot.VLine(7.5, nil, right),
	)

	err := p.Save(10*vg.Centimeter, -1, "testdata/vline.png")
	if err != nil {
		log.Fatalf("error: %+v", err)
	}
}

vline-example

Horizontal lines
func ExampleHLine() {
	p := hplot.New()
	p.Title.Text = "hlines"
	p.X.Min = 0
	p.X.Max = 10
	p.Y.Min = 0
	p.Y.Max = 10

	var (
		top    = color.RGBA{B: 255, A: 255}
		bottom = color.RGBA{R: 255, A: 255}
	)

	p.Add(
		hplot.HLine(2.5, nil, bottom),
		hplot.HLine(5, nil, nil),
		hplot.HLine(7.5, top, nil),
	)

	err := p.Save(10*vg.Centimeter, -1, "testdata/hline.png")
	if err != nil {
		log.Fatalf("error: %+v", err)
	}
}

hline-example

Band between lines
func ExampleBand() {
	const (
		npoints = 100
		xmax    = 10
	)

	// Create a normal distribution.
	dist := distuv.Normal{
		Mu:    0,
		Sigma: 1,
		Src:   rand.New(rand.NewSource(0)),
	}

	topData := make(plotter.XYs, npoints)
	botData := make(plotter.XYs, npoints)

	// Draw some random values from the standard
	// normal distribution.
	for i := 0; i < npoints; i++ {
		x := float64(i+1) / xmax

		v1 := dist.Rand()
		v2 := dist.Rand()

		topData[i].X = x
		topData[i].Y = 1/x + v1 + 10

		botData[i].X = x
		botData[i].Y = math.Log(x) + v2
	}

	top, err := hplot.NewLine(topData)
	if err != nil {
		log.Fatalf("error: %+v", err)
	}
	top.LineStyle.Color = color.RGBA{R: 255, A: 255}

	bot, err := hplot.NewLine(botData)
	if err != nil {
		log.Fatalf("error: %+v", err)
	}
	bot.LineStyle.Color = color.RGBA{B: 255, A: 255}

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

	tp.Plots[0].Title.Text = "Band"
	tp.Plots[0].Add(
		top,
		bot,
		hplot.NewBand(color.Gray{200}, topData, botData),
	)

	tp.Plots[1].Title.Text = "Band"
	var (
		blue = color.RGBA{B: 255, A: 255}
		grey = color.Gray{200}
		band = hplot.NewBand(grey, topData, botData)
	)
	band.LineStyle = plotter.DefaultLineStyle
	band.LineStyle.Color = blue
	tp.Plots[1].Add(band)

	err = tp.Save(10*vg.Centimeter, -1, "testdata/band.png")
	if err != nil {
		log.Fatalf("error: %+v", err)
	}
}

band-example

Plot with borders

One can specify extra-space between the image borders (the physical file canvas) and the actual plot data.

plot-border-example

func ExampleH1D_withPlotBorders() {
	const npoints = 10000

	// Create a normal distribution.
	dist := distuv.Normal{
		Mu:    0,
		Sigma: 1,
		Src:   rand.New(rand.NewSource(0)),
	}

	// Draw some random values from the standard
	// normal distribution.
	hist := hbook.NewH1D(20, -4, +4)
	for i := 0; i < npoints; i++ {
		v := dist.Rand()
		hist.Fill(v, 1)
	}

	// normalize histogram
	area := 0.0
	for _, bin := range hist.Binning.Bins {
		area += bin.SumW() * bin.XWidth()
	}
	hist.Scale(1 / area)

	// Make a plot and set its title.
	p := hplot.New()
	p.Title.Text = "Histogram"
	p.X.Label.Text = "X"
	p.Y.Label.Text = "Y"

	// Create a histogram of our values drawn
	// from the standard normal.
	h := hplot.NewH1D(hist)
	h.Infos.Style = hplot.HInfoSummary
	p.Add(h)

	// The normal distribution function
	norm := hplot.NewFunction(dist.Prob)
	norm.Color = color.RGBA{R: 255, A: 255}
	norm.Width = vg.Points(2)
	p.Add(norm)

	// draw a grid
	p.Add(hplot.NewGrid())

	fig := hplot.Figure(p,
		hplot.WithDPI(96),
		hplot.WithBorder(hplot.Border{
			Right:  25,
			Left:   20,
			Top:    25,
			Bottom: 20,
		}),
	)

	// Save the plot to a PNG file.
	if err := hplot.Save(fig, 6*vg.Inch, -1, "testdata/h1d_borders.png"); err != nil {
		log.Fatalf("error saving plot: %v\n", err)
	}
}
Stack of 1D histograms

hstack-example

func ExampleHStack() {
	h1 := hbook.NewH1D(100, -10, 10)
	h2 := hbook.NewH1D(100, -10, 10)
	h3 := hbook.NewH1D(100, -10, 10)

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

	colors := []color.Color{
		color.NRGBA{122, 195, 106, 150},
		color.NRGBA{90, 155, 212, 150},
		color.NRGBA{250, 167, 91, 150},
	}

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

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

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

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

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

	{
		p := tp.Plots[0]
		p.Title.Text = "Histograms"
		p.Y.Label.Text = "Y"
		p.Add(hh1, hh2, hh3, hplot.NewGrid())
		p.Legend.Add("h1", hh1)
		p.Legend.Add("h2", hh2)
		p.Legend.Add("h3", hh3)
		p.Legend.Top = true
		p.Legend.Left = true
	}

	{
		p := tp.Plot(0, 1)
		p.Title.Text = "HStack - stack: OFF"
		p.Y.Label.Text = "Y"
		hstack := hplot.NewHStack(hs)
		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, 2)
		p.Title.Text = "Hstack - stack: ON"
		p.X.Label.Text = "X"
		p.Y.Label.Text = "Y"
		hstack := hplot.NewHStack(hs, hplot.WithLogY(false))
		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(15*vg.Centimeter, 15*vg.Centimeter, "testdata/hstack.png")
	if err != nil {
		log.Fatalf("error: %+v", err)
	}

}
Stack of 1D histograms with a band

hstack-band-example

func ExampleHStack_withBand() {
	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},
	}

	hh1 := hplot.NewH1D(h1, hplot.WithBand(true))
	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))
	hh2.FillColor = colors[1]
	hh2.LineStyle.Width = 0

	hh3 := hplot.NewH1D(h3, hplot.WithBand(true))
	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)
	hh4.FillColor = colors[0]
	hh4.LineStyle.Color = color.Black

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

	hh6 := hplot.NewH1D(h3)
	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.X.Label.Text = "X"
		p.Y.Label.Text = "Y"
		hstack := hplot.NewHStack(hs, hplot.WithBand(true))
		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(1, 0)
		p.Title.Text = "Histos Without Band, Stack: OFF"
		p.Title.Padding = 10
		p.X.Label.Text = "X"
		p.Y.Label.Text = "Y"
		hstack := hplot.NewHStack(hsHistoNoBand, hplot.WithBand(true))
		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(0, 1)
		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}
		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.X.Label.Text = "X"
		p.Y.Label.Text = "Y"
		hstack := hplot.NewHStack(hsHistoNoBand, hplot.WithBand(true))
		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_band.png")
	if err != nil {
		log.Fatalf("error: %+v", err)
	}
}
Stack of 1D histograms with a band, with a log-y scale

hstack-logy-example

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(1, 0)
		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(0, 1)
		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)
	}
}

Labels

label-example

func ExampleLabel() {

	// Creating a new plot
	p := hplot.New()
	p.Title.Text = "Plot labels"
	p.X.Min = -10
	p.X.Max = +10
	p.Y.Min = -10
	p.Y.Max = +10

	// Default labels
	l1 := hplot.NewLabel(-8, 5, "(-8,5)\nDefault label")
	p.Add(l1)

	// Label with normalized coordinates.
	l3 := hplot.NewLabel(
		0.5, 0.5,
		"(0.5,0.5)\nLabel with relative coords",
		hplot.WithLabelNormalized(true),
	)
	p.Add(l3)

	// Label with normalized coordinates and auto-adjustement.
	l4 := hplot.NewLabel(
		0.95, 0.95,
		"(0.95,0.95)\nLabel at the canvas edge, with AutoAdjust",
		hplot.WithLabelNormalized(true),
		hplot.WithLabelAutoAdjust(true),
	)
	p.Add(l4)

	// Label with a customed TextStyle
	usrFont := font.Font{
		Typeface: "Liberation",
		Variant:  "Mono",
		Weight:   xfnt.WeightBold,
		Style:    xfnt.StyleNormal,
		Size:     12,
	}
	sty := text.Style{
		Color: plotutil.Color(2),
		Font:  usrFont,
	}
	l5 := hplot.NewLabel(
		0.0, 0.1,
		"(0.0,0.1)\nLabel with a user-defined font",
		hplot.WithLabelTextStyle(sty),
		hplot.WithLabelNormalized(true),
	)
	p.Add(l5)

	p.Add(plotter.NewGlyphBoxes())
	p.Add(hplot.NewGrid())

	// Save the plot to a PNG file.
	err := p.Save(15*vg.Centimeter, -1, "testdata/label_plot.png")
	if err != nil {
		log.Fatalf("error saving plot: %v\n", err)
	}
}

Time series

timeseries-example

func ExampleTicks_monthly() {
	cnv := epok.UTCUnixTimeConverter{}

	p := hplot.New()
	p.Title.Text = "Time series (monthly)"
	p.Y.Label.Text = "Goroutines"

	p.Y.Min = 0
	p.Y.Max = 4
	p.X.AutoRescale = true
	p.X.Tick.Marker = epok.Ticks{
		Ruler: epok.Rules{
			Major: epok.Rule{
				Freq:  epok.Monthly,
				Range: epok.RangeFrom(1, 13, 2),
			},
		},
		Format:    "2006\nJan-02\n15:04:05",
		Converter: cnv,
	}

	xysFrom := func(vs ...float64) plotter.XYs {
		o := make(plotter.XYs, len(vs))
		for i := range o {
			o[i].X = vs[i]
			o[i].Y = float64(i + 1)
		}
		return o
	}
	data := xysFrom(
		cnv.FromTime(parse("2010-01-02 01:02:03")),
		cnv.FromTime(parse("2010-02-01 01:02:03")),
		cnv.FromTime(parse("2010-02-04 11:22:33")),
		cnv.FromTime(parse("2010-03-04 01:02:03")),
		cnv.FromTime(parse("2010-04-05 01:02:03")),
		cnv.FromTime(parse("2010-04-05 01:02:03")),
		cnv.FromTime(parse("2010-05-01 00:02:03")),
		cnv.FromTime(parse("2010-05-04 04:04:04")),
		cnv.FromTime(parse("2010-05-08 11:12:13")),
		cnv.FromTime(parse("2010-06-15 01:02:03")),
		cnv.FromTime(parse("2010-07-04 04:04:43")),
		cnv.FromTime(parse("2010-07-14 14:17:09")),
		cnv.FromTime(parse("2010-08-04 21:22:23")),
		cnv.FromTime(parse("2010-08-15 11:12:13")),
		cnv.FromTime(parse("2010-09-01 21:52:53")),
		cnv.FromTime(parse("2010-10-25 01:19:23")),
		cnv.FromTime(parse("2010-11-30 11:32:53")),
		cnv.FromTime(parse("2010-12-24 23:59:59")),
		cnv.FromTime(parse("2010-12-31 23:59:59")),
		cnv.FromTime(parse("2011-01-12 01:02:03")),
	)

	line, pnts, err := hplot.NewLinePoints(data)
	if err != nil {
		log.Fatalf("could not create plotter: %+v", err)
	}

	line.Color = color.RGBA{B: 255, A: 255}
	pnts.Shape = draw.CircleGlyph{}
	pnts.Color = color.RGBA{R: 255, A: 255}

	p.Add(line, pnts, hplot.NewGrid())

	err = p.Save(20*vg.Centimeter, 10*vg.Centimeter, "testdata/timeseries_monthly.png")
	if err != nil {
		log.Fatalf("could not save plot: %+v", err)
	}
}

Documentation

Overview

Package hplot is a package to plot histograms, n-tuples and functions

Example (Latexplot)
package main

import (
	"image/color"
	"log"
	"math"

	"go-hep.org/x/hep/hbook"
	"go-hep.org/x/hep/hplot"
	"golang.org/x/exp/rand"
	"gonum.org/v1/gonum/stat/distuv"
	"gonum.org/v1/plot/vg"
)

func main() {

	const npoints = 10000

	// Create a normal distribution.
	dist := distuv.Normal{
		Mu:    0,
		Sigma: 1,
		Src:   rand.New(rand.NewSource(0)),
	}

	hist := hbook.NewH1D(20, -4, +4)
	for i := 0; i < npoints; i++ {
		v := dist.Rand()
		hist.Fill(v, 1)
	}

	// Make a plot and set its title.
	p := hplot.New()
	p.Title.Text = `Gaussian distribution: $f(x) = \frac{e^{-(x - \mu)^{2}/(2\sigma^{2}) }} {\sigma\sqrt{2\pi}}$`
	p.Y.Label.Text = `$f(x)$`
	p.X.Label.Text = `$x$`

	// Create a histogram of our values drawn
	// from the standard normal.
	h := hplot.NewH1D(hist)
	h.LineStyle.Color = color.RGBA{R: 255, A: 255}
	h.FillColor = nil
	h.Infos.Style = hplot.HInfoSummary
	p.Add(h)

	p.Add(hplot.NewGrid())

	const (
		width  = 15 * vg.Centimeter
		height = width / math.Phi
	)

	fig := hplot.Figure(p, hplot.WithBorder(hplot.Border{
		Left:   5,
		Right:  5,
		Top:    5,
		Bottom: 5,
	}))

	err := hplot.Save(fig, width, height, "testdata/latex_plot.tex")
	if err != nil {
		log.Fatalf("could not save LaTeX plot: %+v\n", err)
	}
}
Output:

Example (Subplot)

An example of a plot + sub-plot

package main

import (
	"image/color"
	"log"
	"math"
	"os"

	"go-hep.org/x/hep/hbook"
	"go-hep.org/x/hep/hplot"
	"golang.org/x/exp/rand"
	"gonum.org/v1/gonum/stat/distuv"
	"gonum.org/v1/plot/vg"
	"gonum.org/v1/plot/vg/draw"
	"gonum.org/v1/plot/vg/vgimg"
)

func main() {
	const npoints = 10000

	// Create a normal distribution.
	dist := distuv.Normal{
		Mu:    0,
		Sigma: 1,
		Src:   rand.New(rand.NewSource(0)),
	}

	// Draw some random values from the standard
	// normal distribution.
	hist := hbook.NewH1D(20, -4, +4)
	for i := 0; i < npoints; i++ {
		v := dist.Rand()
		hist.Fill(v, 1)
	}

	// normalize histo
	area := 0.0
	for _, bin := range hist.Binning.Bins {
		area += bin.SumW() * bin.XWidth()
	}
	hist.Scale(1 / area)

	// Make a plot and set its title.
	p1 := hplot.New()
	p1.Title.Text = "Histogram"
	p1.X.Label.Text = "X"
	p1.Y.Label.Text = "Y"

	// Create a histogram of our values drawn
	// from the standard normal.
	h := hplot.NewH1D(hist)
	p1.Add(h)

	// The normal distribution function
	norm := hplot.NewFunction(dist.Prob)
	norm.Color = color.RGBA{R: 255, A: 255}
	norm.Width = vg.Points(2)
	p1.Add(norm)

	// draw a grid
	p1.Add(hplot.NewGrid())

	// make a second plot which will be diplayed in the upper-right
	// of the previous one
	p2 := hplot.New()
	p2.Title.Text = "Sub plot"
	p2.Add(h)
	p2.Add(hplot.NewGrid())

	const (
		width  = 15 * vg.Centimeter
		height = width / math.Phi
	)

	c := vgimg.PngCanvas{Canvas: vgimg.New(width, height)}
	dc := draw.New(c)
	p1.Draw(dc)
	sub := draw.Canvas{
		Canvas: dc,
		Rectangle: vg.Rectangle{
			Min: vg.Point{X: 0.70 * width, Y: 0.50 * height},
			Max: vg.Point{X: 1.00 * width, Y: 1.00 * height},
		},
	}
	p2.Draw(sub)

	f, err := os.Create("testdata/sub_plot.png")
	if err != nil {
		log.Fatalf("error: %v\n", err)
	}
	defer f.Close()
	_, err = c.WriteTo(f)
	if err != nil {
		log.Fatal(err)
	}
	err = f.Close()
	if err != nil {
		log.Fatal(err)
	}

}
Output:

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Dims added in v0.27.0

func Dims(width, height vg.Length) (w, h vg.Length)

func NewGrid

func NewGrid() *plotter.Grid

NewGrid returns a new grid with both vertical and horizontal lines using the default grid line style.

func NewLine

func NewLine(xys plotter.XYer) (*plotter.Line, error)

NewLine returns a Line that uses the default line style and does not draw glyphs.

func NewLinePoints added in v0.34.0

func NewLinePoints(xys plotter.XYer) (*plotter.Line, *plotter.Scatter, error)

NewLinePoints returns both a Line and a Points for the given point data.

func NewScatter

func NewScatter(xys plotter.XYer) (*plotter.Scatter, error)

NewScatter returns a Scatter that uses the default glyph style.

func Save added in v0.27.0

func Save(p Drawer, w, h vg.Length, fnames ...string) (err error)

Save saves the plot to an image file. The file format is determined by the extension.

Supported extensions are:

.eps, .jpg, .jpeg, .json, .pdf, .png, .svg, .tex, .tif and .tiff.

If w or h are <= 0, the value is chosen such that it follows the Golden Ratio. If w and h are <= 0, the values are chosen such that they follow the Golden Ratio (the width is defaulted to vgimg.DefaultWidth).

Example
package main

import (
	"log"

	"go-hep.org/x/hep/hplot"
)

func main() {
	p := hplot.New()
	p.Title.Text = "my title"
	p.X.Label.Text = "x"
	p.Y.Label.Text = "y"

	const (
		width  = -1 // automatically choose a nice plot width
		height = -1 // automatically choose a nice plot height
	)

	err := hplot.Save(
		p,
		width, height,
		"testdata/plot_save.eps",
		"testdata/plot_save.jpg",
		"testdata/plot_save.pdf",
		"testdata/plot_save.png",
		"testdata/plot_save.svg",
		"testdata/plot_save.tex",
		"testdata/plot_save.tif",
	)

	if err != nil {
		log.Fatalf("could not save plot: %+v", err)
	}
}
Output:

func Show

func Show(p Drawer, w, h vg.Length, format string) ([]byte, error)

Show displays the plot according to format, returning the raw bytes and an error, if any.

If format is the empty string, then "png" is selected. The list of accepted format strings is the same one than from the gonum.org/v1/plot/vg/draw.NewFormattedCanvas function.

func WriterTo added in v0.27.0

func WriterTo(p Drawer, w, h vg.Length, format string) (io.WriterTo, error)

WriterTo returns an io.WriterTo that will write the plots as the specified image format.

Supported formats are the same ones than hplot.Save.

If w or h are <= 0, the value is chosen such that it follows the Golden Ratio. If w and h are <= 0, the values are chosen such that they follow the Golden Ratio (the width is defaulted to vgimg.DefaultWidth).

func ZipXY

func ZipXY(x, y []float64) plotter.XYer

ZipXY zips together 2 slices x and y in such a way to implement the plotter.XYer interface.

ZipXY panics if the slices are not of the same length.

Types

type Band added in v0.20.0

type Band struct {

	// LineStyle is the style of the line contouring the band.
	// Use zero width to disable.
	draw.LineStyle

	// FillColor is the color to fill the area between
	// the top and bottom data points.
	// Use nil to disable the filling.
	FillColor color.Color
	// contains filtered or unexported fields
}

Band implements the plot.Plotter interface, drawing a colored band made of two lines.

Example

An example of making a colored band plot

package main

import (
	"image/color"
	"log"
	"math"

	"go-hep.org/x/hep/hplot"
	"golang.org/x/exp/rand"
	"gonum.org/v1/gonum/stat/distuv"
	"gonum.org/v1/plot/plotter"
	"gonum.org/v1/plot/vg"
	"gonum.org/v1/plot/vg/draw"
)

func main() {
	const (
		npoints = 100
		xmax    = 10
	)

	// Create a normal distribution.
	dist := distuv.Normal{
		Mu:    0,
		Sigma: 1,
		Src:   rand.New(rand.NewSource(0)),
	}

	topData := make(plotter.XYs, npoints)
	botData := make(plotter.XYs, npoints)

	// Draw some random values from the standard
	// normal distribution.
	for i := 0; i < npoints; i++ {
		x := float64(i+1) / xmax

		v1 := dist.Rand()
		v2 := dist.Rand()

		topData[i].X = x
		topData[i].Y = 1/x + v1 + 10

		botData[i].X = x
		botData[i].Y = math.Log(x) + v2
	}

	top, err := hplot.NewLine(topData)
	if err != nil {
		log.Fatalf("error: %+v", err)
	}
	top.LineStyle.Color = color.RGBA{R: 255, A: 255}

	bot, err := hplot.NewLine(botData)
	if err != nil {
		log.Fatalf("error: %+v", err)
	}
	bot.LineStyle.Color = color.RGBA{B: 255, A: 255}

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

	tp.Plots[0].Title.Text = "Band"
	tp.Plots[0].Add(
		top,
		bot,
		hplot.NewBand(color.Gray{200}, topData, botData),
	)

	tp.Plots[1].Title.Text = "Band"
	var (
		blue = color.RGBA{B: 255, A: 255}
		grey = color.Gray{200}
		band = hplot.NewBand(grey, topData, botData)
	)
	band.LineStyle = plotter.DefaultLineStyle
	band.LineStyle.Color = blue
	tp.Plots[1].Add(band)

	err = tp.Save(10*vg.Centimeter, -1, "testdata/band.png")
	if err != nil {
		log.Fatalf("error: %+v", err)
	}
}
Output:

func NewBand added in v0.20.0

func NewBand(fill color.Color, top, bottom plotter.XYer) *Band

func (*Band) DataRange added in v0.20.0

func (band *Band) DataRange() (xmin, xmax, ymin, ymax float64)

DataRange returns the minimum and maximum x and y values, implementing the plot.DataRanger interface.

func (*Band) Plot added in v0.20.0

func (band *Band) Plot(c draw.Canvas, plt *plot.Plot)

type BinnedErrBand added in v0.28.0

type BinnedErrBand struct {

	// Data for every bins.
	Counts []hbook.Count

	// LineStyle is the style of the line
	// contouring the band.
	// Use zero width to disable.
	draw.LineStyle

	// FillColor is the color to fill the area
	// between the top and bottom data points.
	// Use nil to disable the filling.
	FillColor color.Color

	// LogY allows rendering with a log-scaled Y axis.
	// When enabled, bins with negative or zero minimal value (val-err)
	// will be discarded from the error band.
	// The lowest Y value for the DataRange will be corrected to leave an
	// arbitrary amount of height for the smallest bin entry so it is visible
	// on the final plot.
	LogY bool
}

BinnedErrBand implements the plot.Plotter interface, drawing a colored band for the error on any binned quantity.

Example

An example of making a colored binned error band from scratch.

package main

import (
	"image/color"
	"log"

	"gonum.org/v1/plot/vg"

	"go-hep.org/x/hep/hbook"
	"go-hep.org/x/hep/hplot"
)

func main() {

	// Number bins
	nBins := 10

	// Creation of a slice of hbook.Count.
	counts := make([]hbook.Count, nBins)
	for i, xrange := range newBinning(nBins, 0, 10) {
		y := float64(i + 1)
		counts[i].XRange = xrange
		counts[i].Val = y
		counts[i].Err.Low = 0.1 * (y - 5) * (y - 5)
		counts[i].Err.High = 0.1 * (y - 5) * (y - 5)
	}

	// Set error of the 5th bin to zero
	counts[4].Err.Low, counts[4].Err.High = 0, 0

	// Binned error band
	b := &hplot.BinnedErrBand{Counts: counts}
	b.FillColor = color.NRGBA{B: 180, A: 200}
	b.LineStyle.Color = color.NRGBA{R: 180, A: 200}
	b.LineStyle.Width = 2

	// Create a new plot and add b
	p := hplot.New()
	p.Title.Text = "Binned Error Band"
	p.X.Label.Text = "Binned X"
	p.Y.Label.Text = "Y"
	p.Add(b)

	// Save the result
	err := p.Save(10*vg.Centimeter, -1, "testdata/binnederrband.png")
	if err != nil {
		log.Fatalf("error: %+v", err)
	}
}

// newBinning returns a slice of Range corresponding to
// an equally spaced binning.
func newBinning(n int, xmin, xmax float64) []hbook.Range {
	res := make([]hbook.Range, n)
	dx := (xmax - xmin) / float64(n)
	for i := 0; i < n; i++ {
		lo := xmin + float64(i)*dx
		hi := lo + dx
		res[i].Min = lo
		res[i].Max = hi
	}
	return res
}
Output:

Example (FromH1D)
package main

import (
	"image/color"
	"log"

	"golang.org/x/exp/rand"
	"gonum.org/v1/gonum/stat/distuv"
	"gonum.org/v1/plot/vg"

	"go-hep.org/x/hep/hbook"
	"go-hep.org/x/hep/hplot"
)

func main() {

	// Histogram
	h := hbook.NewH1D(20, -5, 5)
	for i := 0; i < 1000; i++ {
		x := gauss.Rand()
		if 0 < x && x < 0.5 {
			continue
		}
		h.Fill(x, 1)
	}

	hp := hplot.NewH1D(h)
	hp.LineStyle.Width = 0
	hp.FillColor = color.NRGBA{R: 180, G: 180, B: 180, A: 200}

	// Binned error band from the histo counts.
	b := hplot.NewBinnedErrBand(h.Counts())
	b.FillColor = color.NRGBA{B: 180, A: 100}
	b.LineStyle.Color = color.NRGBA{B: 100, A: 200}
	b.LineStyle.Width = 1

	// Create a new plot and add the histo and the band.
	p := hplot.New()
	p.Title.Text = "Binned Error Band from H1D"
	p.X.Label.Text = "Binned X"
	p.Y.Label.Text = "Y"
	p.Add(hp)
	p.Add(b)

	// Save the result
	err := p.Save(10*vg.Centimeter, -1, "testdata/binnederrband_fromh1d.png")
	if err != nil {
		log.Fatalf("error: %+v", err)
	}
}

var gauss = distuv.Normal{
	Mu:    0,
	Sigma: 1,
	Src:   rand.New(rand.NewSource(0)),
}
Output:

func NewBinnedErrBand added in v0.28.0

func NewBinnedErrBand(cs []hbook.Count) *BinnedErrBand

NewBinnedErrBand creates a binned error band from a slice of count.

func (*BinnedErrBand) DataRange added in v0.28.0

func (b *BinnedErrBand) DataRange() (xmin, xmax, ymin, ymax float64)

DataRange returns the minimum and maximum x and y values, implementing the plot.DataRanger interface.

func (*BinnedErrBand) Plot added in v0.28.0

func (b *BinnedErrBand) Plot(c draw.Canvas, plt *plot.Plot)

Plot implements the Plotter interface, drawing a colored box defined by width of bins (x-axis) and error (y-axis).

type Border added in v0.27.0

type Border struct {
	Left   vg.Length
	Right  vg.Length
	Bottom vg.Length
	Top    vg.Length
}

Border specifies the borders' sizes, the space between the end of the plot image (PDF, PNG, ...) and the actual plot.

type Drawer added in v0.27.0

type Drawer interface {
	Draw(draw.Canvas)
}

Drawer is the interface that wraps the Draw method.

type Fig added in v0.27.0

type Fig struct {
	// Plot is a gonum/plot.Plot like value.
	Plot Drawer

	// Legend displays a legend on the righthand-side of the plot.
	Legend *Legend

	// Border specifies the borders' sizes, the space between the
	// end of the plot image (PDF, PNG, ...) and the actual plot.
	Border Border

	// Latex handles the generation of PDFs from .tex files.
	// The default is to use htex.NoopHandler (a no-op).
	// To enable the automatic generation of PDFs, use DefaultHandler:
	//  p := hplot.Wrap(plt)
	//  p.Latex = htex.DefaultHandler
	Latex htex.Handler

	// DPI is the dot-per-inch for PNG,JPEG,... plots.
	DPI float64
}

Fig is a figure, holding a plot and figure-level customizations.

func Figure added in v0.27.0

func Figure(p Drawer, opts ...FigOption) *Fig

Figure creates a new figure from a plot and options. Figure returns a value implementing the Drawer interface.

func (*Fig) Draw added in v0.27.0

func (fig *Fig) Draw(dc draw.Canvas)

type FigOption added in v0.27.0

type FigOption func(fig *Fig)

FigOption allows to customize the creation of figures.

func WithBorder added in v0.27.0

func WithBorder(b Border) FigOption

WithBorder allows to specify the borders' sizes, the space between the end of the plot image (PDF, PNG, ...) and the actual plot.

func WithDPI added in v0.27.0

func WithDPI(dpi float64) FigOption

WithDPI allows to modify the default DPI of a plot.

func WithLatexHandler added in v0.27.0

func WithLatexHandler(h htex.Handler) FigOption

WithLatexHandler allows to enable the automatic generation of PDFs from .tex files. To enable the automatic generation of PDFs, use DefaultHandler:

WithLatexHandler(htex.DefaultHandler)

func WithLegend added in v0.34.0

func WithLegend(l Legend) FigOption

WithLegend enables the display of a legend on the righthand-side of a plot.

type FreqTicks

type FreqTicks struct {
	N    int // number of ticks
	Freq int // frequency of labeled ticks
}

FreqTicks implements a simple plot.Ticker scheme. FreqTicks will generate N ticks where 1 every Freq tick will be labeled.

func (FreqTicks) Ticks

func (ft FreqTicks) Ticks(min, max float64) []plot.Tick

Ticks returns Ticks in a specified range

type Function added in v0.21.0

type Function struct {
	F func(x float64) (y float64)

	// XMin and XMax specify the range
	// of x values to pass to F.
	XMin, XMax float64

	Samples int

	draw.LineStyle

	// LogY allows rendering with a log-scaled Y axis.
	// When enabled, function values returning 0 will be discarded from
	// the final plot.
	LogY bool
}

Function implements the Plotter interface, drawing a line for the given function.

Example

ExampleFunction draws some functions.

package main

import (
	"image/color"
	"log"
	"math"

	"go-hep.org/x/hep/hplot"
	"gonum.org/v1/plot/vg"
)

func main() {
	quad := hplot.NewFunction(func(x float64) float64 { return x * x })
	quad.Color = color.RGBA{B: 255, A: 255}

	exp := hplot.NewFunction(func(x float64) float64 { return math.Pow(2, x) })
	exp.Dashes = []vg.Length{vg.Points(2), vg.Points(2)}
	exp.Width = vg.Points(2)
	exp.Color = color.RGBA{G: 255, A: 255}

	sin := hplot.NewFunction(func(x float64) float64 { return 10*math.Sin(x) + 50 })
	sin.Dashes = []vg.Length{vg.Points(4), vg.Points(5)}
	sin.Width = vg.Points(4)
	sin.Color = color.RGBA{R: 255, A: 255}

	p := hplot.New()
	p.Title.Text = "Functions"
	p.X.Label.Text = "X"
	p.Y.Label.Text = "Y"

	p.Add(quad, exp, sin)
	p.Legend.Add("x^2", quad)
	p.Legend.Add("2^x", exp)
	p.Legend.Add("10*sin(x)+50", sin)
	p.Legend.ThumbnailWidth = 0.5 * vg.Inch

	p.X.Min = 0
	p.X.Max = 10
	p.Y.Min = 0
	p.Y.Max = 100

	err := p.Save(200, 200, "testdata/functions.png")
	if err != nil {
		log.Panic(err)
	}
}
Output:

Example (LogY)

ExampleFunction_logY draws a function with a Log-Y axis.

package main

import (
	"image/color"
	"log"

	"go-hep.org/x/hep/hplot"
	"gonum.org/v1/plot"
	"gonum.org/v1/plot/vg"
)

func main() {
	quad := hplot.NewFunction(func(x float64) float64 { return x * x })
	quad.Color = color.RGBA{B: 255, A: 255}

	fun := hplot.NewFunction(func(x float64) float64 {
		switch {
		case x < 6:
			return 20
		case 6 <= x && x < 7:
			return 0
		case 7 <= x && x < 7.5:
			return 30
		case 7.5 <= x && x < 9:
			return 0
		case 9 <= x:
			return 40
		}
		return 50
	})
	fun.LogY = true
	fun.Color = color.RGBA{R: 255, A: 255}

	p := hplot.New()
	p.Title.Text = "Functions - Log-Y scale"
	p.X.Label.Text = "X"
	p.Y.Label.Text = "Y"

	p.Y.Scale = plot.LogScale{}
	p.Y.Tick.Marker = plot.LogTicks{}

	p.Add(fun)
	p.Add(quad)
	p.Add(hplot.NewGrid())
	p.Legend.Add("x^2", quad)
	p.Legend.Add("fct", fun)
	p.Legend.ThumbnailWidth = 0.5 * vg.Inch

	p.X.Min = 5
	p.X.Max = 10
	p.Y.Min = 10
	p.Y.Max = 100

	err := p.Save(200, 200, "testdata/functions_logy.png")
	if err != nil {
		log.Panic(err)
	}
}
Output:

func NewFunction

func NewFunction(f func(float64) float64) *Function

NewFunction returns a Function that plots F using the default line style with 50 samples.

func (*Function) Plot added in v0.21.0

func (f *Function) Plot(c draw.Canvas, p *plot.Plot)

Plot implements the Plotter interface, drawing a line that connects each point in the Line.

func (Function) Thumbnail added in v0.21.0

func (f Function) Thumbnail(c *draw.Canvas)

Thumbnail draws a line in the given style down the center of a DrawArea as a thumbnail representation of the LineStyle of the function.

type H1D

type H1D struct {
	// Hist is the histogramming data
	Hist *hbook.H1D

	// FillColor is the color used to fill each
	// bar of the histogram.  If the color is nil
	// then the bars are not filled.
	FillColor color.Color

	// LineStyle is the style of the outline of each
	// bar of the histogram.
	draw.LineStyle

	// GlyphStyle is the style of the glyphs drawn
	// at the top of each histogram bar.
	GlyphStyle draw.GlyphStyle

	// LogY allows rendering with a log-scaled Y axis.
	// When enabled, histogram bins with no entries will be discarded from
	// the histogram's DataRange.
	// The lowest Y value for the DataRange will be corrected to leave an
	// arbitrary amount of height for the smallest bin entry so it is visible
	// on the final plot.
	LogY bool

	// InfoStyle is the style of infos displayed for
	// the histogram (entries, mean, rms).
	Infos HInfos

	// YErrs is the y error bars plotter.
	YErrs *plotter.YErrorBars

	// Band displays a colored band between the y-min and y-max error bars.
	// The band is shown in the legend thumbnail only if there is no filling.
	Band *BinnedErrBand
}

H1D implements the plotter.Plotter interface, drawing a histogram of the data.

Example

An example of making a 1D-histogram.

package main

import (
	"image/color"
	"log"

	"go-hep.org/x/hep/hbook"
	"go-hep.org/x/hep/hplot"
	"golang.org/x/exp/rand"
	"gonum.org/v1/gonum/stat/distuv"
	"gonum.org/v1/plot/vg"
)

func main() {
	const npoints = 10000

	// Create a normal distribution.
	dist := distuv.Normal{
		Mu:    0,
		Sigma: 1,
		Src:   rand.New(rand.NewSource(0)),
	}

	// Draw some random values from the standard
	// normal distribution.
	hist := hbook.NewH1D(20, -4, +4)
	for i := 0; i < npoints; i++ {
		v := dist.Rand()
		hist.Fill(v, 1)
	}

	// normalize histogram
	area := 0.0
	for _, bin := range hist.Binning.Bins {
		area += bin.SumW() * bin.XWidth()
	}
	hist.Scale(1 / area)

	// Make a plot and set its title.
	p := hplot.New()
	p.Title.Text = "Histogram"
	p.X.Label.Text = "X"
	p.Y.Label.Text = "Y"

	// Create a histogram of our values drawn
	// from the standard normal.
	h := hplot.NewH1D(hist)
	h.Infos.Style = hplot.HInfoSummary
	p.Add(h)

	// The normal distribution function
	norm := hplot.NewFunction(dist.Prob)
	norm.Color = color.RGBA{R: 255, A: 255}
	norm.Width = vg.Points(2)
	p.Add(norm)

	// draw a grid
	p.Add(hplot.NewGrid())

	// Save the plot to a PNG file.
	if err := p.Save(6*vg.Inch, -1, "testdata/h1d_plot.png"); err != nil {
		log.Fatalf("error saving plot: %v\n", err)
	}
}
Output:

Example (LegendStyle)

An example showing legend with different style

package main

import (
	"image/color"
	"log"

	"go-hep.org/x/hep/hbook"
	"go-hep.org/x/hep/hplot"
	"golang.org/x/exp/rand"
	"gonum.org/v1/gonum/stat/distuv"
	"gonum.org/v1/plot/plotutil"
	"gonum.org/v1/plot/vg"
	"gonum.org/v1/plot/vg/draw"
)

func main() {

	const npoints = 500

	// Create a few normal distributions.
	var hists [5]*hbook.H1D
	for id := range [5]int{0, 1, 2, 3, 4} {
		mu := -2. + float64(id)*2
		sigma := 0.3

		dist := distuv.Normal{
			Mu:    mu,
			Sigma: sigma,
			Src:   rand.New(rand.NewSource(uint64(id))),
		}

		// Draw some random values from the standard
		// normal distribution.
		hists[id] = hbook.NewH1D(15, mu-4*sigma, mu+4*sigma)
		for i := 0; i < npoints; i++ {
			v := dist.Rand()
			hists[id].Fill(v, 1)
		}
	}

	// Make a plot and set its title.
	p := hplot.New()
	p.Title.Text = "Histograms"
	p.X.Label.Text = "X"
	p.Y.Label.Text = "Y"
	p.X.Min = -3
	p.X.Max = 15

	// Legend style tunning
	p.Legend.Top = true
	p.Legend.ThumbnailWidth = 0.5 * vg.Inch
	p.Legend.TextStyle.Font.Size = 11
	p.Legend.Padding = 0.1 * vg.Inch

	// Histogram with line and markers
	hmarker := hplot.NewH1D(hists[0],
		hplot.WithYErrBars(true),
		hplot.WithGlyphStyle(draw.GlyphStyle{
			Color:  color.Black,
			Radius: 2,
			Shape:  draw.CircleGlyph{},
		}),
	)
	hmarker.LineStyle.Color = color.NRGBA{R: 200, G: 30, A: 255}
	hmarker.LineStyle.Width = 1
	hmarker.LineStyle.Dashes = plotutil.Dashes(2)
	p.Add(hmarker)
	p.Legend.Add("marker & line", hmarker)

	// Histogram with fill and line
	hfill := hplot.NewH1D(hists[1])
	hfill.FillColor = color.NRGBA{R: 200, A: 130}
	hfill.LineStyle.Color = color.NRGBA{R: 200, G: 30, A: 255}
	hfill.LineStyle.Width = 1.3
	p.Add(hfill)
	p.Legend.Add("fill & line", hfill)

	// Histogram with error band
	hband := hplot.NewH1D(hists[2], hplot.WithBand(true))
	hband.LineStyle.Width = 1.0
	p.Add(hband)
	p.Legend.Add("line & band", hband)

	// Histogram with fill, line and band
	hfillband := hplot.NewH1D(hists[3],
		hplot.WithBand(true),
	)
	hfillband.FillColor = color.NRGBA{B: 200, A: 180}
	hfillband.LineStyle.Color = color.NRGBA{B: 200, G: 30, A: 255}
	hfillband.LineStyle.Width = 1.3
	hfillband.Band.FillColor = color.NRGBA{R: 180, G: 180, B: 180, A: 180}
	p.Add(hfillband)
	p.Legend.Add("fill, line & band", hfillband)

	// Histogram with fill, line, markers and band
	hall := hplot.NewH1D(hists[4],
		hplot.WithBand(true),
		hplot.WithYErrBars(true),
		hplot.WithGlyphStyle(draw.GlyphStyle{
			Color:  color.Black,
			Radius: 2,
			Shape:  draw.CircleGlyph{},
		}),
	)
	hall.FillColor = color.NRGBA{G: 160, A: 180}
	hall.LineStyle.Color = color.NRGBA{G: 250, B: 60, R: 20, A: 255}
	hall.LineStyle.Width = 1.3
	p.Add(hall)
	p.Legend.Add("fill, marker, line & band", hall)

	// Create a figure
	fig := hplot.Figure(p, hplot.WithDPI(192.))
	fig.Border.Right = 15
	fig.Border.Left = 10
	fig.Border.Top = 10
	fig.Border.Bottom = 10

	// Save the figure to a PNG file.
	if err := hplot.Save(fig, 6*vg.Inch, -1, "testdata/h1d_legend.png"); err != nil {
		log.Fatalf("error saving plot: %v\n", err)
	}
}
Output:

Example (LogScaleY)
package main

import (
	"image/color"
	"log"

	"go-hep.org/x/hep/hbook"
	"go-hep.org/x/hep/hplot"
	"gonum.org/v1/plot"
	"gonum.org/v1/plot/vg"
	"gonum.org/v1/plot/vg/draw"
)

func main() {
	p := hplot.New()
	p.Title.Text = "Histogram in log-y"
	p.Y.Scale = plot.LogScale{}
	p.Y.Tick.Marker = plot.LogTicks{}
	p.Y.Label.Text = "Y"
	p.X.Label.Text = "X"

	h1 := hbook.NewH1D(10, -5, +5)
	for _, v := range []float64{
		-2, -2,
		-1,
		+3, +3, +3, +3,
		+1, +1, +1, +1, +1, +1, +1, +1, +1, +1,
		+1, +1, +1, +1, +1, +1, +1, +1, +1, +1,
	} {
		h1.Fill(v, 1)
	}
	p1 := hplot.NewH1D(h1)
	p1.LogY = true
	p1.FillColor = color.RGBA{255, 0, 0, 255}

	h2 := hbook.NewH1D(10, -5, +5)
	for _, v := range []float64{
		-3, -3, -3,
		+2, +2, +2, +2, +2,
	} {
		h2.Fill(v, 1)
	}
	p2 := hplot.NewH1D(h2,
		hplot.WithYErrBars(true),
		hplot.WithLogY(true),
		hplot.WithGlyphStyle(draw.GlyphStyle{
			Color:  color.Black,
			Radius: 2,
			Shape:  draw.CircleGlyph{},
		}),
	)
	p2.FillColor = color.RGBA{0, 0, 255, 255}

	p.Add(p1, p2, hplot.NewGrid())

	err := p.Save(6*vg.Inch, -1, "testdata/h1d_logy.png")
	if err != nil {
		log.Fatal(err)
	}
}
Output:

Example (ToPDF)

An example of making a 1D-histogram and saving to a PDF

package main

import (
	"image/color"
	"log"

	"go-hep.org/x/hep/hbook"
	"go-hep.org/x/hep/hplot"
	"golang.org/x/exp/rand"
	"gonum.org/v1/gonum/stat/distuv"
	"gonum.org/v1/plot/vg"
)

func main() {
	const npoints = 10000

	// Create a normal distribution.
	dist := distuv.Normal{
		Mu:    0,
		Sigma: 1,
		Src:   rand.New(rand.NewSource(0)),
	}

	// Draw some random values from the standard
	// normal distribution.
	hist := hbook.NewH1D(20, -4, +4)
	for i := 0; i < npoints; i++ {
		v := dist.Rand()
		hist.Fill(v, 1)
	}

	// normalize histogram
	area := 0.0
	for _, bin := range hist.Binning.Bins {
		area += bin.SumW() * bin.XWidth()
	}
	hist.Scale(1 / area)

	// Make a plot and set its title.
	p := hplot.New()
	p.Title.Text = "Histogram"
	p.X.Label.Text = "X"
	p.Y.Label.Text = "Y"

	// Create a histogram of our values drawn
	// from the standard normal.
	h := hplot.NewH1D(hist)
	h.Infos.Style = hplot.HInfoSummary
	p.Add(h)

	// The normal distribution function
	norm := hplot.NewFunction(dist.Prob)
	norm.Color = color.RGBA{R: 255, A: 255}
	norm.Width = vg.Points(2)
	p.Add(norm)

	// draw a grid
	p.Add(hplot.NewGrid())

	// Save the plot to a PNG file.
	if err := p.Save(6*vg.Inch, -1, "testdata/h1d_plot.pdf"); err != nil {
		log.Fatalf("error saving plot: %v\n", err)
	}
}
Output:

Example (WithPlotBorders)

An example of making a 1D-histogram.

package main

import (
	"image/color"
	"log"

	"go-hep.org/x/hep/hbook"
	"go-hep.org/x/hep/hplot"
	"golang.org/x/exp/rand"
	"gonum.org/v1/gonum/stat/distuv"
	"gonum.org/v1/plot/vg"
)

func main() {
	const npoints = 10000

	// Create a normal distribution.
	dist := distuv.Normal{
		Mu:    0,
		Sigma: 1,
		Src:   rand.New(rand.NewSource(0)),
	}

	// Draw some random values from the standard
	// normal distribution.
	hist := hbook.NewH1D(20, -4, +4)
	for i := 0; i < npoints; i++ {
		v := dist.Rand()
		hist.Fill(v, 1)
	}

	// normalize histogram
	area := 0.0
	for _, bin := range hist.Binning.Bins {
		area += bin.SumW() * bin.XWidth()
	}
	hist.Scale(1 / area)

	// Make a plot and set its title.
	p := hplot.New()
	p.Title.Text = "Histogram"
	p.X.Label.Text = "X"
	p.Y.Label.Text = "Y"

	// Create a histogram of our values drawn
	// from the standard normal.
	h := hplot.NewH1D(hist)
	h.Infos.Style = hplot.HInfoSummary
	p.Add(h)

	// The normal distribution function
	norm := hplot.NewFunction(dist.Prob)
	norm.Color = color.RGBA{R: 255, A: 255}
	norm.Width = vg.Points(2)
	p.Add(norm)

	// draw a grid
	p.Add(hplot.NewGrid())

	fig := hplot.Figure(p,
		hplot.WithDPI(96),
		hplot.WithBorder(hplot.Border{
			Right:  25,
			Left:   20,
			Top:    25,
			Bottom: 20,
		}),
	)

	// Save the plot to a PNG file.
	if err := hplot.Save(fig, 6*vg.Inch, -1, "testdata/h1d_borders.png"); err != nil {
		log.Fatalf("error saving plot: %v\n", err)
	}
}
Output:

Example (WithYErrBars)

An example of making a 1D-histogram with y-error bars.

package main

import (
	"image/color"
	"log"

	"go-hep.org/x/hep/hbook"
	"go-hep.org/x/hep/hplot"
	"golang.org/x/exp/rand"
	"gonum.org/v1/gonum/stat/distuv"
	"gonum.org/v1/plot/vg"
)

func main() {
	const npoints = 100

	// Create a normal distribution.
	dist := distuv.Normal{
		Mu:    0,
		Sigma: 1,
		Src:   rand.New(rand.NewSource(0)),
	}

	// Draw some random values from the standard
	// normal distribution.
	hist := hbook.NewH1D(20, -4, +4)
	for i := 0; i < npoints; i++ {
		v := dist.Rand()
		hist.Fill(v, 1)
	}

	// normalize histogram
	area := 0.0
	for _, bin := range hist.Binning.Bins {
		area += bin.SumW() * bin.XWidth()
	}
	hist.Scale(1 / area)

	// Make a plot and set its title.
	p := hplot.New()
	p.Title.Text = "Histogram"
	p.X.Label.Text = "X"
	p.Y.Label.Text = "Y"

	// Create a histogram of our values drawn
	// from the standard normal.
	h := hplot.NewH1D(hist,
		hplot.WithHInfo(hplot.HInfoSummary),
		hplot.WithYErrBars(true),
	)
	h.YErrs.LineStyle.Color = color.RGBA{R: 255, A: 255}
	p.Add(h)

	// The normal distribution function
	norm := hplot.NewFunction(dist.Prob)
	norm.Color = color.RGBA{R: 255, A: 255}
	norm.Width = vg.Points(2)
	p.Add(norm)

	// draw a grid
	p.Add(hplot.NewGrid())

	// Save the plot to a PNG file.
	if err := p.Save(6*vg.Inch, -1, "testdata/h1d_yerrs.png"); err != nil {
		log.Fatalf("error saving plot: %v\n", err)
	}
}
Output:

Example (WithYErrBarsAndData)

An example of making a 1D-histogram with y-error bars and no histogram rectangle.

package main

import (
	"image/color"
	"log"

	"go-hep.org/x/hep/hbook"
	"go-hep.org/x/hep/hplot"
	"golang.org/x/exp/rand"
	"gonum.org/v1/gonum/stat/distuv"
	"gonum.org/v1/plot/vg"
	"gonum.org/v1/plot/vg/draw"
)

func main() {
	const npoints = 100

	// Create a normal distribution.
	dist := distuv.Normal{
		Mu:    0,
		Sigma: 1,
		Src:   rand.New(rand.NewSource(0)),
	}

	// Draw some random values from the standard
	// normal distribution.
	hist := hbook.NewH1D(20, -4, +4)
	for i := 0; i < npoints; i++ {
		v := dist.Rand()
		hist.Fill(v, 1)
	}

	// normalize histogram
	area := 0.0
	for _, bin := range hist.Binning.Bins {
		area += bin.SumW() * bin.XWidth()
	}
	hist.Scale(1 / area)

	// Make a plot and set its title.
	p := hplot.New()
	p.Title.Text = "Histogram"
	p.X.Label.Text = "X"
	p.Y.Label.Text = "Y"

	p.Legend.Top = true
	p.Legend.Left = true

	// Create a histogram of our values drawn
	// from the standard normal.
	h := hplot.NewH1D(hist,
		hplot.WithHInfo(hplot.HInfoSummary),
		hplot.WithYErrBars(true),
		hplot.WithGlyphStyle(draw.GlyphStyle{
			Shape:  draw.CrossGlyph{},
			Color:  color.Black,
			Radius: vg.Points(2),
		}),
	)
	h.GlyphStyle.Shape = draw.CircleGlyph{}
	h.YErrs.LineStyle.Color = color.Black
	h.LineStyle.Width = 0 // disable histogram lines
	p.Add(h)
	p.Legend.Add("data", h)

	// The normal distribution function
	norm := hplot.NewFunction(dist.Prob)
	norm.Color = color.RGBA{R: 255, A: 255}
	norm.Width = vg.Points(2)
	p.Add(norm)
	p.Legend.Add("model", norm)

	// draw a grid
	p.Add(hplot.NewGrid())

	// Save the plot to a PNG file.
	if err := p.Save(6*vg.Inch, -1, "testdata/h1d_glyphs.png"); err != nil {
		log.Fatalf("error saving plot: %v\n", err)
	}
}
Output:

Example (WithYErrBars_withBand)

An example of making a 1D-histogram with y-error bars and the associated band.

package main

import (
	"image/color"
	"log"

	"go-hep.org/x/hep/hbook"
	"go-hep.org/x/hep/hplot"
	"golang.org/x/exp/rand"
	"gonum.org/v1/gonum/stat/distuv"
	"gonum.org/v1/plot/vg"
)

func main() {
	const npoints = 100

	// Create a normal distribution.
	dist := distuv.Normal{
		Mu:    0,
		Sigma: 1,
		Src:   rand.New(rand.NewSource(0)),
	}

	// Draw some random values from the standard
	// normal distribution.
	hist := hbook.NewH1D(20, -4, +4)
	for i := 0; i < npoints; i++ {
		v := dist.Rand()
		hist.Fill(v, 1)
	}

	// normalize histogram
	area := 0.0
	for _, bin := range hist.Binning.Bins {
		area += bin.SumW() * bin.XWidth()
	}
	hist.Scale(1 / area)

	// Make a plot and set its title.
	p := hplot.New()
	p.Title.Text = "Histogram"
	p.X.Label.Text = "X"
	p.Y.Label.Text = "Y"

	// Create a histogram of our values drawn
	// from the standard normal.
	h := hplot.NewH1D(hist,
		hplot.WithHInfo(hplot.HInfoSummary),
		hplot.WithYErrBars(true),
		hplot.WithBand(true),
	)
	h.YErrs.LineStyle.Color = color.RGBA{R: 255, A: 255}
	p.Add(h)

	// The normal distribution function
	norm := hplot.NewFunction(dist.Prob)
	norm.Color = color.RGBA{R: 255, A: 255}
	norm.Width = vg.Points(2)
	p.Add(norm)

	// draw a grid
	p.Add(hplot.NewGrid())

	// Save the plot to a PNG file.
	if err := p.Save(6*vg.Inch, -1, "testdata/h1d_yerrs_band.png"); err != nil {
		log.Fatalf("error saving plot: %v\n", err)
	}
}
Output:

func NewH1D

func NewH1D(h *hbook.H1D, opts ...Options) *H1D

NewH1D returns a new histogram, as in NewH1DFromXYer, except that it accepts a hbook.H1D instead of a plotter.XYer

func NewH1FromValuer

func NewH1FromValuer(vs plotter.Valuer, n int, opts ...Options) *H1D

NewH1FromValuer returns a new histogram, as in NewH1FromXYer, except that it accepts a plotter.Valuer instead of an XYer.

func NewH1FromXYer

func NewH1FromXYer(xy plotter.XYer, n int, opts ...Options) *H1D

NewH1FromXYer returns a new histogram that represents the distribution of values using the given number of bins.

Each y value is assumed to be the frequency count for the corresponding x.

It panics if the number of bins is non-positive.

func (*H1D) DataRange

func (h *H1D) DataRange() (xmin, xmax, ymin, ymax float64)

DataRange returns the minimum and maximum X and Y values

func (*H1D) GlyphBoxes

func (h *H1D) GlyphBoxes(p *plot.Plot) []plot.GlyphBox

GlyphBoxes returns a slice of GlyphBoxes, one for each of the bins, implementing the plot.GlyphBoxer interface.

func (*H1D) Plot

func (h *H1D) Plot(c draw.Canvas, p *plot.Plot)

Plot implements the Plotter interface, drawing a line that connects each point in the Line.

func (*H1D) Thumbnail

func (h *H1D) Thumbnail(c *draw.Canvas)

Thumbnail draws a rectangle in the given style of the histogram.

type H2D

type H2D struct {
	// H is the histogramming data
	H *hbook.H2D

	// InfoStyle is the style of infos displayed for
	// the histogram (entries, mean, rms)
	Infos HInfos

	// HeatMap implements the Plotter interface, drawing
	// a heat map of the values in the 2-d histogram.
	HeatMap *plotter.HeatMap
}

H2D implements the plotter.Plotter interface, drawing a 2-dim histogram of the data.

Example
package main

import (
	"log"

	"go-hep.org/x/hep/hbook"
	"go-hep.org/x/hep/hplot"
	"golang.org/x/exp/rand"
	"gonum.org/v1/gonum/mat"
	"gonum.org/v1/gonum/stat/distmv"
	"gonum.org/v1/plot/plotter"
	"gonum.org/v1/plot/vg"
)

func main() {
	h := hbook.NewH2D(100, -10, 10, 100, -10, 10)

	const npoints = 10000

	dist, ok := distmv.NewNormal(
		[]float64{0, 1},
		mat.NewSymDense(2, []float64{4, 0, 0, 2}),
		rand.New(rand.NewSource(1234)),
	)
	if !ok {
		log.Fatalf("error creating distmv.Normal")
	}

	v := make([]float64, 2)
	// Draw some random values from the standard
	// normal distribution.
	for i := 0; i < npoints; i++ {
		v = dist.Rand(v)
		h.Fill(v[0], v[1], 1)
	}

	p := hplot.New()
	p.Title.Text = "Hist-2D"
	p.X.Label.Text = "x"
	p.Y.Label.Text = "y"

	p.Add(hplot.NewH2D(h, nil))
	p.Add(plotter.NewGrid())
	err := p.Save(10*vg.Centimeter, 10*vg.Centimeter, "testdata/h2d_plot.png")
	if err != nil {
		log.Fatal(err)
	}
}
Output:

Example (WithLegend)
package main

import (
	"log"

	"go-hep.org/x/hep/hbook"
	"go-hep.org/x/hep/hplot"
	"golang.org/x/exp/rand"
	"gonum.org/v1/gonum/mat"
	"gonum.org/v1/gonum/stat/distmv"
	"gonum.org/v1/plot/plotter"
	"gonum.org/v1/plot/vg"
)

func main() {
	h2d := hbook.NewH2D(100, -10, 10, 100, -10, 10)

	const npoints = 10000

	dist, ok := distmv.NewNormal(
		[]float64{0, 1},
		mat.NewSymDense(2, []float64{4, 0, 0, 2}),
		rand.New(rand.NewSource(1234)),
	)
	if !ok {
		log.Fatalf("error creating distmv.Normal")
	}

	v := make([]float64, 2)
	// Draw some random values from the standard
	// normal distribution.
	for i := 0; i < npoints; i++ {
		v = dist.Rand(v)
		h2d.Fill(v[0], v[1], 1)
	}
	h := hplot.NewH2D(h2d, nil)

	p := hplot.New()
	p.Title.Text = "Hist-2D"
	p.X.Label.Text = "x"
	p.Y.Label.Text = "y"

	p.Add(h)
	p.Add(plotter.NewGrid())

	fig := hplot.Figure(p, hplot.WithLegend(h.Legend()))
	err := hplot.Save(fig, 10*vg.Centimeter, 10*vg.Centimeter, "testdata/h2d_plot_legend.png")
	if err != nil {
		log.Fatal(err)
	}
}
Output:

func NewH2D

func NewH2D(h *hbook.H2D, p palette.Palette) *H2D

NewH2D returns a new 2-dim histogram from a hbook.H2D.

func (*H2D) DataRange

func (h *H2D) DataRange() (xmin, xmax, ymin, ymax float64)

DataRange implements the DataRange method of the plot.DataRanger interface.

func (*H2D) GlyphBoxes

func (h *H2D) GlyphBoxes(p *plot.Plot) []plot.GlyphBox

GlyphBoxes returns a slice of GlyphBoxes, one for each of the bins, implementing the plot.GlyphBoxer interface.

func (*H2D) Legend added in v0.34.0

func (h *H2D) Legend() Legend

Legend returns a legend constructed from the 2-dim data and palette.

func (*H2D) Plot

func (h *H2D) Plot(c draw.Canvas, p *plot.Plot)

Plot implements the Plotter interface, drawing a line that connects each point in the Line.

type HInfoStyle

type HInfoStyle uint32
const (
	HInfoNone    HInfoStyle = 0
	HInfoEntries HInfoStyle = 1 << iota
	HInfoMean
	HInfoRMS
	HInfoStdDev
	HInfoSummary HInfoStyle = HInfoEntries | HInfoMean | HInfoStdDev
)

type HInfos

type HInfos struct {
	Style HInfoStyle
}

type HStack added in v0.26.0

type HStack struct {

	// LogY allows rendering with a log-scaled Y axis.
	// When enabled, histogram bins with no entries will be discarded from
	// the histogram's DataRange.
	// The lowest Y value for the DataRange will be corrected to leave an
	// arbitrary amount of height for the smallest bin entry so it is visible
	// on the final plot.
	LogY bool

	// Stack specifies how histograms are displayed.
	// Default is to display histograms stacked on top of each other.
	// If not stacked, individual histogram uncertainty bands will be
	// displayed when defined.
	// If stacked, individual uncertainty bands will not be diplayed
	// but the total band can be displayed with the hplot.WithBand(true)
	// option.
	Stack HStackKind

	// Band displays a colored band between the y-min and y-max error bars.
	// Error bars are computed as the bin-by-bin quadratic sum of individual
	// histogram uncertainties.
	Band *BinnedErrBand
	// contains filtered or unexported fields
}

HStack implements the plot.Plotter interface, drawing a stack of histograms.

Example
package main

import (
	"image/color"
	"log"

	"go-hep.org/x/hep/hbook"
	"go-hep.org/x/hep/hplot"
	"golang.org/x/exp/rand"
	"gonum.org/v1/gonum/stat/distuv"
	"gonum.org/v1/plot/vg"
	"gonum.org/v1/plot/vg/draw"
)

func main() {
	h1 := hbook.NewH1D(100, -10, 10)
	h2 := hbook.NewH1D(100, -10, 10)
	h3 := hbook.NewH1D(100, -10, 10)

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

	colors := []color.Color{
		color.NRGBA{122, 195, 106, 150},
		color.NRGBA{90, 155, 212, 150},
		color.NRGBA{250, 167, 91, 150},
	}

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

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

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

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

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

	{
		p := tp.Plots[0]
		p.Title.Text = "Histograms"
		p.Y.Label.Text = "Y"
		p.Add(hh1, hh2, hh3, hplot.NewGrid())
		p.Legend.Add("h1", hh1)
		p.Legend.Add("h2", hh2)
		p.Legend.Add("h3", hh3)
		p.Legend.Top = true
		p.Legend.Left = true
	}

	{
		p := tp.Plot(0, 1)
		p.Title.Text = "HStack - stack: OFF"
		p.Y.Label.Text = "Y"
		hstack := hplot.NewHStack(hs)
		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, 2)
		p.Title.Text = "Hstack - stack: ON"
		p.X.Label.Text = "X"
		p.Y.Label.Text = "Y"
		hstack := hplot.NewHStack(hs, hplot.WithLogY(false))
		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(15*vg.Centimeter, 15*vg.Centimeter, "testdata/hstack.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,
		Sigma: sigma,
		Src:   rand.New(rand.NewSource(seed)),
	}

	for i := 0; i < n; i++ {
		v := dist.Rand()
		h.Fill(v, 1)
	}
}
Output:

Example (WithBand)
package main

import (
	"image/color"
	"log"

	"go-hep.org/x/hep/hbook"
	"go-hep.org/x/hep/hplot"
	"golang.org/x/exp/rand"
	"gonum.org/v1/gonum/stat/distuv"
	"gonum.org/v1/plot/vg"
	"gonum.org/v1/plot/vg/draw"
)

func main() {
	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},
	}

	hh1 := hplot.NewH1D(h1, hplot.WithBand(true))
	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))
	hh2.FillColor = colors[1]
	hh2.LineStyle.Width = 0

	hh3 := hplot.NewH1D(h3, hplot.WithBand(true))
	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)
	hh4.FillColor = colors[0]
	hh4.LineStyle.Color = color.Black

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

	hh6 := hplot.NewH1D(h3)
	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.X.Label.Text = "X"
		p.Y.Label.Text = "Y"
		hstack := hplot.NewHStack(hs, hplot.WithBand(true))
		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(1, 0)
		p.Title.Text = "Histos Without Band, Stack: OFF"
		p.Title.Padding = 10
		p.X.Label.Text = "X"
		p.Y.Label.Text = "Y"
		hstack := hplot.NewHStack(hsHistoNoBand, hplot.WithBand(true))
		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(0, 1)
		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}
		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.X.Label.Text = "X"
		p.Y.Label.Text = "Y"
		hstack := hplot.NewHStack(hsHistoNoBand, hplot.WithBand(true))
		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_band.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,
		Sigma: sigma,
		Src:   rand.New(rand.NewSource(seed)),
	}

	for i := 0; i < n; i++ {
		v := dist.Rand()
		h.Fill(v, 1)
	}
}
Output:

Example (WithLogY)
package main

import (
	"image/color"
	"log"

	"go-hep.org/x/hep/hbook"
	"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"
)

func main() {
	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(1, 0)
		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(0, 1)
		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,
		Sigma: sigma,
		Src:   rand.New(rand.NewSource(seed)),
	}

	for i := 0; i < n; i++ {
		v := dist.Rand()
		h.Fill(v, 1)
	}
}
Output:

func NewHStack added in v0.26.0

func NewHStack(histos []*H1D, opts ...Options) *HStack

NewHStack creates a new histogram stack from the provided list of histograms. NewHStack panicks if the list of histograms is empty. NewHStack panicks if the histograms have different binning.

func (*HStack) DataRange added in v0.26.0

func (hstack *HStack) DataRange() (xmin, xmax, ymin, ymax float64)

DataRange returns the minimum and maximum X and Y values

func (*HStack) Plot added in v0.26.0

func (hstack *HStack) Plot(c draw.Canvas, p *plot.Plot)

Plot implements the Plotter interface, drawing a line that connects each point in the Line.

type HStackKind added in v0.26.0

type HStackKind int

HStackKind customizes how a HStack should behave.

const (
	// HStackOn instructs HStack to display histograms
	// stacked on top of each other.
	HStackOn HStackKind = iota
	// HStackOff instructs HStack to display histograms
	// with the stack disabled.
	HStackOff
)

type HorizLine added in v0.20.0

type HorizLine struct {
	Y      float64
	Line   draw.LineStyle
	Top    color.Color
	Bottom color.Color
}

HorizLine draws a horizontal line at Y and colors the top and bottom portions of the plot with the provided colors.

func HLine added in v0.20.0

func HLine(y float64, top, bottom color.Color) *HorizLine

HLine creates a horizontal line at y with the default line style.

Example

An example of making a horizontal-line plot

package main

import (
	"image/color"
	"log"

	"go-hep.org/x/hep/hplot"
	"gonum.org/v1/plot/vg"
)

func main() {
	p := hplot.New()
	p.Title.Text = "hlines"
	p.X.Min = 0
	p.X.Max = 10
	p.Y.Min = 0
	p.Y.Max = 10

	var (
		top    = color.RGBA{B: 255, A: 255}
		bottom = color.RGBA{R: 255, A: 255}
	)

	p.Add(
		hplot.HLine(2.5, nil, bottom),
		hplot.HLine(5, nil, nil),
		hplot.HLine(7.5, top, nil),
	)

	err := p.Save(10*vg.Centimeter, -1, "testdata/hline.png")
	if err != nil {
		log.Fatalf("error: %+v", err)
	}
}
Output:

func (*HorizLine) Plot added in v0.20.0

func (hline *HorizLine) Plot(c draw.Canvas, plt *plot.Plot)

func (*HorizLine) Thumbnail added in v0.25.0

func (hline *HorizLine) Thumbnail(c *draw.Canvas)

Thumbnail returns the thumbnail for the VertLine, implementing the plot.Thumbnailer interface.

type Label added in v0.28.4

type Label struct {
	Text      string         // Text of the label
	X, Y      float64        // Position of the label
	TextStyle draw.TextStyle // Text style of the label

	// Normalized indicates whether the label position
	// is in data coordinates or normalized with regard
	// to the canvas space.
	// When normalized, the label position is assumed
	// to fall in the [0, 1] interval. If true, NewLabel
	// panics if x or y are outside [0, 1].
	//
	// Normalized is false by default.
	Normalized bool

	// AutoAdjust enables auto adjustment of the label
	// position, when Normalized is true and when x
	// and/or y are close to 1 and the label is partly
	// outside the canvas. If false and the label doesn't
	// fit in the canvas, an error is returned.
	//
	// AutoAdjust is false by default.
	AutoAdjust bool
	// contains filtered or unexported fields
}

Label displays a user-defined text string on a plot.

Fields of Label should not be modified once the Label has been added to an hplot.Plot.

Example
package main

import (
	"log"

	xfnt "golang.org/x/image/font"
	"gonum.org/v1/plot/font"
	"gonum.org/v1/plot/plotter"
	"gonum.org/v1/plot/plotutil"
	"gonum.org/v1/plot/text"
	"gonum.org/v1/plot/vg"

	"go-hep.org/x/hep/hplot"
)

func main() {

	// Creating a new plot
	p := hplot.New()
	p.Title.Text = "Plot labels"
	p.X.Min = -10
	p.X.Max = +10
	p.Y.Min = -10
	p.Y.Max = +10

	// Default labels
	l1 := hplot.NewLabel(-8, 5, "(-8,5)\nDefault label")
	p.Add(l1)

	// Label with normalized coordinates.
	l3 := hplot.NewLabel(
		0.5, 0.5,
		"(0.5,0.5)\nLabel with relative coords",
		hplot.WithLabelNormalized(true),
	)
	p.Add(l3)

	// Label with normalized coordinates and auto-adjustement.
	l4 := hplot.NewLabel(
		0.95, 0.95,
		"(0.95,0.95)\nLabel at the canvas edge, with AutoAdjust",
		hplot.WithLabelNormalized(true),
		hplot.WithLabelAutoAdjust(true),
	)
	p.Add(l4)

	// Label with a customed TextStyle
	usrFont := font.Font{
		Typeface: "Liberation",
		Variant:  "Mono",
		Weight:   xfnt.WeightBold,
		Style:    xfnt.StyleNormal,
		Size:     12,
	}
	sty := text.Style{
		Color: plotutil.Color(2),
		Font:  usrFont,
	}
	l5 := hplot.NewLabel(
		0.0, 0.1,
		"(0.0,0.1)\nLabel with a user-defined font",
		hplot.WithLabelTextStyle(sty),
		hplot.WithLabelNormalized(true),
	)
	p.Add(l5)

	p.Add(plotter.NewGlyphBoxes())
	p.Add(hplot.NewGrid())

	// Save the plot to a PNG file.
	err := p.Save(15*vg.Centimeter, -1, "testdata/label_plot.png")
	if err != nil {
		log.Fatalf("error saving plot: %v\n", err)
	}
}
Output:

func NewLabel added in v0.28.4

func NewLabel(x, y float64, txt string, opts ...LabelOption) *Label

NewLabel creates a new txt label at position (x, y).

func (*Label) DataRange added in v0.28.4

func (lbl *Label) DataRange() (xmin, xmax, ymin, ymax float64)

DataRange returns the minimum and maximum x and y values, implementing the plot.DataRanger interface.

func (*Label) GlyphBoxes added in v0.28.4

func (lbl *Label) GlyphBoxes(p *plot.Plot) []plot.GlyphBox

GlyphBoxes returns a GlyphBox, corresponding to the label. GlyphBoxes implements the plot.GlyphBoxer interface.

func (*Label) Plot added in v0.28.4

func (lbl *Label) Plot(c draw.Canvas, p *plot.Plot)

Plot implements the Plotter interface, drawing the label on the canvas.

type LabelOption added in v0.28.4

type LabelOption func(cfg *labelConfig)

LabelOption handles various options to configure a Label.

func WithLabelAutoAdjust added in v0.28.4

func WithLabelAutoAdjust(auto bool) LabelOption

WithLabelAutoAdjust specifies whether the coordinates are automatically adjusted to the canvas size.

func WithLabelNormalized added in v0.28.4

func WithLabelNormalized(norm bool) LabelOption

WithLabelNormalized specifies whether the coordinates are normalized to the canvas size.

func WithLabelTextStyle added in v0.28.4

func WithLabelTextStyle(style draw.TextStyle) LabelOption

WithLabelTextStyle specifies the text style of the label.

type Legend added in v0.34.0

type Legend = plot.Legend

A Legend gives a description of the meaning of different data elements of the plot. Each legend entry has a name and a thumbnail, where the thumbnail shows a small sample of the display style of the corresponding data.

func NewLegend added in v0.34.0

func NewLegend() Legend

NewLegend returns a legend with the default parameter settings.

type NoTicks

type NoTicks struct{}

NoTicks implements plot.Ticker but does not display any tick.

func (NoTicks) Ticks

func (NoTicks) Ticks(min, max float64) []plot.Tick

Ticks returns Ticks in a specified range

type Options

type Options func(cfg *config)

Options encodes various options to pass to a plot.

func WithBand added in v0.20.0

func WithBand(v bool) Options

WithBand enables or disables the display of a colored band between Y-error bars.

func WithGlyphStyle added in v0.26.0

func WithGlyphStyle(sty draw.GlyphStyle) Options

WithGlyphStyle sets the glyph style of a plotter.

func WithHInfo added in v0.25.0

func WithHInfo(v HInfoStyle) Options

WithHInfo sets a given histogram info style.

func WithLogY added in v0.25.0

func WithLogY(v bool) Options

WithLogY sets whether the plotter in Y should handle log-scale.

func WithStepsKind added in v0.27.0

func WithStepsKind(s StepsKind) Options

WithStepsKind sets the style of the connecting line (NoSteps, HiSteps, etc...)

func WithXErrBars

func WithXErrBars(v bool) Options

WithXErrBars enables or disables the display of X-error bars.

func WithYErrBars

func WithYErrBars(v bool) Options

WithYErrBars enables or disables the display of Y-error bars.

type Plot

type Plot struct {
	*plot.Plot
	Style Style
}

Plot is the basic type representing a plot.

func New

func New() *Plot

New returns a new plot with some reasonable default settings.

func (*Plot) Add

func (p *Plot) Add(ps ...plot.Plotter)

Add adds a Plotters to the plot.

If the plotters implements DataRanger then the minimum and maximum values of the X and Y axes are changed if necessary to fit the range of the data.

When drawing the plot, Plotters are drawn in the order in which they were added to the plot.

func (*Plot) Draw added in v0.26.0

func (p *Plot) Draw(dc draw.Canvas)

Draw draws a plot to a draw.Canvas.

Plotters are drawn in the order in which they were added to the plot. Plotters that implement the GlyphBoxer interface will have their GlyphBoxes taken into account when padding the plot so that none of their glyphs are clipped.

func (*Plot) Save

func (p *Plot) Save(w, h vg.Length, file string) error

Save saves the plot to an image file. The file format is determined by the extension.

Supported extensions are:

.eps, .jpg, .jpeg, .json, .pdf, .png, .svg, .tex, .tif and .tiff.

If w or h are <= 0, the value is chosen such that it follows the Golden Ratio. If w and h are <= 0, the values are chosen such that they follow the Golden Ratio (the width is defaulted to vgimg.DefaultWidth).

func (*Plot) WriterTo added in v0.26.0

func (p *Plot) WriterTo(w, h vg.Length, format string) (io.WriterTo, error)

WriterTo returns an io.WriterTo that will write the plot as the specified image format.

Supported formats are:

eps, jpg|jpeg, pdf, png, svg, tex and tif|tiff.

type RatioPlot added in v0.27.0

type RatioPlot struct {
	Top    *Plot
	Bottom *Plot

	// Tiles controls the layout of the 2x1 ratio-plot grid.
	// Tiles can be used to customize the padding between plots.
	Tiles draw.Tiles

	// Ratio controls how the vertical space is partioned between
	// the top and bottom plots.
	// The top plot will take (1-ratio)*height.
	// Default is 0.3.
	Ratio float64
}
Example
package main

import (
	"image/color"
	"log"
	"math"

	"go-hep.org/x/hep/hbook"
	"go-hep.org/x/hep/hplot"
	"golang.org/x/exp/rand"
	"gonum.org/v1/gonum/stat/distuv"
	"gonum.org/v1/plot/vg"
)

func main() {

	const npoints = 10000

	// Create a normal distribution.
	dist := distuv.Normal{
		Mu:    0,
		Sigma: 1,
		Src:   rand.New(rand.NewSource(0)),
	}

	hist1 := hbook.NewH1D(20, -4, +4)
	hist2 := hbook.NewH1D(20, -4, +4)

	for i := 0; i < npoints; i++ {
		v1 := dist.Rand() - 0.5
		v2 := dist.Rand() + 0.5
		hist1.Fill(v1, 1)
		hist2.Fill(v2, 1)
	}

	rp := hplot.NewRatioPlot()
	rp.Ratio = 0.3

	// Make a plot and set its title.
	rp.Top.Title.Text = "Histos"
	rp.Top.Y.Label.Text = "Y"

	// Create a histogram of our values drawn
	// from the standard normal.
	h1 := hplot.NewH1D(hist1)
	h1.FillColor = color.NRGBA{R: 255, A: 100}
	rp.Top.Add(h1)

	h2 := hplot.NewH1D(hist2)
	h2.FillColor = color.NRGBA{B: 255, A: 100}
	rp.Top.Add(h2)

	rp.Top.Add(hplot.NewGrid())

	hist3 := hbook.NewH1D(20, -4, +4)
	for i := 0; i < hist3.Len(); i++ {
		v1 := hist1.Value(i)
		v2 := hist2.Value(i)
		x1, _ := hist1.XY(i)
		hist3.Fill(x1, v1-v2)
	}

	hdiff := hplot.NewH1D(hist3)

	rp.Bottom.X.Label.Text = "X"
	rp.Bottom.Y.Label.Text = "Delta-Y"
	rp.Bottom.Add(hdiff)
	rp.Bottom.Add(hplot.NewGrid())

	const (
		width  = 15 * vg.Centimeter
		height = width / math.Phi
	)

	err := hplot.Save(rp, width, height, "testdata/diff_plot.png")
	if err != nil {
		log.Fatalf("error: %v\n", err)
	}
}
Output:

func NewRatioPlot added in v0.27.0

func NewRatioPlot() *RatioPlot

func (*RatioPlot) Draw added in v0.27.0

func (rp *RatioPlot) Draw(dc draw.Canvas)

Draw draws a ratio plot to a draw.Canvas.

Plotters are drawn in the order in which they were added to the plot. Plotters that implement the GlyphBoxer interface will have their GlyphBoxes taken into account when padding the plot so that none of their glyphs are clipped.

type S2D

type S2D struct {
	Data plotter.XYer

	// GlyphStyle is the style of the glyphs drawn
	// at each point.
	draw.GlyphStyle

	// LineStyle is the style of the line drawn
	// connecting each point.
	// Use zero width to disable.
	LineStyle draw.LineStyle

	// XErrs is the x error bars plotter.
	XErrs *plotter.XErrorBars

	// YErrs is the y error bars plotter.
	YErrs *plotter.YErrorBars

	// Band displays a colored band between the y-min and y-max error bars.
	Band *Band

	// Steps controls the style of the connecting
	// line (NoSteps, HiSteps, etc...)
	Steps StepsKind
}

S2D plots a set of 2-dim points with error bars.

Example

ExampleS2D draws some scatter points.

package main

import (
	"image/color"
	"log"

	"go-hep.org/x/hep/hbook"
	"go-hep.org/x/hep/hplot"
	"golang.org/x/exp/rand"
	"gonum.org/v1/gonum/mat"
	"gonum.org/v1/gonum/stat/distmv"
	"gonum.org/v1/plot/plotter"
	"gonum.org/v1/plot/vg"
)

func main() {
	const npoints = 1000

	dist, ok := distmv.NewNormal(
		[]float64{0, 1},
		mat.NewSymDense(2, []float64{4, 0, 0, 2}),
		rand.New(rand.NewSource(1234)),
	)
	if !ok {
		log.Fatalf("error creating distmv.Normal")
	}

	s2d := hbook.NewS2D()

	v := make([]float64, 2)
	// Draw some random values from the standard
	// normal distribution.
	for i := 0; i < npoints; i++ {
		v = dist.Rand(v)
		s2d.Fill(hbook.Point2D{X: v[0], Y: v[1]})
	}

	p := hplot.New()
	p.Title.Text = "Scatter-2D"
	p.X.Label.Text = "X"
	p.Y.Label.Text = "Y"
	p.Add(plotter.NewGrid())

	s := hplot.NewS2D(s2d)
	s.GlyphStyle.Color = color.RGBA{R: 255, A: 255}
	s.GlyphStyle.Radius = vg.Points(2)

	p.Add(s)

	err := p.Save(10*vg.Centimeter, 10*vg.Centimeter, "testdata/s2d.png")
	if err != nil {
		log.Fatal(err)
	}
}
Output:

Example (WithBand)

ExampleS2D_withBand draws some scatter points with their error bars and a band

package main

import (
	"image/color"
	"log"

	"go-hep.org/x/hep/hbook"
	"go-hep.org/x/hep/hplot"
	"gonum.org/v1/plot/plotter"
	"gonum.org/v1/plot/plotutil"
	"gonum.org/v1/plot/vg"
)

func main() {
	pts := []hbook.Point2D{
		{X: 1, Y: 1, ErrY: hbook.Range{Min: 2, Max: 3}},
		{X: 2, Y: 2, ErrY: hbook.Range{Min: 5, Max: 2}},
		{X: 3, Y: 3, ErrY: hbook.Range{Min: 2, Max: 2}},
		{X: 4, Y: 4, ErrY: hbook.Range{Min: 1.2, Max: 2}},
	}
	s2d := hbook.NewS2D(pts...)

	p := hplot.New()
	p.Title.Text = "Scatter-2D (with band)"
	p.X.Label.Text = "X"
	p.Y.Label.Text = "Y"
	p.Add(plotter.NewGrid())

	s := hplot.NewS2D(s2d, hplot.WithBand(true), hplot.WithYErrBars(true))
	s.GlyphStyle.Color = color.Black
	s.GlyphStyle.Radius = vg.Points(4)
	s.LineStyle.Width = 1
	s.LineStyle.Dashes = plotutil.Dashes(2)

	p.Add(s)
	p.Legend.Add("s2d", s)

	err := p.Save(10*vg.Centimeter, 10*vg.Centimeter, "testdata/s2d_band.png")
	if err != nil {
		log.Fatal(err)
	}
}
Output:

Example (WithErrorBars)

ExampleS2D_withErrorBars draws some scatter points with their error bars.

package main

import (
	"image/color"
	"log"

	"go-hep.org/x/hep/hbook"
	"go-hep.org/x/hep/hplot"
	"gonum.org/v1/plot/plotter"
	"gonum.org/v1/plot/vg"
	"gonum.org/v1/plot/vg/draw"
)

func main() {
	pts := []hbook.Point2D{
		{X: 1, Y: 1, ErrX: hbook.Range{Min: 0.5, Max: 0.5}, ErrY: hbook.Range{Min: 2, Max: 3}},
		{X: 2, Y: 2, ErrX: hbook.Range{Min: 0.5, Max: 1.5}, ErrY: hbook.Range{Min: 5, Max: 2}},
	}
	s2d := hbook.NewS2D(pts...)

	p := hplot.New()
	p.Title.Text = "Scatter-2D (with error bars)"
	p.X.Label.Text = "X"
	p.Y.Label.Text = "Y"
	p.Add(plotter.NewGrid())

	s := hplot.NewS2D(s2d,
		hplot.WithXErrBars(true),
		hplot.WithYErrBars(true),
		hplot.WithGlyphStyle(draw.GlyphStyle{
			Color:  color.RGBA{R: 255, A: 255},
			Radius: vg.Points(4),
			Shape:  draw.CrossGlyph{},
		}),
	)

	p.Add(s)
	p.Legend.Add("s2d", s)

	err := p.Save(10*vg.Centimeter, 10*vg.Centimeter, "testdata/s2d_errbars.png")
	if err != nil {
		log.Fatal(err)
	}
}
Output:

Example (WithStepsKind)

ExampleS2D_withStepsKind draws some scatter points with their error bars, using a step-like style

package main

import (
	"image/color"
	"log"

	"go-hep.org/x/hep/hbook"
	"go-hep.org/x/hep/hplot"
	"gonum.org/v1/plot/plotter"
	"gonum.org/v1/plot/plotutil"
	"gonum.org/v1/plot/vg"
)

func main() {
	pts := []hbook.Point2D{
		{X: 1, ErrX: hbook.Range{Min: 0.5, Max: 0.5}, Y: 1, ErrY: hbook.Range{Min: 2, Max: 3}},
		{X: 2, ErrX: hbook.Range{Min: 0.5, Max: 0.5}, Y: 2, ErrY: hbook.Range{Min: 5, Max: 2}},
		{X: 3, ErrX: hbook.Range{Min: 0.5, Max: 0.5}, Y: 3, ErrY: hbook.Range{Min: 2, Max: 2}},
		{X: 4, ErrX: hbook.Range{Min: 0.5, Max: 0.5}, Y: 4, ErrY: hbook.Range{Min: 1.2, Max: 2}},
	}
	s2d := hbook.NewS2D(pts...)

	p := hplot.New()
	p.Title.Text = "Scatter-2D (with steps)"
	p.X.Label.Text = "X"
	p.Y.Label.Text = "Y"
	p.Add(plotter.NewGrid())

	s := hplot.NewS2D(s2d, hplot.WithStepsKind(hplot.HiSteps), hplot.WithYErrBars(true))
	s.GlyphStyle.Color = color.Black
	s.GlyphStyle.Radius = vg.Points(4)
	s.LineStyle.Width = 1
	s.LineStyle.Dashes = plotutil.Dashes(2)

	p.Add(s)

	err := p.Save(10*vg.Centimeter, 10*vg.Centimeter, "testdata/s2d_steps.png")
	if err != nil {
		log.Fatal(err)
	}
}
Output:

Example (WithStepsKind_withBand)

ExampleS2D_withSteps_withBand draws some scatter points with their error bars, using a step-like style together with a band

package main

import (
	"image/color"
	"log"

	"go-hep.org/x/hep/hbook"
	"go-hep.org/x/hep/hplot"
	"gonum.org/v1/plot/plotter"
	"gonum.org/v1/plot/plotutil"
	"gonum.org/v1/plot/vg"
)

func main() {
	pts := []hbook.Point2D{
		{X: 1, ErrX: hbook.Range{Min: 0.5, Max: 0.5}, Y: 1, ErrY: hbook.Range{Min: 2, Max: 3}},
		{X: 2, ErrX: hbook.Range{Min: 0.5, Max: 0.5}, Y: 5, ErrY: hbook.Range{Min: 5, Max: 2}},
		{X: 3, ErrX: hbook.Range{Min: 0.5, Max: 0.5}, Y: 10, ErrY: hbook.Range{Min: 2, Max: 2}},
		{X: 4, ErrX: hbook.Range{Min: 0.5, Max: 0.5}, Y: 15, ErrY: hbook.Range{Min: 1.2, Max: 2}},
	}
	s2d := hbook.NewS2D(pts...)

	p := hplot.New()
	p.Title.Text = "Scatter-2D (with steps and band)"
	p.X.Label.Text = "X"
	p.Y.Label.Text = "Y"
	p.Add(plotter.NewGrid())

	s := hplot.NewS2D(s2d, hplot.WithStepsKind(hplot.HiSteps), hplot.WithYErrBars(true), hplot.WithBand(true))
	s.GlyphStyle.Color = color.Black
	s.GlyphStyle.Radius = vg.Points(4)
	s.LineStyle.Width = 1
	s.LineStyle.Dashes = plotutil.Dashes(2)

	p.Add(s)

	err := p.Save(10*vg.Centimeter, 10*vg.Centimeter, "testdata/s2d_steps_band.png")
	if err != nil {
		log.Fatal(err)
	}
}
Output:

func NewS2D

func NewS2D(data plotter.XYer, opts ...Options) *S2D

NewS2D creates a 2-dim scatter plot from a XYer.

func (*S2D) DataRange

func (pts *S2D) DataRange() (xmin, xmax, ymin, ymax float64)

DataRange returns the minimum and maximum x and y values, implementing the plot.DataRanger interface.

func (*S2D) GlyphBoxes

func (pts *S2D) GlyphBoxes(plt *plot.Plot) []plot.GlyphBox

GlyphBoxes returns a slice of plot.GlyphBoxes, implementing the plot.GlyphBoxer interface.

func (*S2D) Plot

func (pts *S2D) Plot(c draw.Canvas, plt *plot.Plot)

Plot draws the Scatter, implementing the plot.Plotter interface.

func (*S2D) Thumbnail

func (pts *S2D) Thumbnail(c *draw.Canvas)

Thumbnail the thumbnail for the Scatter, implementing the plot.Thumbnailer interface.

type StepsKind added in v0.27.0

type StepsKind byte

Step kind

const (
	NoSteps StepsKind = iota
	HiSteps
)

type Style

type Style struct {
	Fonts struct {
		Name    string    // font name of this style
		Default font.Font // font used for the plot
		Title   font.Font // font used for the plot title
		Label   font.Font // font used for the plot labels
		Legend  font.Font // font used for the plot legend
		Tick    font.Font // font used for the plot's axes' ticks

		Cache *font.Cache // cache of fonts for this plot.
	}
	TextHandler text.Handler
}

Style stores a given plot style.

var (
	// DefaultStyle is the default style used for hplot plots.
	DefaultStyle Style
)

func NewStyle

func NewStyle(fnt font.Font, cache *font.Cache) (Style, error)

NewStyle creates a new style with the given font cache.

func (*Style) Apply

func (s *Style) Apply(p *Plot)

Apply setups the plot p with the current style.

type Ticks added in v0.25.0

type Ticks struct {
	N int // N is the suggested number of major ticks to display.

	// Format is an optional major-tick formatter.
	// If empty, a format will be automatically chosen.
	Format string
}

Ticks implements plot.Ticker. Ticks allows to specify the maximum number of major ticks to display. The zero value of Ticks display a maximum number of 3 major ticks.

Example
package main

import (
	"log"

	"go-hep.org/x/hep/hplot"
	"gonum.org/v1/plot/vg"
	"gonum.org/v1/plot/vg/draw"
)

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

	for i := 0; i < tp.Tiles.Rows; i++ {
		for j := 0; j < tp.Tiles.Cols; j++ {
			p := tp.Plot(j, i)
			switch i {
			case 0:
				p.X.Min = 0
				p.X.Max = 1
				switch j {
				case 0:
					p.Title.Text = "hplot.Ticks"
				default:
					p.Title.Text = "plot.Ticks"
				}
			case 1:
				p.X.Min = 0
				p.X.Max = 10
			case 2:
				p.X.Min = 0
				p.X.Max = 100
			case 3:
				p.X.Min = 0
				p.X.Max = 1000
			case 4:
				p.X.Min = 0
				p.X.Max = 10000
			case 5:
				p.X.Min = 0
				p.X.Max = 10000
			case 6:
				p.X.Min = 0
				p.X.Max = 1.2
			case 7:
				p.X.Min = 0
				p.X.Max = 120
			}
			if j == 0 {
				var (
					n    = 10
					xfmt = ""
				)
				switch i {
				case 4:
					n = 5
				case 5:
					n = 5
					xfmt = "%g"
				}
				p.X.Tick.Marker = hplot.Ticks{N: n, Format: xfmt}
			}
			p.Add(hplot.NewGrid())
		}
	}

	const sz = 20 * vg.Centimeter
	err := tp.Save(sz, sz, "testdata/ticks.png")
	if err != nil {
		log.Fatalf("error: %+v\n", err)
	}
}
Output:

Example (Daily)
package main

import (
	"image/color"
	"log"
	"time"

	"git.sr.ht/~sbinet/epok"
	"go-hep.org/x/hep/hplot"
	"gonum.org/v1/plot/plotter"
	"gonum.org/v1/plot/vg"
	"gonum.org/v1/plot/vg/draw"
)

func main() {
	cnv := epok.UTCUnixTimeConverter{}

	p := hplot.New()
	p.Title.Text = "Time series (daily)"
	p.Y.Label.Text = "Goroutines"

	p.Y.Min = 0
	p.Y.Max = 4
	p.X.AutoRescale = true
	p.X.Tick.Marker = epok.Ticks{
		Ruler: epok.Rules{
			Major: epok.Rule{
				Freq:  epok.Daily,
				Range: epok.RangeFrom(1, 29, 14),
			},
			Minor: epok.Rule{
				Freq:  epok.Daily,
				Range: epok.RangeFrom(1, 32, 1),
			},
		},
		Format:    "2006\nJan-02\n15:04:05",
		Converter: cnv,
	}

	xysFrom := func(vs ...float64) plotter.XYs {
		o := make(plotter.XYs, len(vs))
		for i := range o {
			o[i].X = vs[i]
			o[i].Y = float64(i + 1)
		}
		return o
	}
	data := xysFrom(
		cnv.FromTime(parse("2020-01-01 01:02:03")),
		cnv.FromTime(parse("2020-01-02 02:03:04")),
		cnv.FromTime(parse("2020-01-12 03:04:05")),
		cnv.FromTime(parse("2020-01-22 04:05:06")),
		cnv.FromTime(parse("2020-02-03 05:06:07")),
		cnv.FromTime(parse("2020-02-13 06:07:08")),
		cnv.FromTime(parse("2020-02-23 07:08:09")),
		cnv.FromTime(parse("2020-03-01 00:00:00")),
	)

	line, pnts, err := hplot.NewLinePoints(data)
	if err != nil {
		log.Fatalf("could not create plotter: %+v", err)
	}

	line.Color = color.RGBA{B: 255, A: 255}
	pnts.Shape = draw.CircleGlyph{}
	pnts.Color = color.RGBA{R: 255, A: 255}

	p.Add(line, pnts, hplot.NewGrid())

	err = p.Save(20*vg.Centimeter, 10*vg.Centimeter, "testdata/timeseries_daily.png")
	if err != nil {
		log.Fatalf("could not save plot: %+v", err)
	}
}

func parse(vs ...string) time.Time {
	format := "2006-01-02 15:04:05"
	if len(vs) > 1 {
		format = vs[1]
	}
	t, err := time.Parse(format, vs[0])
	if err != nil {
		panic(err)
	}
	return t
}
Output:

Example (Monthly)
package main

import (
	"image/color"
	"log"
	"time"

	"git.sr.ht/~sbinet/epok"
	"go-hep.org/x/hep/hplot"
	"gonum.org/v1/plot/plotter"
	"gonum.org/v1/plot/vg"
	"gonum.org/v1/plot/vg/draw"
)

func main() {
	cnv := epok.UTCUnixTimeConverter{}

	p := hplot.New()
	p.Title.Text = "Time series (monthly)"
	p.Y.Label.Text = "Goroutines"

	p.Y.Min = 0
	p.Y.Max = 4
	p.X.AutoRescale = true
	p.X.Tick.Marker = epok.Ticks{
		Ruler: epok.Rules{
			Major: epok.Rule{
				Freq:  epok.Monthly,
				Range: epok.RangeFrom(1, 13, 2),
			},
		},
		Format:    "2006\nJan-02\n15:04:05",
		Converter: cnv,
	}

	xysFrom := func(vs ...float64) plotter.XYs {
		o := make(plotter.XYs, len(vs))
		for i := range o {
			o[i].X = vs[i]
			o[i].Y = float64(i + 1)
		}
		return o
	}
	data := xysFrom(
		cnv.FromTime(parse("2010-01-02 01:02:03")),
		cnv.FromTime(parse("2010-02-01 01:02:03")),
		cnv.FromTime(parse("2010-02-04 11:22:33")),
		cnv.FromTime(parse("2010-03-04 01:02:03")),
		cnv.FromTime(parse("2010-04-05 01:02:03")),
		cnv.FromTime(parse("2010-04-05 01:02:03")),
		cnv.FromTime(parse("2010-05-01 00:02:03")),
		cnv.FromTime(parse("2010-05-04 04:04:04")),
		cnv.FromTime(parse("2010-05-08 11:12:13")),
		cnv.FromTime(parse("2010-06-15 01:02:03")),
		cnv.FromTime(parse("2010-07-04 04:04:43")),
		cnv.FromTime(parse("2010-07-14 14:17:09")),
		cnv.FromTime(parse("2010-08-04 21:22:23")),
		cnv.FromTime(parse("2010-08-15 11:12:13")),
		cnv.FromTime(parse("2010-09-01 21:52:53")),
		cnv.FromTime(parse("2010-10-25 01:19:23")),
		cnv.FromTime(parse("2010-11-30 11:32:53")),
		cnv.FromTime(parse("2010-12-24 23:59:59")),
		cnv.FromTime(parse("2010-12-31 23:59:59")),
		cnv.FromTime(parse("2011-01-12 01:02:03")),
	)

	line, pnts, err := hplot.NewLinePoints(data)
	if err != nil {
		log.Fatalf("could not create plotter: %+v", err)
	}

	line.Color = color.RGBA{B: 255, A: 255}
	pnts.Shape = draw.CircleGlyph{}
	pnts.Color = color.RGBA{R: 255, A: 255}

	p.Add(line, pnts, hplot.NewGrid())

	err = p.Save(20*vg.Centimeter, 10*vg.Centimeter, "testdata/timeseries_monthly.png")
	if err != nil {
		log.Fatalf("could not save plot: %+v", err)
	}
}

func parse(vs ...string) time.Time {
	format := "2006-01-02 15:04:05"
	if len(vs) > 1 {
		format = vs[1]
	}
	t, err := time.Parse(format, vs[0])
	if err != nil {
		panic(err)
	}
	return t
}
Output:

Example (Yearly)
package main

import (
	"image/color"
	"log"
	"time"

	"git.sr.ht/~sbinet/epok"
	"go-hep.org/x/hep/hplot"
	"gonum.org/v1/plot/plotter"
	"gonum.org/v1/plot/vg"
	"gonum.org/v1/plot/vg/draw"
)

func main() {
	cnv := epok.UTCUnixTimeConverter{}

	p := hplot.New()
	p.Title.Text = "Time series (yearly)"
	p.Y.Label.Text = "Goroutines"

	p.Y.Min = 0
	p.Y.Max = 4
	p.X.AutoRescale = true
	p.X.Tick.Marker = epok.Ticks{
		Ruler: epok.Rules{
			Major: epok.Rule{
				Freq:  epok.Yearly,
				Range: epok.Range{Step: 5},
			},
		},
		Format:    "2006-01-02\n15:04:05",
		Converter: cnv,
	}

	xysFrom := func(vs ...float64) plotter.XYs {
		o := make(plotter.XYs, len(vs))
		for i := range o {
			o[i].X = vs[i]
			o[i].Y = float64(i + 1)
		}
		return o
	}
	data := xysFrom(
		cnv.FromTime(parse("2010-02-03 01:02:03")),
		cnv.FromTime(parse("2011-03-04 11:22:33")),
		cnv.FromTime(parse("2015-02-03 04:05:06")),
		cnv.FromTime(parse("2020-02-03 07:08:09")),
	)

	line, pnts, err := hplot.NewLinePoints(data)
	if err != nil {
		log.Fatalf("could not create plotter: %+v", err)
	}

	line.Color = color.RGBA{B: 255, A: 255}
	pnts.Shape = draw.CircleGlyph{}
	pnts.Color = color.RGBA{R: 255, A: 255}

	p.Add(line, pnts, hplot.NewGrid())

	err = p.Save(20*vg.Centimeter, 10*vg.Centimeter, "testdata/timeseries_yearly.png")
	if err != nil {
		log.Fatalf("could not save plot: %+v", err)
	}
}

func parse(vs ...string) time.Time {
	format := "2006-01-02 15:04:05"
	if len(vs) > 1 {
		format = vs[1]
	}
	t, err := time.Parse(format, vs[0])
	if err != nil {
		panic(err)
	}
	return t
}
Output:

func (Ticks) Ticks added in v0.25.0

func (tck Ticks) Ticks(min, max float64) []plot.Tick

type TiledPlot

type TiledPlot struct {
	Plots []*Plot
	Tiles draw.Tiles
	Align bool // whether to align all tiles axes
}

TiledPlot is a regularly spaced set of plots, aranged as tiles.

Example

An example of making a tile-plot

package main

import (
	"fmt"
	"log"

	"go-hep.org/x/hep/hbook"
	"go-hep.org/x/hep/hplot"
	"golang.org/x/exp/rand"
	"gonum.org/v1/gonum/stat/distuv"
	"gonum.org/v1/plot/vg"
	"gonum.org/v1/plot/vg/draw"
)

func main() {
	tp := hplot.NewTiledPlot(draw.Tiles{Cols: 3, Rows: 2})

	// Create a normal distribution.
	dist := distuv.Normal{
		Mu:    0,
		Sigma: 1,
		Src:   rand.New(rand.NewSource(0)),
	}

	newHist := func(p *hplot.Plot) {
		const npoints = 10000
		hist := hbook.NewH1D(20, -4, +4)
		for i := 0; i < npoints; i++ {
			v := dist.Rand()
			hist.Fill(v, 1)
		}

		h := hplot.NewH1D(hist)
		p.Add(h)
	}

	for i := 0; i < tp.Tiles.Rows; i++ {
		for j := 0; j < tp.Tiles.Cols; j++ {
			p := tp.Plot(j, i)
			p.X.Min = -5
			p.X.Max = +5
			newHist(p)
			p.Title.Text = fmt.Sprintf("hist - (%02d, %02d)", j, i)
		}
	}

	// remove plot at (1,0)
	tp.Plots[1] = nil

	err := tp.Save(15*vg.Centimeter, -1, "testdata/tiled_plot_histogram.png")
	if err != nil {
		log.Fatalf("error: %+v\n", err)
	}
}
Output:

Example (Align)

An example of making aligned tile-plots

package main

import (
	"fmt"
	"image/color"
	"log"
	"math"

	"go-hep.org/x/hep/hbook"
	"go-hep.org/x/hep/hplot"
	"gonum.org/v1/plot/vg"
	"gonum.org/v1/plot/vg/draw"
)

func main() {
	tp := hplot.NewTiledPlot(draw.Tiles{
		Cols: 3, Rows: 3,
		PadX: 20, PadY: 20,
	})
	tp.Align = true

	points := func(i, j int) []hbook.Point2D {
		n := i*tp.Tiles.Cols + j + 1
		i += 1
		j = int(math.Pow(10, float64(n)))

		var pts []hbook.Point2D
		for ii := 0; ii < 10; ii++ {
			pts = append(pts, hbook.Point2D{
				X: float64(i + ii),
				Y: float64(j + ii + 1),
			})
		}
		return pts

	}

	for i := 0; i < tp.Tiles.Rows; i++ {
		for j := 0; j < tp.Tiles.Cols; j++ {
			p := tp.Plot(j, i)
			p.X.Min = -5
			p.X.Max = +5
			s := hplot.NewS2D(hbook.NewS2D(points(i, j)...))
			s.GlyphStyle.Color = color.RGBA{R: 255, A: 255}
			s.GlyphStyle.Radius = vg.Points(4)
			p.Add(s)

			p.Title.Text = fmt.Sprintf("hist - (%02d, %02d)", j, i)
		}
	}

	// remove plot at (1,1)
	tp.Plots[4] = nil

	err := tp.Save(15*vg.Centimeter, -1, "testdata/tiled_plot_aligned_histogram.png")
	if err != nil {
		log.Fatalf("error: %+v\n", err)
	}
}
Output:

func NewTiledPlot

func NewTiledPlot(tiles draw.Tiles) *TiledPlot

NewTiledPlot creates a new set of plots aranged as tiles. By default, NewTiledPlot will put a 1 vg.Length space between each plot.

func (*TiledPlot) Draw

func (tp *TiledPlot) Draw(c draw.Canvas)

Draw draws the tiled plot to a draw.Canvas.

Each non-nil plot.Plot in the aranged set of tiled plots is drawn inside its dedicated sub-canvas, using hplot.Plot.Draw.

func (*TiledPlot) Plot

func (tp *TiledPlot) Plot(i, j int) *Plot

Plot returns the plot at the i-th column and j-th row in the set of tiles. (0,0) is at the top-left of the set of tiles.

func (*TiledPlot) Save

func (tp *TiledPlot) Save(w, h vg.Length, file string) error

Save saves the plots to an image file. The file format is determined by the extension.

Supported extensions are the same ones than hplot.Save.

If w or h are <= 0, the value is chosen such that it follows the Golden Ratio. If w and h are <= 0, the values are chosen such that they follow the Golden Ratio (the width is defaulted to vgimg.DefaultWidth).

type VertLine added in v0.20.0

type VertLine struct {
	X     float64
	Line  draw.LineStyle
	Left  color.Color
	Right color.Color
}

VertLine draws a vertical line at X and colors the left and right portions of the plot with the provided colors.

func VLine added in v0.20.0

func VLine(x float64, left, right color.Color) *VertLine

VLine creates a vertical line at x with the default line style.

Example

An example of making a vertical-line plot

package main

import (
	"image/color"
	"log"

	"go-hep.org/x/hep/hplot"
	"gonum.org/v1/plot/vg"
)

func main() {
	p := hplot.New()
	p.Title.Text = "vlines"
	p.X.Min = 0
	p.X.Max = 10
	p.Y.Min = 0
	p.Y.Max = 10

	var (
		left  = color.RGBA{B: 255, A: 255}
		right = color.RGBA{R: 255, A: 255}
	)

	p.Add(
		hplot.VLine(2.5, left, nil),
		hplot.VLine(5, nil, nil),
		hplot.VLine(7.5, nil, right),
	)

	err := p.Save(10*vg.Centimeter, -1, "testdata/vline.png")
	if err != nil {
		log.Fatalf("error: %+v", err)
	}
}
Output:

func (*VertLine) Plot added in v0.20.0

func (vline *VertLine) Plot(c draw.Canvas, plt *plot.Plot)

func (*VertLine) Thumbnail added in v0.25.0

func (vline *VertLine) Thumbnail(c *draw.Canvas)

Thumbnail returns the thumbnail for the VertLine, implementing the plot.Thumbnailer interface.

Directories

Path Synopsis
cmd
hplot
hplot is a simple gnuplot-like command to create plots
hplot is a simple gnuplot-like command to create plots
internal
Package vgop provides tools to record a set of vector graphics operations.
Package vgop provides tools to record a set of vector graphics operations.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL