go-hep.org/x/hep@v0.38.1/hbook/h1d.go (about) 1 // Copyright ©2015 The go-hep Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package hbook 6 7 import ( 8 "bufio" 9 "bytes" 10 "encoding/binary" 11 "encoding/gob" 12 "fmt" 13 "io" 14 "math" 15 "strings" 16 17 "go-hep.org/x/hep/rio" 18 ) 19 20 // H1D is a 1-dim histogram with weighted entries. 21 type H1D struct { 22 Binning Binning1D 23 Ann Annotation 24 } 25 26 // NewH1D returns a 1-dim histogram with n bins between xmin and xmax. 27 func NewH1D(n int, xmin, xmax float64) *H1D { 28 return &H1D{ 29 Binning: newBinning1D(n, xmin, xmax), 30 Ann: make(Annotation), 31 } 32 } 33 34 // NewH1DFromEdges returns a 1-dim histogram given a slice of edges. 35 // The number of bins is thus len(edges)-1. 36 // It panics if the length of edges is <= 1. 37 // It panics if the edges are not sorted. 38 // It panics if there are duplicate edge values. 39 func NewH1DFromEdges(edges []float64) *H1D { 40 return &H1D{ 41 Binning: newBinning1DFromEdges(edges), 42 Ann: make(Annotation), 43 } 44 } 45 46 // NewH1DFromBins returns a 1-dim histogram given a slice of 1-dim bins. 47 // It panics if the length of bins is < 1. 48 // It panics if the bins overlap. 49 func NewH1DFromBins(bins ...Range) *H1D { 50 return &H1D{ 51 Binning: newBinning1DFromBins(bins), 52 Ann: make(Annotation), 53 } 54 } 55 56 // Clone returns a deep copy of this 1-dim histogram. 57 func (h *H1D) Clone() *H1D { 58 return &H1D{ 59 Binning: h.Binning.clone(), 60 Ann: h.Ann.clone(), 61 } 62 } 63 64 // Name returns the name of this histogram, if any 65 func (h *H1D) Name() string { 66 v, ok := h.Ann["name"] 67 if !ok { 68 return "" 69 } 70 n, ok := v.(string) 71 if !ok { 72 return "" 73 } 74 return n 75 } 76 77 // Annotation returns the annotations attached to this histogram 78 func (h *H1D) Annotation() Annotation { 79 return h.Ann 80 } 81 82 // Rank returns the number of dimensions for this histogram 83 func (h *H1D) Rank() int { 84 return 1 85 } 86 87 // Entries returns the number of entries in this histogram 88 func (h *H1D) Entries() int64 { 89 return h.Binning.entries() 90 } 91 92 // EffEntries returns the number of effective entries in this histogram 93 func (h *H1D) EffEntries() float64 { 94 return h.Binning.effEntries() 95 } 96 97 // SumW returns the sum of weights in this histogram. 98 // Overflows are included in the computation. 99 func (h *H1D) SumW() float64 { 100 return h.Binning.Dist.SumW() 101 } 102 103 // SumW2 returns the sum of squared weights in this histogram. 104 // Overflows are included in the computation. 105 func (h *H1D) SumW2() float64 { 106 return h.Binning.Dist.SumW2() 107 } 108 109 // SumWX returns the 1st order weighted x moment 110 func (h *H1D) SumWX() float64 { 111 return h.Binning.Dist.SumWX() 112 } 113 114 // SumWX2 returns the 2nd order weighted x moment 115 func (h *H1D) SumWX2() float64 { 116 return h.Binning.Dist.SumWX2() 117 } 118 119 // XMean returns the mean X. 120 // Overflows are included in the computation. 121 func (h *H1D) XMean() float64 { 122 return h.Binning.Dist.mean() 123 } 124 125 // XVariance returns the variance in X. 126 // Overflows are included in the computation. 127 func (h *H1D) XVariance() float64 { 128 return h.Binning.Dist.variance() 129 } 130 131 // XStdDev returns the standard deviation in X. 132 // Overflows are included in the computation. 133 func (h *H1D) XStdDev() float64 { 134 return h.Binning.Dist.stdDev() 135 } 136 137 // XStdErr returns the standard error in X. 138 // Overflows are included in the computation. 139 func (h *H1D) XStdErr() float64 { 140 return h.Binning.Dist.stdErr() 141 } 142 143 // XRMS returns the XRMS in X. 144 // Overflows are included in the computation. 145 func (h *H1D) XRMS() float64 { 146 return h.Binning.Dist.rms() 147 } 148 149 // Fill fills this histogram with x and weight w. 150 func (h *H1D) Fill(x, w float64) { 151 h.Binning.fill(x, w) 152 } 153 154 // FillN fills this histogram with the provided slices of xs and weight ws. 155 // if ws is nil, the histogram will be filled with entries of weight 1. 156 // Otherwise, FillN panics if the slices lengths differ. 157 func (h *H1D) FillN(xs, ws []float64) { 158 switch ws { 159 case nil: 160 for _, x := range xs { 161 h.Binning.fill(x, 1) 162 } 163 default: 164 if len(xs) != len(ws) { 165 panic(fmt.Errorf("hbook: lengths mismatch")) 166 } 167 for i, x := range xs { 168 h.Binning.fill(x, ws[i]) 169 } 170 } 171 } 172 173 // Bin returns the bin at coordinates (x) for this 1-dim histogram. 174 // Bin returns nil for under/over flow bins. 175 func (h *H1D) Bin(x float64) *Bin1D { 176 idx := h.Binning.coordToIndex(x) 177 if idx < 0 { 178 return nil 179 } 180 return &h.Binning.Bins[idx] 181 } 182 183 // XMin returns the low edge of the X-axis of this histogram. 184 func (h *H1D) XMin() float64 { 185 return h.Binning.xMin() 186 } 187 188 // XMax returns the high edge of the X-axis of this histogram. 189 func (h *H1D) XMax() float64 { 190 return h.Binning.xMax() 191 } 192 193 // Scale scales the content of each bin by the given factor. 194 func (h *H1D) Scale(factor float64) { 195 h.Binning.scaleW(factor) 196 } 197 198 // Integral computes the integral of the histogram. 199 // 200 // The number of parameters can be 0 or 2. 201 // If 0, overflows are included. 202 // If 2, the first parameter must be the lower bound of the range in which 203 // the integral is computed and the second one the upper range. 204 // 205 // If the lower bound is math.Inf(-1) then the underflow bin is included. 206 // If the upper bound is math.Inf(+1) then the overflow bin is included. 207 // 208 // Examples: 209 // 210 // // integral of all in-range bins + overflows 211 // v := h.Integral() 212 // 213 // // integral of all in-range bins, underflow and overflow bins included. 214 // v := h.Integral(math.Inf(-1), math.Inf(+1)) 215 // 216 // // integrall of all in-range bins, overflow bin included 217 // v := h.Integral(h.Binning.XRange.Min, math.Inf(+1)) 218 // 219 // // integrall of all bins for which the lower edge is in [0.5, 5.5) 220 // v := h.Integral(0.5, 5.5) 221 func (h *H1D) Integral(args ...float64) float64 { 222 min, max := 0., 0. 223 switch len(args) { 224 case 0: 225 return h.SumW() 226 case 2: 227 min = args[0] 228 max = args[1] 229 if min > max { 230 panic("hbook: min > max") 231 } 232 default: 233 panic("hbook: invalid number of arguments. expected 0 or 2.") 234 } 235 236 integral := 0.0 237 for _, bin := range h.Binning.Bins { 238 v := bin.Range.Min 239 if min <= v && v < max { 240 integral += bin.SumW() 241 } 242 } 243 if math.IsInf(min, -1) { 244 integral += h.Binning.Outflows[0].SumW() 245 } 246 if math.IsInf(max, +1) { 247 integral += h.Binning.Outflows[1].SumW() 248 } 249 return integral 250 } 251 252 // Value returns the content of the idx-th bin. 253 // 254 // Value implements gonum/plot/plotter.Valuer 255 func (h *H1D) Value(i int) float64 { 256 return h.Binning.Bins[i].SumW() 257 } 258 259 // Error returns the error, defined as sqrt(sumW2), of the idx-th bin. 260 func (h *H1D) Error(i int) float64 { 261 return math.Sqrt(h.Binning.Bins[i].SumW2()) 262 } 263 264 // Len returns the number of bins for this histogram 265 // 266 // Len implements gonum/plot/plotter.Valuer 267 func (h *H1D) Len() int { 268 return len(h.Binning.Bins) 269 } 270 271 // XY returns the x,y values for the i-th bin 272 // 273 // XY implements gonum/plot/plotter.XYer 274 func (h *H1D) XY(i int) (float64, float64) { 275 bin := h.Binning.Bins[i] 276 x := bin.Range.Min 277 y := bin.SumW() 278 return x, y 279 } 280 281 // DataRange implements the gonum/plot.DataRanger interface 282 func (h *H1D) DataRange() (xmin, xmax, ymin, ymax float64) { 283 xmin = h.XMin() 284 xmax = h.XMax() 285 ymin = +math.MaxFloat64 286 ymax = -math.MaxFloat64 287 for _, b := range h.Binning.Bins { 288 v := b.SumW() 289 ymax = math.Max(ymax, v) 290 ymin = math.Min(ymin, v) 291 } 292 return xmin, xmax, ymin, ymax 293 } 294 295 // RioMarshal implements rio.RioMarshaler 296 func (h *H1D) RioMarshal(w io.Writer) error { 297 data, err := h.MarshalBinary() 298 if err != nil { 299 return err 300 } 301 var buf [8]byte 302 binary.LittleEndian.PutUint64(buf[:], uint64(len(data))) 303 _, err = w.Write(buf[:]) 304 if err != nil { 305 return err 306 } 307 _, err = w.Write(data) 308 return err 309 } 310 311 // RioUnmarshal implements rio.RioUnmarshaler 312 func (h *H1D) RioUnmarshal(r io.Reader) error { 313 buf := make([]byte, 8) 314 _, err := io.ReadFull(r, buf) 315 if err != nil { 316 return err 317 } 318 n := int64(binary.LittleEndian.Uint64(buf)) 319 buf = make([]byte, int(n)) 320 _, err = io.ReadFull(r, buf) 321 if err != nil { 322 return err 323 } 324 return h.UnmarshalBinary(buf) 325 } 326 327 // RioVersion implements rio.RioStreamer 328 func (h *H1D) RioVersion() rio.Version { 329 return 0 330 } 331 332 // annToYODA creates a new Annotation with fields compatible with YODA 333 func (h *H1D) annToYODA() Annotation { 334 ann := make(Annotation, len(h.Ann)) 335 ann["Type"] = "Histo1D" 336 ann["Path"] = "/" + h.Name() 337 ann["Title"] = "" 338 for k, v := range h.Ann { 339 if k == "name" { 340 continue 341 } 342 if k == "title" { 343 ann["Title"] = v 344 continue 345 } 346 ann[k] = v 347 } 348 return ann 349 } 350 351 // annFromYODA creates a new Annotation from YODA compatible fields 352 func (h *H1D) annFromYODA(ann Annotation) { 353 if len(h.Ann) == 0 { 354 h.Ann = make(Annotation, len(ann)) 355 } 356 for k, v := range ann { 357 switch k { 358 case "Type": 359 // noop 360 case "Path": 361 name := v.(string) 362 name = strings.TrimPrefix(name, "/") 363 h.Ann["name"] = name 364 case "Title": 365 h.Ann["title"] = v 366 default: 367 h.Ann[k] = v 368 } 369 } 370 } 371 372 // MarshalYODA implements the YODAMarshaler interface. 373 func (h *H1D) MarshalYODA() ([]byte, error) { 374 return h.marshalYODAv2() 375 } 376 377 func (h *H1D) marshalYODAv1() ([]byte, error) { 378 buf := new(bytes.Buffer) 379 ann := h.annToYODA() 380 fmt.Fprintf(buf, "BEGIN YODA_HISTO1D %s\n", ann["Path"]) 381 data, err := ann.marshalYODAv1() 382 if err != nil { 383 return nil, err 384 } 385 buf.Write(data) 386 387 fmt.Fprintf(buf, "# Mean: %e\n", h.XMean()) 388 fmt.Fprintf(buf, "# Area: %e\n", h.Integral()) 389 390 fmt.Fprintf(buf, "# ID\t ID\t sumw\t sumw2\t sumwx\t sumwx2\t numEntries\n") 391 d := h.Binning.Dist 392 fmt.Fprintf( 393 buf, 394 "Total \tTotal \t%e\t%e\t%e\t%e\t%d\n", 395 d.SumW(), d.SumW2(), d.SumWX(), d.SumWX2(), d.Entries(), 396 ) 397 d = h.Binning.Outflows[0] 398 fmt.Fprintf( 399 buf, 400 "Underflow\tUnderflow\t%e\t%e\t%e\t%e\t%d\n", 401 d.SumW(), d.SumW2(), d.SumWX(), d.SumWX2(), d.Entries(), 402 ) 403 404 d = h.Binning.Outflows[1] 405 fmt.Fprintf( 406 buf, 407 "Overflow\tOverflow\t%e\t%e\t%e\t%e\t%d\n", 408 d.SumW(), d.SumW2(), d.SumWX(), d.SumWX2(), d.Entries(), 409 ) 410 411 // bins 412 fmt.Fprintf(buf, "# xlow\t xhigh\t sumw\t sumw2\t sumwx\t sumwx2\t numEntries\n") 413 for _, bin := range h.Binning.Bins { 414 d := bin.Dist 415 fmt.Fprintf( 416 buf, 417 "%e\t%e\t%e\t%e\t%e\t%e\t%d\n", 418 bin.Range.Min, bin.Range.Max, 419 d.SumW(), d.SumW2(), d.SumWX(), d.SumWX2(), d.Entries(), 420 ) 421 } 422 fmt.Fprintf(buf, "END YODA_HISTO1D\n\n") 423 return buf.Bytes(), err 424 } 425 426 func (h *H1D) marshalYODAv2() ([]byte, error) { 427 buf := new(bytes.Buffer) 428 ann := h.annToYODA() 429 fmt.Fprintf(buf, "BEGIN YODA_HISTO1D_V2 %s\n", ann["Path"]) 430 data, err := ann.marshalYODAv2() 431 if err != nil { 432 return nil, err 433 } 434 buf.Write(data) 435 buf.Write([]byte("---\n")) 436 437 fmt.Fprintf(buf, "# Mean: %e\n", h.XMean()) 438 fmt.Fprintf(buf, "# Area: %e\n", h.Integral()) 439 440 fmt.Fprintf(buf, "# ID\t ID\t sumw\t sumw2\t sumwx\t sumwx2\t numEntries\n") 441 d := h.Binning.Dist 442 fmt.Fprintf( 443 buf, 444 "Total \tTotal \t%e\t%e\t%e\t%e\t%e\n", 445 d.SumW(), d.SumW2(), d.SumWX(), d.SumWX2(), float64(d.Entries()), 446 ) 447 d = h.Binning.Outflows[0] 448 fmt.Fprintf( 449 buf, 450 "Underflow\tUnderflow\t%e\t%e\t%e\t%e\t%e\n", 451 d.SumW(), d.SumW2(), d.SumWX(), d.SumWX2(), float64(d.Entries()), 452 ) 453 454 d = h.Binning.Outflows[1] 455 fmt.Fprintf( 456 buf, 457 "Overflow\tOverflow\t%e\t%e\t%e\t%e\t%e\n", 458 d.SumW(), d.SumW2(), d.SumWX(), d.SumWX2(), float64(d.Entries()), 459 ) 460 461 // bins 462 fmt.Fprintf(buf, "# xlow\t xhigh\t sumw\t sumw2\t sumwx\t sumwx2\t numEntries\n") 463 for _, bin := range h.Binning.Bins { 464 d := bin.Dist 465 fmt.Fprintf( 466 buf, 467 "%e\t%e\t%e\t%e\t%e\t%e\t%e\n", 468 bin.Range.Min, bin.Range.Max, 469 d.SumW(), d.SumW2(), d.SumWX(), d.SumWX2(), float64(d.Entries()), 470 ) 471 } 472 fmt.Fprintf(buf, "END YODA_HISTO1D_V2\n\n") 473 return buf.Bytes(), err 474 } 475 476 // UnmarshalYODA implements the YODAUnmarshaler interface. 477 func (h *H1D) UnmarshalYODA(data []byte) error { 478 r := newRBuffer(data) 479 _, vers, err := readYODAHeader(r, "BEGIN YODA_HISTO1D") 480 if err != nil { 481 return err 482 } 483 switch vers { 484 case 1: 485 return h.unmarshalYODAv1(r) 486 case 2: 487 return h.unmarshalYODAv2(r) 488 default: 489 return fmt.Errorf("hbook: invalid YODA version %v", vers) 490 } 491 } 492 493 func (h *H1D) unmarshalYODAv1(r *rbuffer) error { 494 ann := make(Annotation) 495 496 // pos of end of annotations 497 pos := bytes.Index(r.Bytes(), []byte("\n# Mean:")) 498 if pos < 0 { 499 return fmt.Errorf("hbook: invalid H1D-YODA data") 500 } 501 err := ann.unmarshalYODAv1(r.Bytes()[:pos+1]) 502 if err != nil { 503 return fmt.Errorf("hbook: %q\nhbook: %w", string(r.Bytes()[:pos+1]), err) 504 } 505 h.annFromYODA(ann) 506 r.next(pos) 507 508 var ctx struct { 509 total bool 510 under bool 511 over bool 512 bins bool 513 } 514 515 // sets of xlow values, to infer number of bins in X. 516 xset := make(map[float64]int) 517 518 var ( 519 dist Dist1D 520 oflows [2]Dist1D 521 bins []Bin1D 522 xmin = math.Inf(+1) 523 xmax = math.Inf(-1) 524 ) 525 s := bufio.NewScanner(r) 526 scanLoop: 527 for s.Scan() { 528 buf := s.Bytes() 529 if len(buf) == 0 || buf[0] == '#' { 530 continue 531 } 532 rbuf := bytes.NewReader(buf) 533 switch { 534 case bytes.HasPrefix(buf, []byte("END YODA_HISTO1D")): 535 break scanLoop 536 case !ctx.total && bytes.HasPrefix(buf, []byte("Total \t")): 537 ctx.total = true 538 d := &dist 539 _, err = fmt.Fscanf( 540 rbuf, 541 "Total \tTotal \t%e\t%e\t%e\t%e\t%d\n", 542 &d.Dist.SumW, &d.Dist.SumW2, 543 &d.Stats.SumWX, &d.Stats.SumWX2, 544 &d.Dist.N, 545 ) 546 if err != nil { 547 return fmt.Errorf("hbook: %q\nhbook: %w", string(buf), err) 548 } 549 case !ctx.under && bytes.HasPrefix(buf, []byte("Underflow\t")): 550 ctx.under = true 551 d := &oflows[0] 552 _, err = fmt.Fscanf( 553 rbuf, 554 "Underflow\tUnderflow\t%e\t%e\t%e\t%e\t%d\n", 555 &d.Dist.SumW, &d.Dist.SumW2, 556 &d.Stats.SumWX, &d.Stats.SumWX2, 557 &d.Dist.N, 558 ) 559 if err != nil { 560 return fmt.Errorf("hbook: %q\nhbook: %w", string(buf), err) 561 } 562 case !ctx.over && bytes.HasPrefix(buf, []byte("Overflow\t")): 563 ctx.over = true 564 d := &oflows[1] 565 _, err = fmt.Fscanf( 566 rbuf, 567 "Overflow\tOverflow\t%e\t%e\t%e\t%e\t%d\n", 568 &d.Dist.SumW, &d.Dist.SumW2, 569 &d.Stats.SumWX, &d.Stats.SumWX2, 570 &d.Dist.N, 571 ) 572 if err != nil { 573 return fmt.Errorf("hbook: %q\nhbook: %w", string(buf), err) 574 } 575 ctx.bins = true 576 case ctx.bins: 577 var bin Bin1D 578 d := &bin.Dist 579 _, err = fmt.Fscanf( 580 rbuf, 581 "%e\t%e\t%e\t%e\t%e\t%e\t%d\n", 582 &bin.Range.Min, &bin.Range.Max, 583 &d.Dist.SumW, &d.Dist.SumW2, 584 &d.Stats.SumWX, &d.Stats.SumWX2, 585 &d.Dist.N, 586 ) 587 if err != nil { 588 return fmt.Errorf("hbook: %q\nhbook: %w", string(buf), err) 589 } 590 xset[bin.Range.Min] = 1 591 xmin = math.Min(xmin, bin.Range.Min) 592 xmax = math.Max(xmax, bin.Range.Max) 593 bins = append(bins, bin) 594 595 default: 596 return fmt.Errorf("hbook: invalid H1D-YODA data: %q", string(buf)) 597 } 598 } 599 h.Binning = Binning1D{ 600 Bins: bins, 601 Dist: dist, 602 Outflows: oflows, 603 XRange: Range{xmin, xmax}, 604 } 605 return err 606 } 607 608 func (h *H1D) unmarshalYODAv2(r *rbuffer) error { 609 ann := make(Annotation) 610 611 // pos of end of annotations 612 pos := bytes.Index(r.Bytes(), []byte("\n# Mean:")) 613 if pos < 0 { 614 return fmt.Errorf("hbook: invalid H1D-YODA data") 615 } 616 err := ann.unmarshalYODAv2(r.Bytes()[:pos+1]) 617 if err != nil { 618 return fmt.Errorf("hbook: %q\nhbook: %w", string(r.Bytes()[:pos+1]), err) 619 } 620 h.annFromYODA(ann) 621 r.next(pos) 622 623 var ctx struct { 624 total bool 625 under bool 626 over bool 627 bins bool 628 } 629 630 // sets of xlow values, to infer number of bins in X. 631 xset := make(map[float64]int) 632 633 var ( 634 dist Dist1D 635 oflows [2]Dist1D 636 bins []Bin1D 637 xmin = math.Inf(+1) 638 xmax = math.Inf(-1) 639 ) 640 s := bufio.NewScanner(r) 641 scanLoop: 642 for s.Scan() { 643 buf := s.Bytes() 644 if len(buf) == 0 || buf[0] == '#' { 645 continue 646 } 647 rbuf := bytes.NewReader(buf) 648 switch { 649 case bytes.HasPrefix(buf, []byte("END YODA_HISTO1D")): 650 break scanLoop 651 case !ctx.total && bytes.HasPrefix(buf, []byte("Total \t")): 652 ctx.total = true 653 d := &dist 654 var n float64 655 _, err = fmt.Fscanf( 656 rbuf, 657 "Total \tTotal \t%e\t%e\t%e\t%e\t%e\n", 658 &d.Dist.SumW, &d.Dist.SumW2, 659 &d.Stats.SumWX, &d.Stats.SumWX2, 660 &n, 661 ) 662 if err != nil { 663 return fmt.Errorf("hbook: %q\nhbook: %w", string(buf), err) 664 } 665 d.Dist.N = int64(n) 666 case !ctx.under && bytes.HasPrefix(buf, []byte("Underflow\t")): 667 ctx.under = true 668 d := &oflows[0] 669 var n float64 670 _, err = fmt.Fscanf( 671 rbuf, 672 "Underflow\tUnderflow\t%e\t%e\t%e\t%e\t%e\n", 673 &d.Dist.SumW, &d.Dist.SumW2, 674 &d.Stats.SumWX, &d.Stats.SumWX2, 675 &n, 676 ) 677 if err != nil { 678 return fmt.Errorf("hbook: %q\nhbook: %w", string(buf), err) 679 } 680 d.Dist.N = int64(n) 681 case !ctx.over && bytes.HasPrefix(buf, []byte("Overflow\t")): 682 ctx.over = true 683 d := &oflows[1] 684 var n float64 685 _, err = fmt.Fscanf( 686 rbuf, 687 "Overflow\tOverflow\t%e\t%e\t%e\t%e\t%e\n", 688 &d.Dist.SumW, &d.Dist.SumW2, 689 &d.Stats.SumWX, &d.Stats.SumWX2, 690 &n, 691 ) 692 if err != nil { 693 return fmt.Errorf("hbook: %q\nhbook: %w", string(buf), err) 694 } 695 d.Dist.N = int64(n) 696 ctx.bins = true 697 case ctx.bins: 698 var bin Bin1D 699 d := &bin.Dist 700 var n float64 701 _, err = fmt.Fscanf( 702 rbuf, 703 "%e\t%e\t%e\t%e\t%e\t%e\t%e\n", 704 &bin.Range.Min, &bin.Range.Max, 705 &d.Dist.SumW, &d.Dist.SumW2, 706 &d.Stats.SumWX, &d.Stats.SumWX2, 707 &n, 708 ) 709 if err != nil { 710 return fmt.Errorf("hbook: %q\nhbook: %w", string(buf), err) 711 } 712 d.Dist.N = int64(n) 713 xset[bin.Range.Min] = 1 714 xmin = math.Min(xmin, bin.Range.Min) 715 xmax = math.Max(xmax, bin.Range.Max) 716 bins = append(bins, bin) 717 718 default: 719 return fmt.Errorf("hbook: invalid H1D-YODA data: %q", string(buf)) 720 } 721 } 722 h.Binning = Binning1D{ 723 Bins: bins, 724 Dist: dist, 725 Outflows: oflows, 726 XRange: Range{xmin, xmax}, 727 } 728 return err 729 } 730 731 // Counts return a slice of Count, ignoring outerflow. 732 // The low and high error is equal to 0.5 * sqrt(sum(w^2)). 733 func (h *H1D) Counts() []Count { 734 cs := make([]Count, h.Len()) 735 for i, bin := range h.Binning.Bins { 736 cs[i].XRange = bin.Range 737 cs[i].Val = h.Value(i) 738 cs[i].Err.Low = h.Error(i) * 0.5 739 cs[i].Err.High = h.Error(i) * 0.5 740 } 741 return cs 742 } 743 744 // check various interfaces 745 var _ Object = (*H1D)(nil) 746 var _ Histogram = (*H1D)(nil) 747 748 // serialization interfaces 749 var _ rio.Marshaler = (*H1D)(nil) 750 var _ rio.Unmarshaler = (*H1D)(nil) 751 var _ rio.Streamer = (*H1D)(nil) 752 753 func init() { 754 gob.Register((*H1D)(nil)) 755 }