go-hep.org/x/hep@v0.38.1/hplot/README.md (about) 1 hplot 2 ==== 3 4 [](https://godoc.org/go-hep.org/x/hep/hplot) 5 6 `hplot` is a WIP package relying on `gonum/plot` to plot histograms, 7 n-tuples and functions. 8 9 ## Installation 10 11 ```sh 12 $ go get go-hep.org/x/hep/hplot 13 ``` 14 15 ## Documentation 16 17 Is available on ``godoc``: 18 19 https://godoc.org/go-hep.org/x/hep/hplot 20 21 22 ## Examples 23 24 ### 1D histogram 25 26  27 28 [embedmd]:# (h1d_example_test.go go /func ExampleH1D/ /\n}/) 29 ```go 30 func ExampleH1D() { 31 const npoints = 10000 32 33 // Create a normal distribution. 34 dist := distuv.Normal{ 35 Mu: 0, 36 Sigma: 1, 37 Src: rand.New(rand.NewPCG(0, 0)), 38 } 39 40 // Draw some random values from the standard 41 // normal distribution. 42 hist := hbook.NewH1D(20, -4, +4) 43 for range npoints { 44 v := dist.Rand() 45 hist.Fill(v, 1) 46 } 47 48 // normalize histogram 49 area := 0.0 50 for _, bin := range hist.Binning.Bins { 51 area += bin.SumW() * bin.XWidth() 52 } 53 hist.Scale(1 / area) 54 55 // Make a plot and set its title. 56 p := hplot.New() 57 p.Title.Text = "Histogram" 58 p.X.Label.Text = "X" 59 p.Y.Label.Text = "Y" 60 61 // Create a histogram of our values drawn 62 // from the standard normal. 63 h := hplot.NewH1D(hist) 64 h.Infos.Style = hplot.HInfoSummary 65 p.Add(h) 66 67 // The normal distribution function 68 norm := hplot.NewFunction(dist.Prob) 69 norm.Color = color.RGBA{R: 255, A: 255} 70 norm.Width = vg.Points(2) 71 p.Add(norm) 72 73 // draw a grid 74 p.Add(hplot.NewGrid()) 75 76 // Save the plot to a PNG file. 77 if err := p.Save(6*vg.Inch, -1, "testdata/h1d_plot.png"); err != nil { 78 log.Fatalf("error saving plot: %v\n", err) 79 } 80 } 81 ``` 82 83 ### 1D histogram with y-error bars 84 85  86 87 [embedmd]:# (h1d_example_test.go go /func ExampleH1D_withYErrBars/ /\n}/) 88 ```go 89 func ExampleH1D_withYErrBars() { 90 const npoints = 100 91 92 // Create a normal distribution. 93 dist := distuv.Normal{ 94 Mu: 0, 95 Sigma: 1, 96 Src: rand.New(rand.NewPCG(0, 0)), 97 } 98 99 // Draw some random values from the standard 100 // normal distribution. 101 hist := hbook.NewH1D(20, -4, +4) 102 for range npoints { 103 v := dist.Rand() 104 hist.Fill(v, 1) 105 } 106 107 // normalize histogram 108 area := 0.0 109 for _, bin := range hist.Binning.Bins { 110 area += bin.SumW() * bin.XWidth() 111 } 112 hist.Scale(1 / area) 113 114 // Make a plot and set its title. 115 p := hplot.New() 116 p.Title.Text = "Histogram" 117 p.X.Label.Text = "X" 118 p.Y.Label.Text = "Y" 119 120 // Create a histogram of our values drawn 121 // from the standard normal. 122 h := hplot.NewH1D(hist, 123 hplot.WithHInfo(hplot.HInfoSummary), 124 hplot.WithYErrBars(true), 125 ) 126 h.YErrs.LineStyle.Color = color.RGBA{R: 255, A: 255} 127 p.Add(h) 128 129 // The normal distribution function 130 norm := hplot.NewFunction(dist.Prob) 131 norm.Color = color.RGBA{R: 255, A: 255} 132 norm.Width = vg.Points(2) 133 p.Add(norm) 134 135 // draw a grid 136 p.Add(hplot.NewGrid()) 137 138 // Save the plot to a PNG file. 139 if err := p.Save(6*vg.Inch, -1, "testdata/h1d_yerrs.png"); err != nil { 140 log.Fatalf("error saving plot: %v\n", err) 141 } 142 } 143 ``` 144 145 ### 1D histogram with y-error bars, no lines 146 147  148 149 [embedmd]:# (h1d_example_test.go go /func ExampleH1D_withYErrBarsAndData/ /\n}/) 150 ```go 151 func ExampleH1D_withYErrBarsAndData() { 152 const npoints = 100 153 154 // Create a normal distribution. 155 dist := distuv.Normal{ 156 Mu: 0, 157 Sigma: 1, 158 Src: rand.New(rand.NewPCG(0, 0)), 159 } 160 161 // Draw some random values from the standard 162 // normal distribution. 163 hist := hbook.NewH1D(20, -4, +4) 164 for range npoints { 165 v := dist.Rand() 166 hist.Fill(v, 1) 167 } 168 169 // normalize histogram 170 area := 0.0 171 for _, bin := range hist.Binning.Bins { 172 area += bin.SumW() * bin.XWidth() 173 } 174 hist.Scale(1 / area) 175 176 // Make a plot and set its title. 177 p := hplot.New() 178 p.Title.Text = "Histogram" 179 p.X.Label.Text = "X" 180 p.Y.Label.Text = "Y" 181 182 p.Legend.Top = true 183 p.Legend.Left = true 184 185 // Create a histogram of our values drawn 186 // from the standard normal. 187 h := hplot.NewH1D(hist, 188 hplot.WithHInfo(hplot.HInfoSummary), 189 hplot.WithYErrBars(true), 190 hplot.WithGlyphStyle(draw.GlyphStyle{ 191 Shape: draw.CrossGlyph{}, 192 Color: color.Black, 193 Radius: vg.Points(2), 194 }), 195 ) 196 h.GlyphStyle.Shape = draw.CircleGlyph{} 197 h.YErrs.LineStyle.Color = color.Black 198 h.LineStyle.Width = 0 // disable histogram lines 199 p.Add(h) 200 p.Legend.Add("data", h) 201 202 // The normal distribution function 203 norm := hplot.NewFunction(dist.Prob) 204 norm.Color = color.RGBA{R: 255, A: 255} 205 norm.Width = vg.Points(2) 206 p.Add(norm) 207 p.Legend.Add("model", norm) 208 209 // draw a grid 210 p.Add(hplot.NewGrid()) 211 212 // Save the plot to a PNG file. 213 if err := p.Save(6*vg.Inch, -1, "testdata/h1d_glyphs.png"); err != nil { 214 log.Fatalf("error saving plot: %v\n", err) 215 } 216 } 217 ``` 218 219 ### 1D histogram with y-error bars and error bands 220 221  222 223 [embedmd]:# (h1d_example_test.go go /func ExampleH1D_withYErrBars_withBand/ /\n}/) 224 ```go 225 func ExampleH1D_withYErrBars_withBand() { 226 const npoints = 100 227 228 // Create a normal distribution. 229 dist := distuv.Normal{ 230 Mu: 0, 231 Sigma: 1, 232 Src: rand.New(rand.NewPCG(0, 0)), 233 } 234 235 // Draw some random values from the standard 236 // normal distribution. 237 hist := hbook.NewH1D(20, -4, +4) 238 for range npoints { 239 v := dist.Rand() 240 hist.Fill(v, 1) 241 } 242 243 // normalize histogram 244 area := 0.0 245 for _, bin := range hist.Binning.Bins { 246 area += bin.SumW() * bin.XWidth() 247 } 248 hist.Scale(1 / area) 249 250 // Make a plot and set its title. 251 p := hplot.New() 252 p.Title.Text = "Histogram" 253 p.X.Label.Text = "X" 254 p.Y.Label.Text = "Y" 255 256 // Create a histogram of our values drawn 257 // from the standard normal. 258 h := hplot.NewH1D(hist, 259 hplot.WithHInfo(hplot.HInfoSummary), 260 hplot.WithYErrBars(true), 261 hplot.WithBand(true), 262 ) 263 h.YErrs.LineStyle.Color = color.RGBA{R: 255, A: 255} 264 p.Add(h) 265 266 // The normal distribution function 267 norm := hplot.NewFunction(dist.Prob) 268 norm.Color = color.RGBA{R: 255, A: 255} 269 norm.Width = vg.Points(2) 270 p.Add(norm) 271 272 // draw a grid 273 p.Add(hplot.NewGrid()) 274 275 // Save the plot to a PNG file. 276 if err := p.Save(6*vg.Inch, -1, "testdata/h1d_yerrs_band.png"); err != nil { 277 log.Fatalf("error saving plot: %v\n", err) 278 } 279 } 280 ``` 281 282 ### Tiles of 1D histograms 283 284  285 286 [embedmd]:# (tiledplot_example_test.go go /func ExampleTiledPlot/ /\n}/) 287 ```go 288 func ExampleTiledPlot() { 289 tp := hplot.NewTiledPlot(draw.Tiles{Cols: 3, Rows: 2}) 290 291 // Create a normal distribution. 292 dist := distuv.Normal{ 293 Mu: 0, 294 Sigma: 1, 295 Src: rand.New(rand.NewPCG(0, 0)), 296 } 297 298 newHist := func(p *hplot.Plot) { 299 const npoints = 10000 300 hist := hbook.NewH1D(20, -4, +4) 301 for range npoints { 302 v := dist.Rand() 303 hist.Fill(v, 1) 304 } 305 306 h := hplot.NewH1D(hist) 307 p.Add(h) 308 } 309 310 for i := range tp.Tiles.Rows { 311 for j := range tp.Tiles.Cols { 312 p := tp.Plot(j, i) 313 p.X.Min = -5 314 p.X.Max = +5 315 newHist(p) 316 p.Title.Text = fmt.Sprintf("hist - (%02d, %02d)", j, i) 317 } 318 } 319 320 // remove plot at (1,0) 321 tp.Plots[1] = nil 322 323 err := tp.Save(15*vg.Centimeter, -1, "testdata/tiled_plot_histogram.png") 324 if err != nil { 325 log.Fatalf("error: %+v\n", err) 326 } 327 } 328 ``` 329 330  331 332 [embedmd]:# (tiledplot_example_test.go go /func ExampleTiledPlot_align/ /\n}/) 333 ```go 334 func ExampleTiledPlot_align() { 335 tp := hplot.NewTiledPlot(draw.Tiles{ 336 Cols: 3, Rows: 3, 337 PadX: 20, PadY: 20, 338 }) 339 tp.Align = true 340 341 points := func(i, j int) []hbook.Point2D { 342 n := i*tp.Tiles.Cols + j + 1 343 i += 1 344 j = int(math.Pow(10, float64(n))) 345 346 var pts []hbook.Point2D 347 for ii := range 10 { 348 pts = append(pts, hbook.Point2D{ 349 X: float64(i + ii), 350 Y: float64(j + ii + 1), 351 }) 352 } 353 return pts 354 355 } 356 357 for i := range tp.Tiles.Rows { 358 for j := range tp.Tiles.Cols { 359 p := tp.Plot(j, i) 360 p.X.Min = -5 361 p.X.Max = +5 362 s := hplot.NewS2D(hbook.NewS2D(points(i, j)...)) 363 s.GlyphStyle.Color = color.RGBA{R: 255, A: 255} 364 s.GlyphStyle.Radius = vg.Points(4) 365 p.Add(s) 366 367 p.Title.Text = fmt.Sprintf("hist - (%02d, %02d)", j, i) 368 } 369 } 370 371 // remove plot at (1,1) 372 tp.Plots[4] = nil 373 374 err := tp.Save(15*vg.Centimeter, -1, "testdata/tiled_plot_aligned_histogram.png") 375 if err != nil { 376 log.Fatalf("error: %+v\n", err) 377 } 378 } 379 ``` 380 381 ### Subplots 382 383  384 385 https://godoc.org/go-hep.org/x/hep/hplot#example-package--Subplot 386 387 ### Ratio-plots 388 389  390 391 [embedmd]:# (ratioplot_example_test.go go /func ExampleRatioPlot/ /\n}/) 392 ```go 393 func ExampleRatioPlot() { 394 395 const npoints = 10000 396 397 // Create a normal distribution. 398 dist := distuv.Normal{ 399 Mu: 0, 400 Sigma: 1, 401 Src: rand.New(rand.NewPCG(0, 0)), 402 } 403 404 hist1 := hbook.NewH1D(20, -4, +4) 405 hist2 := hbook.NewH1D(20, -4, +4) 406 407 for range npoints { 408 v1 := dist.Rand() - 0.5 409 v2 := dist.Rand() + 0.5 410 hist1.Fill(v1, 1) 411 hist2.Fill(v2, 1) 412 } 413 414 rp := hplot.NewRatioPlot() 415 rp.Ratio = 0.3 416 417 // Make a plot and set its title. 418 rp.Top.Title.Text = "Histos" 419 rp.Top.Y.Label.Text = "Y" 420 421 // Create a histogram of our values drawn 422 // from the standard normal. 423 h1 := hplot.NewH1D(hist1) 424 h1.FillColor = color.NRGBA{R: 255, A: 100} 425 rp.Top.Add(h1) 426 427 h2 := hplot.NewH1D(hist2) 428 h2.FillColor = color.NRGBA{B: 255, A: 100} 429 rp.Top.Add(h2) 430 431 rp.Top.Add(hplot.NewGrid()) 432 433 hist3 := hbook.NewH1D(20, -4, +4) 434 for i := range hist3.Len() { 435 v1 := hist1.Value(i) 436 v2 := hist2.Value(i) 437 x1, _ := hist1.XY(i) 438 hist3.Fill(x1, v1-v2) 439 } 440 441 hdiff := hplot.NewH1D(hist3) 442 443 rp.Bottom.X.Label.Text = "X" 444 rp.Bottom.Y.Label.Text = "Delta-Y" 445 rp.Bottom.Add(hdiff) 446 rp.Bottom.Add(hplot.NewGrid()) 447 448 const ( 449 width = 15 * vg.Centimeter 450 height = width / math.Phi 451 ) 452 453 err := hplot.Save(rp, width, height, "testdata/diff_plot.png") 454 if err != nil { 455 log.Fatalf("error: %v\n", err) 456 } 457 } 458 ``` 459 460 ### LaTeX-plots 461 462 [latex-plot (PDF)](https://codeberg.org/go-hep/hep/raw/branch/main/hplot/testdata/latex_plot_golden.pdf) 463 464 https://godoc.org/go-hep.org/x/hep/hplot#example-package--Latexplot 465 466 ### 2D histogram 467 468 [embedmd]:# (h2d_example_test.go go /func ExampleH2D/ /\n}/) 469 ```go 470 func ExampleH2D() { 471 h := hbook.NewH2D(100, -10, 10, 100, -10, 10) 472 473 const npoints = 10000 474 475 dist, ok := distmv.NewNormal( 476 []float64{0, 1}, 477 mat.NewSymDense(2, []float64{4, 0, 0, 2}), 478 rand.New(rand.NewPCG(1234, 1234)), 479 ) 480 if !ok { 481 log.Fatalf("error creating distmv.Normal") 482 } 483 484 v := make([]float64, 2) 485 // Draw some random values from the standard 486 // normal distribution. 487 for range npoints { 488 v = dist.Rand(v) 489 h.Fill(v[0], v[1], 1) 490 } 491 492 p := hplot.New() 493 p.Title.Text = "Hist-2D" 494 p.X.Label.Text = "x" 495 p.Y.Label.Text = "y" 496 497 p.Add(hplot.NewH2D(h, nil)) 498 p.Add(plotter.NewGrid()) 499 err := p.Save(10*vg.Centimeter, 10*vg.Centimeter, "testdata/h2d_plot.png") 500 if err != nil { 501 log.Fatal(err) 502 } 503 } 504 ``` 505  506 507 ### Scatter2D 508 509 [embedmd]:# (s2d_example_test.go go /func ExampleS2D/ /\n}/) 510 ```go 511 func ExampleS2D() { 512 const npoints = 1000 513 514 dist, ok := distmv.NewNormal( 515 []float64{0, 1}, 516 mat.NewSymDense(2, []float64{4, 0, 0, 2}), 517 rand.New(rand.NewPCG(1234, 1234)), 518 ) 519 if !ok { 520 log.Fatalf("error creating distmv.Normal") 521 } 522 523 s2d := hbook.NewS2D() 524 525 v := make([]float64, 2) 526 // Draw some random values from the standard 527 // normal distribution. 528 for range npoints { 529 v = dist.Rand(v) 530 s2d.Fill(hbook.Point2D{X: v[0], Y: v[1]}) 531 } 532 533 p := hplot.New() 534 p.Title.Text = "Scatter-2D" 535 p.X.Label.Text = "X" 536 p.Y.Label.Text = "Y" 537 p.Add(plotter.NewGrid()) 538 539 s := hplot.NewS2D(s2d) 540 s.GlyphStyle.Color = color.RGBA{R: 255, A: 255} 541 s.GlyphStyle.Radius = vg.Points(2) 542 543 p.Add(s) 544 545 err := p.Save(10*vg.Centimeter, 10*vg.Centimeter, "testdata/s2d.png") 546 if err != nil { 547 log.Fatal(err) 548 } 549 } 550 ``` 551  552  553  554  555  556 557 ### Vertical lines 558 559 [embedmd]:# (line_example_test.go go /func ExampleVLine/ /\n}/) 560 ```go 561 func ExampleVLine() { 562 p := hplot.New() 563 p.Title.Text = "vlines" 564 p.X.Min = 0 565 p.X.Max = 10 566 p.Y.Min = 0 567 p.Y.Max = 10 568 569 var ( 570 left = color.RGBA{B: 255, A: 255} 571 right = color.RGBA{R: 255, A: 255} 572 ) 573 574 p.Add( 575 hplot.VLine(2.5, left, nil), 576 hplot.VLine(5, nil, nil), 577 hplot.VLine(7.5, nil, right), 578 ) 579 580 err := p.Save(10*vg.Centimeter, -1, "testdata/vline.png") 581 if err != nil { 582 log.Fatalf("error: %+v", err) 583 } 584 } 585 ``` 586  587 588 ### Horizontal lines 589 590 [embedmd]:# (line_example_test.go go /func ExampleHLine/ /\n}/) 591 ```go 592 func ExampleHLine() { 593 p := hplot.New() 594 p.Title.Text = "hlines" 595 p.X.Min = 0 596 p.X.Max = 10 597 p.Y.Min = 0 598 p.Y.Max = 10 599 600 var ( 601 top = color.RGBA{B: 255, A: 255} 602 bottom = color.RGBA{R: 255, A: 255} 603 ) 604 605 p.Add( 606 hplot.HLine(2.5, nil, bottom), 607 hplot.HLine(5, nil, nil), 608 hplot.HLine(7.5, top, nil), 609 ) 610 611 err := p.Save(10*vg.Centimeter, -1, "testdata/hline.png") 612 if err != nil { 613 log.Fatalf("error: %+v", err) 614 } 615 } 616 ``` 617  618 619 ### Band between lines 620 621 [embedmd]:# (band_example_test.go go /func ExampleBand/ /\n}/) 622 ```go 623 func ExampleBand() { 624 const ( 625 npoints = 100 626 xmax = 10 627 ) 628 629 // Create a normal distribution. 630 dist := distuv.Normal{ 631 Mu: 0, 632 Sigma: 1, 633 Src: rand.New(rand.NewPCG(0, 0)), 634 } 635 636 topData := make(plotter.XYs, npoints) 637 botData := make(plotter.XYs, npoints) 638 639 // Draw some random values from the standard 640 // normal distribution. 641 for i := range npoints { 642 x := float64(i+1) / xmax 643 644 v1 := dist.Rand() 645 v2 := dist.Rand() 646 647 topData[i].X = x 648 topData[i].Y = 1/x + v1 + 10 649 650 botData[i].X = x 651 botData[i].Y = math.Log(x) + v2 652 } 653 654 top, err := hplot.NewLine(topData) 655 if err != nil { 656 log.Fatalf("error: %+v", err) 657 } 658 top.LineStyle.Color = color.RGBA{R: 255, A: 255} 659 660 bot, err := hplot.NewLine(botData) 661 if err != nil { 662 log.Fatalf("error: %+v", err) 663 } 664 bot.LineStyle.Color = color.RGBA{B: 255, A: 255} 665 666 tp := hplot.NewTiledPlot(draw.Tiles{Cols: 1, Rows: 2}) 667 668 tp.Plots[0].Title.Text = "Band" 669 tp.Plots[0].Add( 670 top, 671 bot, 672 hplot.NewBand(color.Gray{200}, topData, botData), 673 ) 674 675 tp.Plots[1].Title.Text = "Band" 676 var ( 677 blue = color.RGBA{B: 255, A: 255} 678 grey = color.Gray{200} 679 band = hplot.NewBand(grey, topData, botData) 680 ) 681 band.LineStyle = plotter.DefaultLineStyle 682 band.LineStyle.Color = blue 683 tp.Plots[1].Add(band) 684 685 err = tp.Save(10*vg.Centimeter, -1, "testdata/band.png") 686 if err != nil { 687 log.Fatalf("error: %+v", err) 688 } 689 } 690 ``` 691  692 693 ### Plot with borders 694 695 One can specify extra-space between the image borders (the physical file canvas) and the actual plot data. 696 697  698 699 [embedmd]:# (h1d_example_test.go go /func ExampleH1D_withPlotBorders/ /\n}/) 700 ```go 701 func ExampleH1D_withPlotBorders() { 702 const npoints = 10000 703 704 // Create a normal distribution. 705 dist := distuv.Normal{ 706 Mu: 0, 707 Sigma: 1, 708 Src: rand.New(rand.NewPCG(0, 0)), 709 } 710 711 // Draw some random values from the standard 712 // normal distribution. 713 hist := hbook.NewH1D(20, -4, +4) 714 for range npoints { 715 v := dist.Rand() 716 hist.Fill(v, 1) 717 } 718 719 // normalize histogram 720 area := 0.0 721 for _, bin := range hist.Binning.Bins { 722 area += bin.SumW() * bin.XWidth() 723 } 724 hist.Scale(1 / area) 725 726 // Make a plot and set its title. 727 p := hplot.New() 728 p.Title.Text = "Histogram" 729 p.X.Label.Text = "X" 730 p.Y.Label.Text = "Y" 731 732 // Create a histogram of our values drawn 733 // from the standard normal. 734 h := hplot.NewH1D(hist) 735 h.Infos.Style = hplot.HInfoSummary 736 p.Add(h) 737 738 // The normal distribution function 739 norm := hplot.NewFunction(dist.Prob) 740 norm.Color = color.RGBA{R: 255, A: 255} 741 norm.Width = vg.Points(2) 742 p.Add(norm) 743 744 // draw a grid 745 p.Add(hplot.NewGrid()) 746 747 fig := hplot.Figure(p, 748 hplot.WithDPI(96), 749 hplot.WithBorder(hplot.Border{ 750 Right: 25, 751 Left: 20, 752 Top: 25, 753 Bottom: 20, 754 }), 755 ) 756 757 // Save the plot to a PNG file. 758 if err := hplot.Save(fig, 6*vg.Inch, -1, "testdata/h1d_borders.png"); err != nil { 759 log.Fatalf("error saving plot: %v\n", err) 760 } 761 } 762 ``` 763 764 ### Stack of 1D histograms 765 766  767 768 [embedmd]:# (hstack_example_test.go go /func ExampleHStack/ /\n}/) 769 ```go 770 func ExampleHStack() { 771 h1 := hbook.NewH1D(100, -10, 10) 772 h2 := hbook.NewH1D(100, -10, 10) 773 h3 := hbook.NewH1D(100, -10, 10) 774 775 const seed = 1234 776 fillH1(h1, 10000, -2, 1, seed) 777 fillH1(h2, 10000, +3, 3, seed) 778 fillH1(h3, 10000, +4, 1, seed) 779 780 colors := []color.Color{ 781 color.NRGBA{122, 195, 106, 150}, 782 color.NRGBA{90, 155, 212, 150}, 783 color.NRGBA{250, 167, 91, 150}, 784 } 785 786 hh1 := hplot.NewH1D(h1) 787 hh1.FillColor = colors[0] 788 hh1.LineStyle.Color = color.Black 789 790 hh2 := hplot.NewH1D(h2) 791 hh2.FillColor = colors[1] 792 hh2.LineStyle.Width = 0 793 794 hh3 := hplot.NewH1D(h3) 795 hh3.FillColor = colors[2] 796 hh3.LineStyle.Color = color.Black 797 798 hs := []*hplot.H1D{hh1, hh2, hh3} 799 800 tp := hplot.NewTiledPlot(draw.Tiles{Cols: 1, Rows: 3}) 801 tp.Align = true 802 803 { 804 p := tp.Plots[0] 805 p.Title.Text = "Histograms" 806 p.Y.Label.Text = "Y" 807 p.Add(hh1, hh2, hh3, hplot.NewGrid()) 808 p.Legend.Add("h1", hh1) 809 p.Legend.Add("h2", hh2) 810 p.Legend.Add("h3", hh3) 811 p.Legend.Top = true 812 p.Legend.Left = true 813 } 814 815 { 816 p := tp.Plot(0, 1) 817 p.Title.Text = "HStack - stack: OFF" 818 p.Y.Label.Text = "Y" 819 hstack := hplot.NewHStack(hs) 820 hstack.Stack = hplot.HStackOff 821 p.Add(hstack, hplot.NewGrid()) 822 p.Legend.Add("h1", hs[0]) 823 p.Legend.Add("h2", hs[1]) 824 p.Legend.Add("h3", hs[2]) 825 p.Legend.Top = true 826 p.Legend.Left = true 827 } 828 829 { 830 p := tp.Plot(0, 2) 831 p.Title.Text = "Hstack - stack: ON" 832 p.X.Label.Text = "X" 833 p.Y.Label.Text = "Y" 834 hstack := hplot.NewHStack(hs, hplot.WithLogY(false)) 835 p.Add(hstack, hplot.NewGrid()) 836 p.Legend.Add("h1", hs[0]) 837 p.Legend.Add("h2", hs[1]) 838 p.Legend.Add("h3", hs[2]) 839 p.Legend.Top = true 840 p.Legend.Left = true 841 } 842 843 err := tp.Save(15*vg.Centimeter, 15*vg.Centimeter, "testdata/hstack.png") 844 if err != nil { 845 log.Fatalf("error: %+v", err) 846 } 847 848 } 849 ``` 850 851 ### Stack of 1D histograms with a band 852 853  854 855 [embedmd]:# (hstack_example_test.go go /func ExampleHStack_withBand/ /\n}/) 856 ```go 857 func ExampleHStack_withBand() { 858 h1 := hbook.NewH1D(50, -8, 12) 859 h2 := hbook.NewH1D(50, -8, 12) 860 h3 := hbook.NewH1D(50, -8, 12) 861 862 const seed = 1234 863 fillH1(h1, 2000, -2, 1, seed) 864 fillH1(h2, 2000, +3, 3, seed) 865 fillH1(h3, 2000, +4, 1, seed) 866 867 colors := []color.Color{ 868 color.NRGBA{122, 195, 106, 150}, 869 color.NRGBA{90, 155, 212, 150}, 870 color.NRGBA{250, 167, 91, 150}, 871 } 872 873 hh1 := hplot.NewH1D(h1, hplot.WithBand(true)) 874 hh1.FillColor = colors[0] 875 hh1.LineStyle.Color = color.Black 876 hh1.Band.FillColor = color.NRGBA{G: 210, A: 200} 877 878 hh2 := hplot.NewH1D(h2, hplot.WithBand(false)) 879 hh2.FillColor = colors[1] 880 hh2.LineStyle.Width = 0 881 882 hh3 := hplot.NewH1D(h3, hplot.WithBand(true)) 883 hh3.FillColor = colors[2] 884 hh3.LineStyle.Color = color.Black 885 hh3.Band.FillColor = color.NRGBA{R: 220, A: 200} 886 887 hs := []*hplot.H1D{hh1, hh2, hh3} 888 889 hh4 := hplot.NewH1D(h1) 890 hh4.FillColor = colors[0] 891 hh4.LineStyle.Color = color.Black 892 893 hh5 := hplot.NewH1D(h2) 894 hh5.FillColor = colors[1] 895 hh5.LineStyle.Width = 0 896 897 hh6 := hplot.NewH1D(h3) 898 hh6.FillColor = colors[2] 899 hh6.LineStyle.Color = color.Black 900 901 hsHistoNoBand := []*hplot.H1D{hh4, hh5, hh6} 902 903 tp := hplot.NewTiledPlot(draw.Tiles{Cols: 2, Rows: 2}) 904 tp.Align = true 905 906 { 907 p := tp.Plot(0, 0) 908 p.Title.Text = "Histos With or Without Band, Stack: OFF" 909 p.Title.Padding = 10 910 p.X.Label.Text = "X" 911 p.Y.Label.Text = "Y" 912 hstack := hplot.NewHStack(hs, hplot.WithBand(true)) 913 hstack.Stack = hplot.HStackOff 914 p.Add(hstack, hplot.NewGrid()) 915 p.Legend.Add("h1", hs[0]) 916 p.Legend.Add("h2", hs[1]) 917 p.Legend.Add("h3", hs[2]) 918 p.Legend.Top = true 919 p.Legend.Left = true 920 } 921 922 { 923 p := tp.Plot(1, 0) 924 p.Title.Text = "Histos Without Band, Stack: OFF" 925 p.Title.Padding = 10 926 p.X.Label.Text = "X" 927 p.Y.Label.Text = "Y" 928 hstack := hplot.NewHStack(hsHistoNoBand, hplot.WithBand(true)) 929 hstack.Stack = hplot.HStackOff 930 hstack.Band.FillColor = color.NRGBA{R: 100, G: 100, B: 100, A: 200} 931 p.Add(hstack, hplot.NewGrid()) 932 p.Legend.Add("h1", hs[0]) 933 p.Legend.Add("h2", hs[1]) 934 p.Legend.Add("h3", hs[2]) 935 p.Legend.Top = true 936 p.Legend.Left = true 937 } 938 939 { 940 p := tp.Plot(0, 1) 941 p.Title.Text = "Histos With or Without Band, Stack: ON" 942 p.Title.Padding = 10 943 p.X.Label.Text = "X" 944 p.Y.Label.Text = "Y" 945 hstack := hplot.NewHStack(hs, hplot.WithBand(true)) 946 hstack.Band.FillColor = color.NRGBA{R: 100, G: 100, B: 100, A: 200} 947 p.Add(hstack, hplot.NewGrid()) 948 p.Legend.Add("h1", hs[0]) 949 p.Legend.Add("h2", hs[1]) 950 p.Legend.Add("h3", hs[2]) 951 p.Legend.Top = true 952 p.Legend.Left = true 953 } 954 955 { 956 p := tp.Plot(1, 1) 957 p.Title.Text = "Histos Without Band, Stack: ON" 958 p.Title.Padding = 10 959 p.X.Label.Text = "X" 960 p.Y.Label.Text = "Y" 961 hstack := hplot.NewHStack(hsHistoNoBand, hplot.WithBand(true)) 962 hstack.Band.FillColor = color.NRGBA{R: 100, G: 100, B: 100, A: 200} 963 p.Add(hstack, hplot.NewGrid()) 964 p.Legend.Add("h1", hs[0]) 965 p.Legend.Add("h2", hs[1]) 966 p.Legend.Add("h3", hs[2]) 967 p.Legend.Top = true 968 p.Legend.Left = true 969 } 970 971 err := tp.Save(25*vg.Centimeter, 15*vg.Centimeter, "testdata/hstack_band.png") 972 if err != nil { 973 log.Fatalf("error: %+v", err) 974 } 975 } 976 ``` 977 978 ### Stack of 1D histograms with a band, with a log-y scale 979 980  981 982 [embedmd]:# (hstack_example_test.go go /func ExampleHStack_withLogY/ /\n}/) 983 ```go 984 func ExampleHStack_withLogY() { 985 h1 := hbook.NewH1D(50, -8, 12) 986 h2 := hbook.NewH1D(50, -8, 12) 987 h3 := hbook.NewH1D(50, -8, 12) 988 989 const seed = 1234 990 fillH1(h1, 2000, -2, 1, seed) 991 fillH1(h2, 2000, +3, 3, seed) 992 fillH1(h3, 2000, +4, 1, seed) 993 994 colors := []color.Color{ 995 color.NRGBA{122, 195, 106, 150}, 996 color.NRGBA{90, 155, 212, 150}, 997 color.NRGBA{250, 167, 91, 150}, 998 } 999 logy := hplot.WithLogY(true) 1000 1001 hh1 := hplot.NewH1D(h1, hplot.WithBand(true), logy) 1002 hh1.FillColor = colors[0] 1003 hh1.LineStyle.Color = color.Black 1004 hh1.Band.FillColor = color.NRGBA{G: 210, A: 200} 1005 1006 hh2 := hplot.NewH1D(h2, hplot.WithBand(false), logy) 1007 hh2.FillColor = colors[1] 1008 hh2.LineStyle.Width = 0 1009 1010 hh3 := hplot.NewH1D(h3, hplot.WithBand(true), logy) 1011 hh3.FillColor = colors[2] 1012 hh3.LineStyle.Color = color.Black 1013 hh3.Band.FillColor = color.NRGBA{R: 220, A: 200} 1014 1015 hs := []*hplot.H1D{hh1, hh2, hh3} 1016 1017 hh4 := hplot.NewH1D(h1, logy) 1018 hh4.FillColor = colors[0] 1019 hh4.LineStyle.Color = color.Black 1020 1021 hh5 := hplot.NewH1D(h2, logy) 1022 hh5.FillColor = colors[1] 1023 hh5.LineStyle.Width = 0 1024 1025 hh6 := hplot.NewH1D(h3, logy) 1026 hh6.FillColor = colors[2] 1027 hh6.LineStyle.Color = color.Black 1028 1029 hsHistoNoBand := []*hplot.H1D{hh4, hh5, hh6} 1030 1031 tp := hplot.NewTiledPlot(draw.Tiles{Cols: 2, Rows: 2}) 1032 tp.Align = true 1033 1034 { 1035 p := tp.Plot(0, 0) 1036 p.Title.Text = "Histos With or Without Band, Stack: OFF" 1037 p.Title.Padding = 10 1038 p.Y.Scale = plot.LogScale{} 1039 p.Y.Tick.Marker = plot.LogTicks{} 1040 p.X.Label.Text = "X" 1041 p.Y.Label.Text = "Y" 1042 hstack := hplot.NewHStack(hs, hplot.WithBand(true), logy) 1043 hstack.Stack = hplot.HStackOff 1044 p.Add(hstack, hplot.NewGrid()) 1045 p.Legend.Add("h1", hs[0]) 1046 p.Legend.Add("h2", hs[1]) 1047 p.Legend.Add("h3", hs[2]) 1048 p.Legend.Top = true 1049 p.Legend.Left = true 1050 } 1051 1052 { 1053 p := tp.Plot(1, 0) 1054 p.Title.Text = "Histos Without Band, Stack: OFF" 1055 p.Title.Padding = 10 1056 p.Y.Scale = plot.LogScale{} 1057 p.Y.Tick.Marker = plot.LogTicks{} 1058 p.X.Label.Text = "X" 1059 p.Y.Label.Text = "Y" 1060 hstack := hplot.NewHStack(hsHistoNoBand, hplot.WithBand(true), logy) 1061 hstack.Stack = hplot.HStackOff 1062 hstack.Band.FillColor = color.NRGBA{R: 100, G: 100, B: 100, A: 200} 1063 p.Add(hstack, hplot.NewGrid()) 1064 p.Legend.Add("h1", hs[0]) 1065 p.Legend.Add("h2", hs[1]) 1066 p.Legend.Add("h3", hs[2]) 1067 p.Legend.Top = true 1068 p.Legend.Left = true 1069 } 1070 1071 { 1072 p := tp.Plot(0, 1) 1073 p.Title.Text = "Histos With or Without Band, Stack: ON" 1074 p.Title.Padding = 10 1075 p.Y.Scale = plot.LogScale{} 1076 p.Y.Tick.Marker = plot.LogTicks{} 1077 p.X.Label.Text = "X" 1078 p.Y.Label.Text = "Y" 1079 hstack := hplot.NewHStack(hs, hplot.WithBand(true), logy) 1080 hstack.Band.FillColor = color.NRGBA{R: 100, G: 100, B: 100, A: 200} 1081 p.Add(hstack, hplot.NewGrid()) 1082 p.Legend.Add("h1", hs[0]) 1083 p.Legend.Add("h2", hs[1]) 1084 p.Legend.Add("h3", hs[2]) 1085 p.Legend.Top = true 1086 p.Legend.Left = true 1087 } 1088 1089 { 1090 p := tp.Plot(1, 1) 1091 p.Title.Text = "Histos Without Band, Stack: ON" 1092 p.Title.Padding = 10 1093 p.Y.Scale = plot.LogScale{} 1094 p.Y.Tick.Marker = plot.LogTicks{} 1095 p.X.Label.Text = "X" 1096 p.Y.Label.Text = "Y" 1097 hstack := hplot.NewHStack(hsHistoNoBand, hplot.WithBand(true), logy) 1098 hstack.Band.FillColor = color.NRGBA{R: 100, G: 100, B: 100, A: 200} 1099 p.Add(hstack, hplot.NewGrid()) 1100 p.Legend.Add("h1", hs[0]) 1101 p.Legend.Add("h2", hs[1]) 1102 p.Legend.Add("h3", hs[2]) 1103 p.Legend.Top = true 1104 p.Legend.Left = true 1105 } 1106 1107 err := tp.Save(25*vg.Centimeter, 15*vg.Centimeter, "testdata/hstack_logy.png") 1108 if err != nil { 1109 log.Fatalf("error: %+v", err) 1110 } 1111 } 1112 ``` 1113 1114 ## Labels 1115 1116  1117 1118 [embedmd]:# (label_example_test.go go /func ExampleLabel/ /\n}/) 1119 ```go 1120 func ExampleLabel() { 1121 1122 // Creating a new plot 1123 p := hplot.New() 1124 p.Title.Text = "Plot labels" 1125 p.X.Min = -10 1126 p.X.Max = +10 1127 p.Y.Min = -10 1128 p.Y.Max = +10 1129 1130 // Default labels 1131 l1 := hplot.NewLabel(-8, 5, "(-8,5)\nDefault label") 1132 p.Add(l1) 1133 1134 // Label with normalized coordinates. 1135 l3 := hplot.NewLabel( 1136 0.5, 0.5, 1137 "(0.5,0.5)\nLabel with relative coords", 1138 hplot.WithLabelNormalized(true), 1139 ) 1140 p.Add(l3) 1141 1142 // Label with normalized coordinates and auto-adjustement. 1143 l4 := hplot.NewLabel( 1144 0.95, 0.95, 1145 "(0.95,0.95)\nLabel at the canvas edge, with AutoAdjust", 1146 hplot.WithLabelNormalized(true), 1147 hplot.WithLabelAutoAdjust(true), 1148 ) 1149 p.Add(l4) 1150 1151 // Label with a customed TextStyle 1152 usrFont := font.Font{ 1153 Typeface: "Liberation", 1154 Variant: "Mono", 1155 Weight: xfnt.WeightBold, 1156 Style: xfnt.StyleNormal, 1157 Size: 12, 1158 } 1159 sty := text.Style{ 1160 Color: plotutil.Color(2), 1161 Font: usrFont, 1162 } 1163 l5 := hplot.NewLabel( 1164 0.0, 0.1, 1165 "(0.0,0.1)\nLabel with a user-defined font", 1166 hplot.WithLabelTextStyle(sty), 1167 hplot.WithLabelNormalized(true), 1168 ) 1169 p.Add(l5) 1170 1171 p.Add(plotter.NewGlyphBoxes()) 1172 p.Add(hplot.NewGrid()) 1173 1174 // Save the plot to a PNG file. 1175 err := p.Save(15*vg.Centimeter, -1, "testdata/label_plot.png") 1176 if err != nil { 1177 log.Fatalf("error saving plot: %v\n", err) 1178 } 1179 } 1180 ``` 1181 1182 ## Time series 1183 1184  1185 1186 [embedmd]:# (ticks_example_test.go go /func ExampleTicks_monthly/ /\n}/) 1187 ```go 1188 func ExampleTicks_monthly() { 1189 cnv := epok.UTCUnixTimeConverter{} 1190 1191 p := hplot.New() 1192 p.Title.Text = "Time series (monthly)" 1193 p.Y.Label.Text = "Goroutines" 1194 1195 p.Y.Min = 0 1196 p.Y.Max = 4 1197 p.X.AutoRescale = true 1198 p.X.Tick.Marker = epok.Ticks{ 1199 Ruler: epok.Rules{ 1200 Major: epok.Rule{ 1201 Freq: epok.Monthly, 1202 Range: epok.RangeFrom(1, 13, 2), 1203 }, 1204 }, 1205 Format: "2006\nJan-02\n15:04:05", 1206 Converter: cnv, 1207 } 1208 1209 xysFrom := func(vs ...float64) plotter.XYs { 1210 o := make(plotter.XYs, len(vs)) 1211 for i := range o { 1212 o[i].X = vs[i] 1213 o[i].Y = float64(i + 1) 1214 } 1215 return o 1216 } 1217 data := xysFrom( 1218 cnv.FromTime(parse("2010-01-02 01:02:03")), 1219 cnv.FromTime(parse("2010-02-01 01:02:03")), 1220 cnv.FromTime(parse("2010-02-04 11:22:33")), 1221 cnv.FromTime(parse("2010-03-04 01:02:03")), 1222 cnv.FromTime(parse("2010-04-05 01:02:03")), 1223 cnv.FromTime(parse("2010-04-05 01:02:03")), 1224 cnv.FromTime(parse("2010-05-01 00:02:03")), 1225 cnv.FromTime(parse("2010-05-04 04:04:04")), 1226 cnv.FromTime(parse("2010-05-08 11:12:13")), 1227 cnv.FromTime(parse("2010-06-15 01:02:03")), 1228 cnv.FromTime(parse("2010-07-04 04:04:43")), 1229 cnv.FromTime(parse("2010-07-14 14:17:09")), 1230 cnv.FromTime(parse("2010-08-04 21:22:23")), 1231 cnv.FromTime(parse("2010-08-15 11:12:13")), 1232 cnv.FromTime(parse("2010-09-01 21:52:53")), 1233 cnv.FromTime(parse("2010-10-25 01:19:23")), 1234 cnv.FromTime(parse("2010-11-30 11:32:53")), 1235 cnv.FromTime(parse("2010-12-24 23:59:59")), 1236 cnv.FromTime(parse("2010-12-31 23:59:59")), 1237 cnv.FromTime(parse("2011-01-12 01:02:03")), 1238 ) 1239 1240 line, pnts, err := hplot.NewLinePoints(data) 1241 if err != nil { 1242 log.Fatalf("could not create plotter: %+v", err) 1243 } 1244 1245 line.Color = color.RGBA{B: 255, A: 255} 1246 pnts.Shape = draw.CircleGlyph{} 1247 pnts.Color = color.RGBA{R: 255, A: 255} 1248 1249 p.Add(line, pnts, hplot.NewGrid()) 1250 1251 err = p.Save(20*vg.Centimeter, 10*vg.Centimeter, "testdata/timeseries_monthly.png") 1252 if err != nil { 1253 log.Fatalf("could not save plot: %+v", err) 1254 } 1255 } 1256 ```