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 )