go-hep.org/x/hep@v0.38.1/groot/rhist/graph.go (about) 1 // Copyright ©2017 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 rhist 6 7 import ( 8 "fmt" 9 "math" 10 "reflect" 11 12 "go-hep.org/x/hep/groot/rbase" 13 "go-hep.org/x/hep/groot/rbytes" 14 "go-hep.org/x/hep/groot/rcont" 15 "go-hep.org/x/hep/groot/root" 16 "go-hep.org/x/hep/groot/rtypes" 17 "go-hep.org/x/hep/groot/rvers" 18 "go-hep.org/x/hep/hbook" 19 "go-hep.org/x/hep/hbook/yodacnv" 20 ) 21 22 type tgraph struct { 23 rbase.Named 24 attline rbase.AttLine 25 attfill rbase.AttFill 26 attmarker rbase.AttMarker 27 28 maxsize int32 29 npoints int32 30 x []float64 31 y []float64 32 funcs root.List 33 histo *H1F 34 min float64 35 max float64 36 opt string 37 } 38 39 func newGraph(n int) *tgraph { 40 return &tgraph{ 41 Named: *rbase.NewNamed("", ""), 42 attline: *rbase.NewAttLine(), 43 attfill: *rbase.NewAttFill(), 44 attmarker: *rbase.NewAttMarker(), 45 maxsize: int32(n), 46 npoints: int32(n), 47 x: make([]float64, n), 48 y: make([]float64, n), 49 funcs: rcont.NewList("", nil), 50 opt: "", 51 } 52 } 53 54 // NewGraphFrom creates a new Graph from 2-dim hbook data points. 55 func NewGraphFrom(s2 *hbook.S2D) Graph { 56 var ( 57 n = s2.Len() 58 groot = newGraph(n) 59 ymin = +math.MaxFloat64 60 ymax = -math.MaxFloat64 61 ) 62 63 for i, pt := range s2.Points() { 64 groot.x[i] = pt.X 65 groot.y[i] = pt.Y 66 67 ymax = math.Max(ymax, pt.Y) 68 ymin = math.Min(ymin, pt.Y) 69 } 70 71 groot.Named.SetName(s2.Name()) 72 if v, ok := s2.Annotation()["title"]; ok { 73 groot.Named.SetTitle(v.(string)) 74 } 75 76 groot.min = ymin 77 groot.max = ymax 78 79 return groot 80 } 81 82 func (*tgraph) RVersion() int16 { 83 return rvers.Graph 84 } 85 86 func (g *tgraph) Class() string { 87 return "TGraph" 88 } 89 90 func (g *tgraph) Len() int { 91 return int(len(g.x)) 92 } 93 94 func (g *tgraph) XY(i int) (float64, float64) { 95 return g.x[i], g.y[i] 96 } 97 98 func (g *tgraph) ROOTMerge(src root.Object) error { 99 switch src := src.(type) { 100 case *tgraph: 101 if src.maxsize > g.maxsize { 102 g.maxsize = src.maxsize 103 } 104 g.npoints += src.npoints 105 g.x = append(g.x, src.x...) 106 g.y = append(g.y, src.y...) 107 g.min = math.Min(g.min, src.min) 108 g.max = math.Max(g.max, src.max) 109 // FIXME(sbinet): handle g.funcs 110 // FIXME(sbinet): handle g.histo 111 // FIXME(sbinet): re-sort x,y,... slices according to x. 112 return nil 113 default: 114 return fmt.Errorf("rhist: can not merge %T into %T", src, g) 115 } 116 } 117 118 // ROOTMarshaler is the interface implemented by an object that can 119 // marshal itself to a ROOT buffer 120 func (g *tgraph) MarshalROOT(w *rbytes.WBuffer) (int, error) { 121 if w.Err() != nil { 122 return 0, w.Err() 123 } 124 125 hdr := w.WriteHeader(g.Class(), g.RVersion()) 126 127 w.WriteObject(&g.Named) 128 w.WriteObject(&g.attline) 129 w.WriteObject(&g.attfill) 130 w.WriteObject(&g.attmarker) 131 132 w.WriteI32(g.npoints) 133 { 134 w.WriteI8(1) 135 w.WriteArrayF64(g.x) 136 w.WriteI8(1) 137 w.WriteArrayF64(g.y) 138 } 139 140 w.WriteObjectAny(g.funcs) 141 w.WriteObjectAny(g.histo) 142 { 143 w.WriteF64(g.min) 144 w.WriteF64(g.max) 145 } 146 w.WriteString(g.opt) 147 148 return w.SetHeader(hdr) 149 } 150 151 // ROOTUnmarshaler is the interface implemented by an object that can 152 // unmarshal itself from a ROOT buffer 153 func (g *tgraph) UnmarshalROOT(r *rbytes.RBuffer) error { 154 if r.Err() != nil { 155 return r.Err() 156 } 157 158 hdr := r.ReadHeader(g.Class(), g.RVersion()) 159 160 r.ReadObject(&g.Named) 161 r.ReadObject(&g.attline) 162 r.ReadObject(&g.attfill) 163 r.ReadObject(&g.attmarker) 164 165 g.npoints = r.ReadI32() 166 g.maxsize = g.npoints 167 if hdr.Vers < 2 { 168 _ = r.ReadI8() 169 xs := make([]float32, g.npoints) 170 r.ReadArrayF32(xs) 171 _ = r.ReadI8() 172 ys := make([]float32, g.npoints) 173 r.ReadArrayF32(ys) 174 g.x = make([]float64, len(xs)) 175 g.y = make([]float64, len(ys)) 176 for i := range xs { 177 g.x[i] = float64(xs[i]) 178 g.y[i] = float64(ys[i]) 179 } 180 181 } else { 182 _ = r.ReadI8() 183 g.x = make([]float64, g.npoints) 184 r.ReadArrayF64(g.x) 185 _ = r.ReadI8() 186 g.y = make([]float64, g.npoints) 187 r.ReadArrayF64(g.y) 188 } 189 190 funcs := r.ReadObjectAny() 191 if funcs != nil { 192 g.funcs = funcs.(root.List) 193 } 194 195 histo := r.ReadObjectAny() 196 if histo != nil { 197 g.histo = histo.(*H1F) 198 } 199 200 if hdr.Vers < 2 { 201 g.min = float64(r.ReadF32()) 202 g.max = float64(r.ReadF32()) 203 } else { 204 g.min = r.ReadF64() 205 g.max = r.ReadF64() 206 } 207 if hdr.Vers > 4 { 208 g.opt = r.ReadString() 209 } 210 211 r.CheckHeader(hdr) 212 return r.Err() 213 } 214 215 func (g *tgraph) RMembers() (mbrs []rbytes.Member) { 216 mbrs = append(mbrs, g.Named.RMembers()...) 217 mbrs = append(mbrs, g.attline.RMembers()...) 218 mbrs = append(mbrs, g.attfill.RMembers()...) 219 mbrs = append(mbrs, g.attmarker.RMembers()...) 220 mbrs = append(mbrs, []rbytes.Member{ 221 {Name: "fNpoints", Value: &g.npoints}, 222 {Name: "fX", Value: &g.x}, 223 {Name: "fY", Value: &g.y}, 224 {Name: "fFunctions", Value: g.funcs}, 225 {Name: "fHistogram", Value: &g.histo}, 226 {Name: "fMinimum", Value: &g.min}, 227 {Name: "fMaximum", Value: &g.max}, 228 {Name: "fOption", Value: &g.opt}, 229 }...) 230 231 return mbrs 232 } 233 234 // MarshalYODA implements the YODAMarshaler interface. 235 func (g *tgraph) MarshalYODA() ([]byte, error) { 236 pts := make([]hbook.Point2D, g.Len()) 237 for i := range pts { 238 x, y := g.XY(i) 239 pts[i].X = x 240 pts[i].Y = y 241 } 242 243 s2d := hbook.NewS2D(pts...) 244 s2d.Annotation()["name"] = g.Name() 245 s2d.Annotation()["title"] = g.Title() 246 return s2d.MarshalYODA() 247 } 248 249 // UnmarshalYODA implements the YODAUnmarshaler interface. 250 func (g *tgraph) UnmarshalYODA(raw []byte) error { 251 var gg hbook.S2D 252 err := gg.UnmarshalYODA(raw) 253 if err != nil { 254 return err 255 } 256 257 *g = *NewGraphFrom(&gg).(*tgraph) 258 return nil 259 } 260 261 // Keys implements the ObjectFinder interface. 262 func (g *tgraph) Keys() []string { 263 var keys []string 264 for i := range g.funcs.Len() { 265 o, ok := g.funcs.At(i).(root.Named) 266 if !ok { 267 continue 268 } 269 keys = append(keys, o.Name()) 270 } 271 return keys 272 } 273 274 // Get implements the ObjectFinder interface. 275 func (g *tgraph) Get(name string) (root.Object, error) { 276 for i := range g.funcs.Len() { 277 o, ok := g.funcs.At(i).(root.Named) 278 if !ok { 279 continue 280 } 281 if o.Name() == name { 282 return g.funcs.At(i), nil 283 } 284 } 285 286 return nil, fmt.Errorf("no object named %q", name) 287 } 288 289 type tgrapherrs struct { 290 tgraph 291 292 xerr []float64 293 yerr []float64 294 } 295 296 func newGraphErrs(n int) *tgrapherrs { 297 return &tgrapherrs{ 298 tgraph: *newGraph(n), 299 xerr: make([]float64, n), 300 yerr: make([]float64, n), 301 } 302 } 303 304 // NewGraphErrorsFrom creates a new GraphErrors from 2-dim hbook data points. 305 func NewGraphErrorsFrom(s2 *hbook.S2D) GraphErrors { 306 var ( 307 n = s2.Len() 308 groot = newGraphErrs(n) 309 ymin = +math.MaxFloat64 310 ymax = -math.MaxFloat64 311 ) 312 313 for i, pt := range s2.Points() { 314 groot.x[i] = pt.X 315 groot.xerr[i] = pt.ErrX.Min 316 groot.y[i] = pt.Y 317 groot.yerr[i] = pt.ErrY.Min 318 319 ymax = math.Max(ymax, pt.Y) 320 ymin = math.Min(ymin, pt.Y) 321 } 322 323 groot.tgraph.Named.SetName(s2.Name()) 324 if v, ok := s2.Annotation()["title"]; ok { 325 groot.tgraph.Named.SetTitle(v.(string)) 326 } 327 328 groot.min = ymin 329 groot.max = ymax 330 331 return groot 332 } 333 334 func (*tgrapherrs) RVersion() int16 { 335 return rvers.GraphErrors 336 } 337 338 func (g *tgrapherrs) Class() string { 339 return "TGraphErrors" 340 } 341 342 func (g *tgrapherrs) XError(i int) (float64, float64) { 343 return g.xerr[i], g.xerr[i] 344 } 345 346 func (g *tgrapherrs) YError(i int) (float64, float64) { 347 return g.yerr[i], g.yerr[i] 348 } 349 350 func (g *tgrapherrs) ROOTMerge(src root.Object) error { 351 switch src := src.(type) { 352 case *tgrapherrs: 353 err := g.tgraph.ROOTMerge(&src.tgraph) 354 if err != nil { 355 return fmt.Errorf("rhist: could not merge %q: %w", src.Name(), err) 356 } 357 g.xerr = append(g.xerr, src.xerr...) 358 g.yerr = append(g.yerr, src.yerr...) 359 // FIXME(sbinet): re-sort x,y,... slices according to x. 360 return nil 361 default: 362 return fmt.Errorf("rhist: can not merge %T into %T", src, g) 363 } 364 } 365 366 // ROOTMarshaler is the interface implemented by an object that can 367 // marshal itself to a ROOT buffer 368 func (g *tgrapherrs) MarshalROOT(w *rbytes.WBuffer) (int, error) { 369 if w.Err() != nil { 370 return 0, nil 371 } 372 373 hdr := w.WriteHeader(g.Class(), g.RVersion()) 374 375 w.WriteObject(&g.tgraph) 376 { 377 w.WriteI8(1) 378 w.WriteArrayF64(g.xerr) 379 w.WriteI8(1) 380 w.WriteArrayF64(g.yerr) 381 } 382 383 return w.SetHeader(hdr) 384 } 385 386 // ROOTUnmarshaler is the interface implemented by an object that can 387 // unmarshal itself from a ROOT buffer 388 func (g *tgrapherrs) UnmarshalROOT(r *rbytes.RBuffer) error { 389 if r.Err() != nil { 390 return r.Err() 391 } 392 393 hdr := r.ReadHeader(g.Class(), g.RVersion()) 394 395 r.ReadObject(&g.tgraph) 396 397 if hdr.Vers < 2 { 398 _ = r.ReadI8() 399 xerrs := make([]float32, g.tgraph.npoints) 400 r.ReadArrayF32(xerrs) 401 _ = r.ReadI8() 402 yerrs := make([]float32, g.tgraph.npoints) 403 r.ReadArrayF32(yerrs) 404 g.xerr = make([]float64, len(xerrs)) 405 g.yerr = make([]float64, len(yerrs)) 406 for i := range xerrs { 407 g.xerr[i] = float64(xerrs[i]) 408 g.yerr[i] = float64(yerrs[i]) 409 } 410 411 } else { 412 _ = r.ReadI8() 413 g.xerr = make([]float64, g.tgraph.npoints) 414 r.ReadArrayF64(g.xerr) 415 _ = r.ReadI8() 416 g.yerr = make([]float64, g.tgraph.npoints) 417 r.ReadArrayF64(g.yerr) 418 } 419 420 r.CheckHeader(hdr) 421 return r.Err() 422 } 423 424 func (g *tgrapherrs) RMembers() (mbrs []rbytes.Member) { 425 mbrs = append(mbrs, g.tgraph.RMembers()...) 426 mbrs = append(mbrs, []rbytes.Member{ 427 {Name: "fEX", Value: &g.xerr}, 428 {Name: "fEY", Value: &g.yerr}, 429 }...) 430 431 return mbrs 432 } 433 434 // MarshalYODA implements the YODAMarshaler interface. 435 func (g *tgrapherrs) MarshalYODA() ([]byte, error) { 436 pts := make([]hbook.Point2D, g.Len()) 437 for i := range pts { 438 x, y := g.XY(i) 439 pts[i].X = x 440 pts[i].Y = y 441 } 442 for i := range pts { 443 xlo, xhi := g.XError(i) 444 ylo, yhi := g.YError(i) 445 pt := &pts[i] 446 pt.ErrX = hbook.Range{Min: xlo, Max: xhi} 447 pt.ErrY = hbook.Range{Min: ylo, Max: yhi} 448 } 449 450 s2d := hbook.NewS2D(pts...) 451 s2d.Annotation()["name"] = g.Name() 452 s2d.Annotation()["title"] = g.Title() 453 return s2d.MarshalYODA() 454 } 455 456 // UnmarshalYODA implements the YODAUnmarshaler interface. 457 func (g *tgrapherrs) UnmarshalYODA(raw []byte) error { 458 var gg hbook.S2D 459 err := gg.UnmarshalYODA(raw) 460 if err != nil { 461 return err 462 } 463 464 *g = *NewGraphErrorsFrom(&gg).(*tgrapherrs) 465 return nil 466 } 467 468 type tgraphasymmerrs struct { 469 tgraph 470 471 xerrlo []float64 472 xerrhi []float64 473 yerrlo []float64 474 yerrhi []float64 475 } 476 477 func newGraphAsymmErrs(n int) *tgraphasymmerrs { 478 return &tgraphasymmerrs{ 479 tgraph: *newGraph(n), 480 xerrlo: make([]float64, n), 481 xerrhi: make([]float64, n), 482 yerrlo: make([]float64, n), 483 yerrhi: make([]float64, n), 484 } 485 } 486 487 // NewGraphAsymmErrorsFrom creates a new GraphAsymErrors from 2-dim hbook data points. 488 func NewGraphAsymmErrorsFrom(s2 *hbook.S2D) GraphErrors { 489 var ( 490 n = s2.Len() 491 groot = newGraphAsymmErrs(n) 492 ymin = +math.MaxFloat64 493 ymax = -math.MaxFloat64 494 ) 495 496 for i, pt := range s2.Points() { 497 groot.x[i] = pt.X 498 groot.xerrlo[i] = pt.ErrX.Min 499 groot.xerrhi[i] = pt.ErrX.Max 500 groot.y[i] = pt.Y 501 groot.yerrlo[i] = pt.ErrY.Min 502 groot.yerrhi[i] = pt.ErrY.Max 503 504 ymax = math.Max(ymax, pt.Y) 505 ymin = math.Min(ymin, pt.Y) 506 } 507 508 groot.tgraph.Named.SetName(s2.Name()) 509 if v, ok := s2.Annotation()["title"]; ok { 510 groot.tgraph.Named.SetTitle(v.(string)) 511 } 512 513 groot.min = ymin 514 groot.max = ymax 515 516 return groot 517 } 518 519 func (*tgraphasymmerrs) RVersion() int16 { 520 return rvers.GraphAsymmErrors 521 } 522 523 func (g *tgraphasymmerrs) Class() string { 524 return "TGraphAsymmErrors" 525 } 526 527 func (g *tgraphasymmerrs) XError(i int) (float64, float64) { 528 return g.xerrlo[i], g.xerrhi[i] 529 } 530 531 func (g *tgraphasymmerrs) YError(i int) (float64, float64) { 532 return g.yerrlo[i], g.yerrhi[i] 533 } 534 535 func (g *tgraphasymmerrs) ROOTMerge(src root.Object) error { 536 switch src := src.(type) { 537 case *tgraphasymmerrs: 538 err := g.tgraph.ROOTMerge(&src.tgraph) 539 if err != nil { 540 return fmt.Errorf("rhist: could not merge %q: %w", src.Name(), err) 541 } 542 g.xerrlo = append(g.xerrlo, src.xerrlo...) 543 g.xerrhi = append(g.xerrhi, src.xerrhi...) 544 g.yerrlo = append(g.yerrlo, src.yerrlo...) 545 g.yerrhi = append(g.yerrhi, src.yerrhi...) 546 // FIXME(sbinet): re-sort x,y,... slices according to x. 547 return nil 548 default: 549 return fmt.Errorf("rhist: can not merge %T into %T", src, g) 550 } 551 } 552 553 // ROOTMarshaler is the interface implemented by an object that can 554 // marshal itself to a ROOT buffer 555 func (g *tgraphasymmerrs) MarshalROOT(w *rbytes.WBuffer) (int, error) { 556 if w.Err() != nil { 557 return 0, w.Err() 558 } 559 560 hdr := w.WriteHeader(g.Class(), g.RVersion()) 561 562 w.WriteObject(&g.tgraph) 563 { 564 w.WriteI8(1) 565 w.WriteArrayF64(g.xerrlo) 566 w.WriteI8(1) 567 w.WriteArrayF64(g.xerrhi) 568 w.WriteI8(1) 569 w.WriteArrayF64(g.yerrlo) 570 w.WriteI8(1) 571 w.WriteArrayF64(g.yerrhi) 572 } 573 574 return w.SetHeader(hdr) 575 } 576 577 // ROOTUnmarshaler is the interface implemented by an object that can 578 // unmarshal itself from a ROOT buffer 579 func (g *tgraphasymmerrs) UnmarshalROOT(r *rbytes.RBuffer) error { 580 if r.Err() != nil { 581 return r.Err() 582 } 583 584 hdr := r.ReadHeader(g.Class(), g.RVersion()) 585 586 r.ReadObject(&g.tgraph) 587 588 n := int(g.tgraph.npoints) 589 g.xerrlo = make([]float64, n) 590 g.xerrhi = make([]float64, n) 591 g.yerrlo = make([]float64, n) 592 g.yerrhi = make([]float64, n) 593 switch { 594 case hdr.Vers < 2: 595 // up to version 2, order is: xlo,ylo,xhi,yhi 596 xerrlo := make([]float32, n) 597 yerrlo := make([]float32, n) 598 xerrhi := make([]float32, n) 599 yerrhi := make([]float32, n) 600 _ = r.ReadI8() 601 r.ReadArrayF32(xerrlo) 602 _ = r.ReadI8() 603 r.ReadArrayF32(yerrlo) 604 _ = r.ReadI8() 605 r.ReadArrayF32(xerrhi) 606 _ = r.ReadI8() 607 r.ReadArrayF32(yerrhi) 608 for i := range xerrlo { 609 g.xerrlo[i] = float64(xerrlo[i]) 610 g.xerrhi[i] = float64(xerrhi[i]) 611 g.yerrlo[i] = float64(yerrlo[i]) 612 g.yerrhi[i] = float64(yerrhi[i]) 613 } 614 case hdr.Vers == 2: 615 // version 2, order is: xlo,ylo,xhi,yhi (but in float64) 616 _ = r.ReadI8() 617 r.ReadArrayF64(g.xerrlo) 618 _ = r.ReadI8() 619 r.ReadArrayF64(g.yerrlo) 620 _ = r.ReadI8() 621 r.ReadArrayF64(g.xerrhi) 622 _ = r.ReadI8() 623 r.ReadArrayF64(g.yerrhi) 624 default: 625 // version 3 and higher: xlo,xhi,ylo,yhi 626 // ie: the order of the fields in the TGraphAsymmErrors class. 627 _ = r.ReadI8() 628 r.ReadArrayF64(g.xerrlo) 629 _ = r.ReadI8() 630 r.ReadArrayF64(g.xerrhi) 631 _ = r.ReadI8() 632 r.ReadArrayF64(g.yerrlo) 633 _ = r.ReadI8() 634 r.ReadArrayF64(g.yerrhi) 635 } 636 637 r.CheckHeader(hdr) 638 return r.Err() 639 } 640 641 func (g *tgraphasymmerrs) RMembers() (mbrs []rbytes.Member) { 642 mbrs = append(mbrs, g.tgraph.RMembers()...) 643 mbrs = append(mbrs, []rbytes.Member{ 644 {Name: "fEXlow", Value: &g.xerrlo}, 645 {Name: "fEXhigh", Value: &g.xerrhi}, 646 {Name: "fEYlow", Value: &g.yerrlo}, 647 {Name: "fEYhigh", Value: &g.yerrhi}, 648 }...) 649 650 return mbrs 651 } 652 653 // MarshalYODA implements the YODAMarshaler interface. 654 func (g *tgraphasymmerrs) MarshalYODA() ([]byte, error) { 655 pts := make([]hbook.Point2D, g.Len()) 656 for i := range pts { 657 x, y := g.XY(i) 658 pts[i].X = x 659 pts[i].Y = y 660 } 661 for i := range pts { 662 xlo, xhi := g.XError(i) 663 ylo, yhi := g.YError(i) 664 pt := &pts[i] 665 pt.ErrX = hbook.Range{Min: xlo, Max: xhi} 666 pt.ErrY = hbook.Range{Min: ylo, Max: yhi} 667 } 668 669 s2d := hbook.NewS2D(pts...) 670 s2d.Annotation()["name"] = g.Name() 671 s2d.Annotation()["title"] = g.Title() 672 return s2d.MarshalYODA() 673 } 674 675 // UnmarshalYODA implements the YODAUnmarshaler interface. 676 func (g *tgraphasymmerrs) UnmarshalYODA(raw []byte) error { 677 var gg hbook.S2D 678 err := gg.UnmarshalYODA(raw) 679 if err != nil { 680 return err 681 } 682 683 *g = *NewGraphAsymmErrorsFrom(&gg).(*tgraphasymmerrs) 684 return nil 685 } 686 687 // tgraphmultierrs is a graph with asymmetric error bars and 688 // multiple y error dimensions. 689 type tgraphmultierrs struct { 690 tgraph 691 692 nyerr int32 // The amount of different y-errors 693 sumErrMode int32 // How y errors are summed: kOnlyFirst = Only First; kSquareSum = Squared Sum; kSum = 694 xerrlo []float64 // array of X low errors 695 xerrhi []float64 // array of X high errors 696 yerrlo []rcont.ArrayD // two dimensional array of Y low errors 697 yerrhi []rcont.ArrayD // two dimensional array of Y high errors 698 attfills []rbase.AttFill // the AttFill attributes of the different errors 699 attlines []rbase.AttLine // the AttLine attributes of the different errors 700 } 701 702 // NewGraphMultiErrorsFrom creates a new GraphMultiErrors from 2-dim hbook data points. 703 func NewGraphMultiErrorsFrom(s2 *hbook.S2D) GraphErrors { 704 return newGraphMultiErrorsFrom(s2) 705 } 706 707 func newGraphMultiErrs(n, ny int) *tgraphmultierrs { 708 g := &tgraphmultierrs{ 709 tgraph: *newGraph(n), 710 nyerr: int32(ny), 711 xerrlo: make([]float64, n), 712 xerrhi: make([]float64, n), 713 yerrlo: make([]rcont.ArrayD, ny), 714 yerrhi: make([]rcont.ArrayD, ny), 715 attfills: make([]rbase.AttFill, n), 716 attlines: make([]rbase.AttLine, n), 717 } 718 for i := range ny { 719 g.yerrlo[i].Data = make([]float64, n) 720 g.yerrhi[i].Data = make([]float64, n) 721 } 722 return g 723 } 724 725 func newGraphMultiErrorsFrom(s2 *hbook.S2D) GraphErrors { 726 var ( 727 n = s2.Len() 728 groot = newGraphMultiErrs(n, 1) 729 ymin = +math.MaxFloat64 730 ymax = -math.MaxFloat64 731 ) 732 for i, pt := range s2.Points() { 733 groot.x[i] = pt.X 734 groot.xerrlo[i] = pt.ErrX.Min 735 groot.xerrhi[i] = pt.ErrX.Max 736 groot.y[i] = pt.Y 737 groot.yerrlo[0].Data[i] = pt.ErrY.Min 738 groot.yerrhi[0].Data[i] = pt.ErrY.Max 739 740 ymax = math.Max(ymax, pt.Y) 741 ymin = math.Min(ymin, pt.Y) 742 } 743 744 groot.tgraph.Named.SetName(s2.Name()) 745 if v, ok := s2.Annotation()["title"]; ok { 746 groot.tgraph.Named.SetTitle(v.(string)) 747 } 748 749 groot.min = ymin 750 groot.max = ymax 751 752 return groot 753 } 754 755 func (*tgraphmultierrs) Class() string { 756 return "TGraphMultiErrors" 757 } 758 759 func (*tgraphmultierrs) RVersion() int16 { 760 return rvers.GraphMultiErrors 761 } 762 763 func (g *tgraphmultierrs) XError(i int) (float64, float64) { 764 return g.xerrlo[i], g.xerrhi[i] 765 } 766 767 func (g *tgraphmultierrs) YError(i int) (float64, float64) { 768 return g.yerrlo[0].At(i), g.yerrhi[0].At(i) 769 } 770 771 // MarshalROOT implements rbytes.Marshaler 772 func (g *tgraphmultierrs) MarshalROOT(w *rbytes.WBuffer) (int, error) { 773 if w.Err() != nil { 774 return 0, w.Err() 775 } 776 777 hdr := w.WriteHeader(g.Class(), g.RVersion()) 778 779 w.WriteObject(&g.tgraph) 780 w.WriteI32(g.nyerr) 781 w.WriteI32(g.sumErrMode) 782 w.WriteI8(1) // is-array 783 w.WriteArrayF64(g.xerrlo[:g.tgraph.npoints]) 784 w.WriteI8(1) // is-array 785 w.WriteArrayF64(g.xerrhi[:g.tgraph.npoints]) 786 writeStdVectorTArrayD(w, g.yerrlo) 787 writeStdVectorTArrayD(w, g.yerrhi) 788 writeStdVectorTAttFill(w, g.attfills) 789 writeStdVectorTAttLine(w, g.attlines) 790 return w.SetHeader(hdr) 791 } 792 793 // UnmarshalROOT implements rbytes.Unmarshaler 794 func (g *tgraphmultierrs) UnmarshalROOT(r *rbytes.RBuffer) error { 795 if r.Err() != nil { 796 return r.Err() 797 } 798 799 hdr := r.ReadHeader(g.Class(), g.RVersion()) 800 801 r.ReadObject(&g.tgraph) 802 803 g.nyerr = r.ReadI32() 804 g.sumErrMode = r.ReadI32() 805 _ = r.ReadI8() // is-array 806 g.xerrlo = rbytes.ResizeF64(nil, int(g.tgraph.npoints)) 807 r.ReadArrayF64(g.xerrlo) 808 _ = r.ReadI8() // is-array 809 g.xerrhi = rbytes.ResizeF64(nil, int(g.tgraph.npoints)) 810 r.ReadArrayF64(g.xerrhi) 811 readStdVectorTArrayD(r, &g.yerrlo) 812 readStdVectorTArrayD(r, &g.yerrhi) 813 readStdVectorTAttFill(r, &g.attfills) 814 readStdVectorTAttLine(r, &g.attlines) 815 816 r.CheckHeader(hdr) 817 return r.Err() 818 } 819 820 func (g *tgraphmultierrs) RMembers() (mbrs []rbytes.Member) { 821 var ( 822 yerrlo = make([][]float64, len(g.yerrlo)) 823 yerrhi = make([][]float64, len(g.yerrhi)) 824 ) 825 for i, v := range g.yerrlo { 826 yerrlo[i] = v.Data 827 } 828 829 for i, v := range g.yerrhi { 830 yerrhi[i] = v.Data 831 } 832 833 var ( 834 attfills = make([]*rbase.AttFill, len(g.attfills)) 835 attlines = make([]*rbase.AttLine, len(g.attlines)) 836 ) 837 for i := range g.attfills { 838 attfills[i] = &g.attfills[i] 839 } 840 for i := range g.attlines { 841 attlines[i] = &g.attlines[i] 842 } 843 mbrs = append(mbrs, g.tgraph.RMembers()...) 844 mbrs = append(mbrs, []rbytes.Member{ 845 {Name: "fNYErrors", Value: &g.nyerr}, 846 {Name: "fSumErrorsMode", Value: &g.sumErrMode}, 847 {Name: "fExL", Value: &g.xerrlo}, 848 {Name: "fExH", Value: &g.xerrhi}, 849 {Name: "fEyL", Value: &yerrlo}, 850 {Name: "fEyH", Value: &yerrhi}, 851 {Name: "fAttFill", Value: attfills}, 852 {Name: "fAttLine", Value: attlines}, 853 }...) 854 855 return mbrs 856 } 857 858 // MarshalYODA implements the YODAMarshaler interface. 859 func (g *tgraphmultierrs) MarshalYODA() ([]byte, error) { 860 pts := make([]hbook.Point2D, g.Len()) 861 for i := range pts { 862 x, y := g.XY(i) 863 pts[i].X = x 864 pts[i].Y = y 865 } 866 for i := range pts { 867 xlo, xhi := g.XError(i) 868 ylo, yhi := g.YError(i) 869 pt := &pts[i] 870 pt.ErrX = hbook.Range{Min: xlo, Max: xhi} 871 pt.ErrY = hbook.Range{Min: ylo, Max: yhi} 872 } 873 874 // FIXME(sbinet): add a yoda-compatible representation 875 // for multi-errors? 876 s2d := hbook.NewS2D(pts...) 877 s2d.Annotation()["name"] = g.Name() 878 s2d.Annotation()["title"] = g.Title() 879 return s2d.MarshalYODA() 880 } 881 882 // UnmarshalYODA implements the YODAUnmarshaler interface. 883 func (g *tgraphmultierrs) UnmarshalYODA(raw []byte) error { 884 var gg hbook.S2D 885 err := gg.UnmarshalYODA(raw) 886 if err != nil { 887 return err 888 } 889 890 *g = *newGraphMultiErrorsFrom(&gg).(*tgraphmultierrs) 891 return nil 892 } 893 894 func init() { 895 { 896 f := func() reflect.Value { 897 o := newGraph(0) 898 return reflect.ValueOf(o) 899 } 900 rtypes.Factory.Add("TGraph", f) 901 } 902 { 903 f := func() reflect.Value { 904 o := newGraphErrs(0) 905 return reflect.ValueOf(o) 906 } 907 rtypes.Factory.Add("TGraphErrors", f) 908 } 909 { 910 f := func() reflect.Value { 911 o := newGraphAsymmErrs(0) 912 return reflect.ValueOf(o) 913 } 914 rtypes.Factory.Add("TGraphAsymmErrors", f) 915 } 916 { 917 f := func() reflect.Value { 918 o := newGraphMultiErrs(0, 0) 919 return reflect.ValueOf(o) 920 } 921 rtypes.Factory.Add("TGraphMultiErrors", f) 922 } 923 } 924 925 var ( 926 _ root.Object = (*tgraph)(nil) 927 _ root.Named = (*tgraph)(nil) 928 _ root.Merger = (*tgraph)(nil) 929 _ root.ObjectFinder = (*tgraph)(nil) 930 _ Graph = (*tgraph)(nil) 931 _ rbytes.Marshaler = (*tgraph)(nil) 932 _ rbytes.Unmarshaler = (*tgraph)(nil) 933 _ rbytes.RSlicer = (*tgraph)(nil) 934 _ yodacnv.Marshaler = (*tgraph)(nil) 935 _ yodacnv.Unmarshaler = (*tgraph)(nil) 936 937 _ root.Object = (*tgrapherrs)(nil) 938 _ root.Named = (*tgrapherrs)(nil) 939 _ root.Merger = (*tgrapherrs)(nil) 940 _ root.ObjectFinder = (*tgrapherrs)(nil) 941 _ Graph = (*tgrapherrs)(nil) 942 _ GraphErrors = (*tgrapherrs)(nil) 943 _ rbytes.Marshaler = (*tgrapherrs)(nil) 944 _ rbytes.Unmarshaler = (*tgrapherrs)(nil) 945 _ rbytes.RSlicer = (*tgrapherrs)(nil) 946 _ yodacnv.Marshaler = (*tgrapherrs)(nil) 947 _ yodacnv.Unmarshaler = (*tgrapherrs)(nil) 948 949 _ root.Object = (*tgraphasymmerrs)(nil) 950 _ root.Named = (*tgraphasymmerrs)(nil) 951 _ root.Merger = (*tgraphasymmerrs)(nil) 952 _ root.ObjectFinder = (*tgraphasymmerrs)(nil) 953 _ Graph = (*tgraphasymmerrs)(nil) 954 _ GraphErrors = (*tgraphasymmerrs)(nil) 955 _ rbytes.Marshaler = (*tgraphasymmerrs)(nil) 956 _ rbytes.Unmarshaler = (*tgraphasymmerrs)(nil) 957 _ rbytes.RSlicer = (*tgraphasymmerrs)(nil) 958 _ yodacnv.Marshaler = (*tgraphasymmerrs)(nil) 959 _ yodacnv.Unmarshaler = (*tgraphasymmerrs)(nil) 960 961 _ root.Object = (*tgraphmultierrs)(nil) 962 _ root.Named = (*tgraphmultierrs)(nil) 963 _ root.Merger = (*tgraphmultierrs)(nil) 964 _ root.ObjectFinder = (*tgraphmultierrs)(nil) 965 _ Graph = (*tgraphmultierrs)(nil) 966 _ GraphErrors = (*tgraphmultierrs)(nil) 967 _ rbytes.Marshaler = (*tgraphmultierrs)(nil) 968 _ rbytes.Unmarshaler = (*tgraphmultierrs)(nil) 969 _ rbytes.RSlicer = (*tgraphmultierrs)(nil) 970 _ yodacnv.Marshaler = (*tgraphmultierrs)(nil) 971 _ yodacnv.Unmarshaler = (*tgraphmultierrs)(nil) 972 ) 973 974 func writeStdVectorTArrayD(w *rbytes.WBuffer, vs []rcont.ArrayD) { 975 if w.Err() != nil { 976 return 977 } 978 const typename = "vector<TArrayD>" 979 hdr := w.WriteHeader(typename, rvers.StreamerBaseSTL) 980 w.WriteI32(int32(len(vs))) 981 for i := range vs { 982 w.WriteObject(&vs[i]) 983 } 984 _, _ = w.SetHeader(hdr) 985 } 986 987 func writeStdVectorTAttFill(w *rbytes.WBuffer, vs []rbase.AttFill) { 988 if w.Err() != nil { 989 return 990 } 991 const typename = "vector<TAttFill>" 992 hdr := w.WriteHeader(typename, rvers.StreamerBaseSTL) 993 w.WriteI32(int32(len(vs))) 994 for i := range vs { 995 w.WriteObject(&vs[i]) 996 } 997 _, _ = w.SetHeader(hdr) 998 } 999 1000 func writeStdVectorTAttLine(w *rbytes.WBuffer, vs []rbase.AttLine) { 1001 if w.Err() != nil { 1002 return 1003 } 1004 const typename = "vector<TAttLine>" 1005 hdr := w.WriteHeader(typename, rvers.StreamerBaseSTL) 1006 w.WriteI32(int32(len(vs))) 1007 for i := range vs { 1008 w.WriteObject(&vs[i]) 1009 } 1010 _, _ = w.SetHeader(hdr) 1011 } 1012 1013 func readStdVectorTArrayD(r *rbytes.RBuffer, vs *[]rcont.ArrayD) { 1014 if r.Err() != nil { 1015 return 1016 } 1017 1018 hdr := r.ReadHeader("vector<TArrayD>", rvers.StreamerBaseSTL) 1019 1020 // FIXME(sbinet): use rbytes.Resize[T] 1021 n := int(r.ReadI32()) 1022 if n == 0 { 1023 *vs = nil 1024 r.CheckHeader(hdr) 1025 return 1026 } 1027 *vs = make([]rcont.ArrayD, n) 1028 for i := range *vs { 1029 r.ReadObject(&(*vs)[i]) 1030 } 1031 1032 r.CheckHeader(hdr) 1033 } 1034 1035 func readStdVectorTAttFill(r *rbytes.RBuffer, vs *[]rbase.AttFill) { 1036 if r.Err() != nil { 1037 return 1038 } 1039 1040 hdr := r.ReadHeader("vector<TAttFill>", rvers.StreamerBaseSTL) 1041 if hdr.MemberWise { 1042 clvers := r.ReadI16() 1043 switch { 1044 case clvers == 1: 1045 // TODO 1046 case clvers <= 0: 1047 /*chksum*/ _ = r.ReadU32() 1048 } 1049 } 1050 1051 // FIXME(sbinet): use rbytes.Resize[T] 1052 n := int(r.ReadI32()) 1053 if n == 0 { 1054 *vs = nil 1055 r.CheckHeader(hdr) 1056 return 1057 } 1058 1059 *vs = make([]rbase.AttFill, n) 1060 switch { 1061 case hdr.MemberWise: 1062 p := make([]int16, n) 1063 r.ReadArrayI16(p) 1064 for i := range *vs { 1065 (*vs)[i].Color = p[i] 1066 } 1067 r.ReadArrayI16(p) 1068 for i := range *vs { 1069 (*vs)[i].Style = p[i] 1070 } 1071 default: 1072 for i := range *vs { 1073 r.ReadObject(&(*vs)[i]) 1074 } 1075 } 1076 1077 r.CheckHeader(hdr) 1078 } 1079 1080 func readStdVectorTAttLine(r *rbytes.RBuffer, vs *[]rbase.AttLine) { 1081 if r.Err() != nil { 1082 return 1083 } 1084 1085 hdr := r.ReadHeader("vector<TAttLine>", rvers.StreamerBaseSTL) 1086 if hdr.MemberWise { 1087 clvers := r.ReadI16() 1088 switch { 1089 case clvers == 1: 1090 // TODO 1091 case clvers <= 0: 1092 /*chksum*/ _ = r.ReadU32() 1093 } 1094 } 1095 1096 // FIXME(sbinet): use rbytes.Resize[T] 1097 n := int(r.ReadI32()) 1098 if n == 0 { 1099 *vs = nil 1100 r.CheckHeader(hdr) 1101 return 1102 } 1103 *vs = make([]rbase.AttLine, n) 1104 switch { 1105 case hdr.MemberWise: 1106 p := make([]int16, n) 1107 r.ReadArrayI16(p) 1108 for i := range *vs { 1109 (*vs)[i].Color = p[i] 1110 } 1111 r.ReadArrayI16(p) 1112 for i := range *vs { 1113 (*vs)[i].Style = p[i] 1114 } 1115 r.ReadArrayI16(p) 1116 for i := range *vs { 1117 (*vs)[i].Width = p[i] 1118 } 1119 default: 1120 for i := range *vs { 1121 r.ReadObject(&(*vs)[i]) 1122 } 1123 } 1124 1125 r.CheckHeader(hdr) 1126 }