go-hep.org/x/hep@v0.38.1/groot/rhist/scatter.go (about)

     1  // Copyright ©2024 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/root"
    15  	"go-hep.org/x/hep/groot/rtypes"
    16  	"go-hep.org/x/hep/groot/rvers"
    17  )
    18  
    19  // Scatter implements ROOT's TScatter.
    20  // A scatter plot able to draw four variables on a single plot.
    21  type Scatter struct {
    22  	rbase.Named
    23  	attline   rbase.AttLine
    24  	attfill   rbase.AttFill
    25  	attmarker rbase.AttMarker
    26  
    27  	npoints int32     // Number of points <= fMaxSize
    28  	histo   *H2F      // Pointer to histogram used for drawing axis
    29  	graph   *tgraph   // Pointer to graph holding X and Y positions
    30  	color   []float64 // [fNpoints] array of colors
    31  	size    []float64 // [fNpoints] array of marker sizes
    32  
    33  	maxMarkerSize float64 // Largest marker size used to paint the markers
    34  	minMarkerSize float64 // Smallest marker size used to paint the markers
    35  	margin        float64 // Margin around the plot in %
    36  }
    37  
    38  func newScatter(n int) *Scatter {
    39  	return &Scatter{
    40  		Named:         *rbase.NewNamed("", ""),
    41  		attline:       *rbase.NewAttLine(),
    42  		attfill:       *rbase.NewAttFill(),
    43  		attmarker:     *rbase.NewAttMarker(),
    44  		npoints:       int32(n),
    45  		color:         make([]float64, n),
    46  		size:          make([]float64, n),
    47  		maxMarkerSize: 5,
    48  		minMarkerSize: 1,
    49  		margin:        0.1,
    50  	}
    51  }
    52  
    53  func (*Scatter) RVersion() int16 {
    54  	return rvers.Scatter
    55  }
    56  
    57  func (*Scatter) Class() string {
    58  	return "TScatter"
    59  }
    60  
    61  func (s *Scatter) ROOTMerge(src root.Object) error {
    62  	switch src := src.(type) {
    63  	case *Scatter:
    64  		var err error
    65  		s.npoints += src.npoints
    66  		// FIXME(sbinet): implement ROOTMerge for TH2x
    67  		//	err = s.histo.ROOTMerge(src.histo)
    68  		//	if err != nil {
    69  		//		return fmt.Errorf("rhist: could not merge Scatter's underlying H2F: %w", err)
    70  		//	}
    71  		err = s.graph.ROOTMerge(src.graph)
    72  		if err != nil {
    73  			return fmt.Errorf("rhist: could not merge Scatter's underlying Graph: %w", err)
    74  		}
    75  		s.color = append(s.color, src.color...)
    76  		s.size = append(s.size, src.size...)
    77  		s.maxMarkerSize = math.Max(s.maxMarkerSize, src.maxMarkerSize)
    78  		s.minMarkerSize = math.Min(s.minMarkerSize, src.minMarkerSize)
    79  		// FIXME(sbinet): handle margin
    80  		return nil
    81  	default:
    82  		return fmt.Errorf("rhist: can not merge %T into %T", src, s)
    83  	}
    84  }
    85  
    86  // ROOTMarshaler is the interface implemented by an object that can
    87  // marshal itself to a ROOT buffer
    88  func (s *Scatter) MarshalROOT(w *rbytes.WBuffer) (int, error) {
    89  	if w.Err() != nil {
    90  		return 0, w.Err()
    91  	}
    92  
    93  	hdr := w.WriteHeader(s.Class(), s.RVersion())
    94  
    95  	w.WriteObject(&s.Named)
    96  	w.WriteObject(&s.attline)
    97  	w.WriteObject(&s.attfill)
    98  	w.WriteObject(&s.attmarker)
    99  
   100  	w.WriteI32(s.npoints)
   101  	w.WriteObjectAny(s.histo)
   102  	w.WriteObjectAny(s.graph)
   103  
   104  	w.WriteI8(1)
   105  	w.WriteArrayF64(s.color)
   106  	w.WriteI8(1)
   107  	w.WriteArrayF64(s.size)
   108  
   109  	w.WriteF64(s.maxMarkerSize)
   110  	w.WriteF64(s.minMarkerSize)
   111  	w.WriteF64(s.margin)
   112  
   113  	return w.SetHeader(hdr)
   114  }
   115  
   116  // ROOTUnmarshaler is the interface implemented by an object that can
   117  // unmarshal itself from a ROOT buffer
   118  func (s *Scatter) UnmarshalROOT(r *rbytes.RBuffer) error {
   119  	if r.Err() != nil {
   120  		return r.Err()
   121  	}
   122  
   123  	hdr := r.ReadHeader(s.Class(), s.RVersion())
   124  
   125  	r.ReadObject(&s.Named)
   126  	r.ReadObject(&s.attline)
   127  	r.ReadObject(&s.attfill)
   128  	r.ReadObject(&s.attmarker)
   129  
   130  	s.npoints = r.ReadI32()
   131  	if hdr.Vers < 2 {
   132  		r.SetErr(fmt.Errorf("rhist: invalid TScatter version %d", hdr.Vers))
   133  		return r.Err()
   134  	}
   135  
   136  	histo := r.ReadObjectAny()
   137  	if histo != nil {
   138  		s.histo = histo.(*H2F)
   139  	}
   140  	graph := r.ReadObjectAny()
   141  	if graph != nil {
   142  		s.graph = graph.(*tgraph)
   143  	}
   144  
   145  	_ = r.ReadI8()
   146  	s.color = make([]float64, s.npoints)
   147  	r.ReadArrayF64(s.color)
   148  	_ = r.ReadI8()
   149  	s.size = make([]float64, s.npoints)
   150  	r.ReadArrayF64(s.size)
   151  
   152  	s.maxMarkerSize = r.ReadF64()
   153  	s.minMarkerSize = r.ReadF64()
   154  	s.margin = r.ReadF64()
   155  
   156  	r.CheckHeader(hdr)
   157  	return r.Err()
   158  }
   159  
   160  func (g *Scatter) RMembers() (mbrs []rbytes.Member) {
   161  	mbrs = append(mbrs, g.Named.RMembers()...)
   162  	mbrs = append(mbrs, g.attline.RMembers()...)
   163  	mbrs = append(mbrs, g.attfill.RMembers()...)
   164  	mbrs = append(mbrs, g.attmarker.RMembers()...)
   165  	mbrs = append(mbrs, []rbytes.Member{
   166  		{Name: "fNpoints", Value: &g.npoints},
   167  		{Name: "fHistogram", Value: &g.histo},
   168  		{Name: "fGraph", Value: &g.graph},
   169  		{Name: "fColor", Value: &g.color},
   170  		{Name: "fSize", Value: &g.size},
   171  		{Name: "fMaxMarkerSize", Value: &g.maxMarkerSize},
   172  		{Name: "fMinMarkerSize", Value: &g.minMarkerSize},
   173  		{Name: "fMargin", Value: &g.margin},
   174  	}...)
   175  
   176  	return mbrs
   177  }
   178  
   179  func init() {
   180  	{
   181  		f := func() reflect.Value {
   182  			o := newScatter(0)
   183  			return reflect.ValueOf(o)
   184  		}
   185  		rtypes.Factory.Add("TScatter", f)
   186  	}
   187  }
   188  
   189  var (
   190  	_ root.Object        = (*Scatter)(nil)
   191  	_ root.Named         = (*Scatter)(nil)
   192  	_ root.Merger        = (*Scatter)(nil)
   193  	_ rbytes.Marshaler   = (*Scatter)(nil)
   194  	_ rbytes.Unmarshaler = (*Scatter)(nil)
   195  	_ rbytes.RSlicer     = (*Scatter)(nil)
   196  )