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  }