Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

groot: add support for TScatter #1007

Merged
merged 1 commit into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions groot/gen.rboot.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ var (
"TLimit", "TLimitDataSource",
"TMultiGraph",
"TProfile", "TProfile2D",
"TScatter",

// riofs
"TDirectory",
Expand Down
158 changes: 158 additions & 0 deletions groot/rdict/cxx_root_streamers_gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -4946,6 +4946,164 @@ func init() {
Factor: 0.000000,
}.New()},
}))
StreamerInfos.Add(NewCxxStreamerInfo("TScatter", 2, 0xc091e335, []rbytes.StreamerElement{
NewStreamerBase(Element{
Name: *rbase.NewNamed("TNamed", "The basis for a named object (name, title)"),
Type: rmeta.Base,
Size: 0,
ArrLen: 0,
ArrDim: 0,
MaxIdx: [5]int32{0, -541636036, 0, 0, 0},
Offset: 0,
EName: "BASE",
XMin: 0.000000,
XMax: 0.000000,
Factor: 0.000000,
}.New(), 1),
NewStreamerBase(Element{
Name: *rbase.NewNamed("TAttLine", "Line attributes"),
Type: rmeta.Base,
Size: 0,
ArrLen: 0,
ArrDim: 0,
MaxIdx: [5]int32{0, -1811462839, 0, 0, 0},
Offset: 0,
EName: "BASE",
XMin: 0.000000,
XMax: 0.000000,
Factor: 0.000000,
}.New(), 2),
NewStreamerBase(Element{
Name: *rbase.NewNamed("TAttFill", "Fill area attributes"),
Type: rmeta.Base,
Size: 0,
ArrLen: 0,
ArrDim: 0,
MaxIdx: [5]int32{0, -2545006, 0, 0, 0},
Offset: 0,
EName: "BASE",
XMin: 0.000000,
XMax: 0.000000,
Factor: 0.000000,
}.New(), 2),
NewStreamerBase(Element{
Name: *rbase.NewNamed("TAttMarker", "Marker attributes"),
Type: rmeta.Base,
Size: 0,
ArrLen: 0,
ArrDim: 0,
MaxIdx: [5]int32{0, 689802220, 0, 0, 0},
Offset: 0,
EName: "BASE",
XMin: 0.000000,
XMax: 0.000000,
Factor: 0.000000,
}.New(), 2),
&StreamerBasicType{StreamerElement: Element{
Name: *rbase.NewNamed("fNpoints", "Number of points <= fMaxSize"),
Type: rmeta.Counter,
Size: 4,
ArrLen: 0,
ArrDim: 0,
MaxIdx: [5]int32{0, 0, 0, 0, 0},
Offset: 0,
EName: "int",
XMin: 0.000000,
XMax: 0.000000,
Factor: 0.000000,
}.New()},
&StreamerObjectPointer{StreamerElement: Element{
Name: *rbase.NewNamed("fHistogram", "Pointer to histogram used for drawing axis"),
Type: rmeta.ObjectP,
Size: 8,
ArrLen: 0,
ArrDim: 0,
MaxIdx: [5]int32{0, 0, 0, 0, 0},
Offset: 0,
EName: "TH2F*",
XMin: 0.000000,
XMax: 0.000000,
Factor: 0.000000,
}.New()},
&StreamerObjectPointer{StreamerElement: Element{
Name: *rbase.NewNamed("fGraph", "Pointer to graph holding X and Y positions"),
Type: rmeta.ObjectP,
Size: 8,
ArrLen: 0,
ArrDim: 0,
MaxIdx: [5]int32{0, 0, 0, 0, 0},
Offset: 0,
EName: "TGraph*",
XMin: 0.000000,
XMax: 0.000000,
Factor: 0.000000,
}.New()},
NewStreamerBasicPointer(Element{
Name: *rbase.NewNamed("fColor", "[fNpoints] array of colors"),
Type: 48,
Size: 8,
ArrLen: 0,
ArrDim: 0,
MaxIdx: [5]int32{0, 0, 0, 0, 0},
Offset: 0,
EName: "double*",
XMin: 0.000000,
XMax: 0.000000,
Factor: 0.000000,
}.New(), 2, "fNpoints", "TScatter"),
NewStreamerBasicPointer(Element{
Name: *rbase.NewNamed("fSize", "[fNpoints] array of marker sizes"),
Type: 48,
Size: 8,
ArrLen: 0,
ArrDim: 0,
MaxIdx: [5]int32{0, 0, 0, 0, 0},
Offset: 0,
EName: "double*",
XMin: 0.000000,
XMax: 0.000000,
Factor: 0.000000,
}.New(), 2, "fNpoints", "TScatter"),
&StreamerBasicType{StreamerElement: Element{
Name: *rbase.NewNamed("fMaxMarkerSize", "Largest marker size used to paint the markers"),
Type: rmeta.Double,
Size: 8,
ArrLen: 0,
ArrDim: 0,
MaxIdx: [5]int32{0, 0, 0, 0, 0},
Offset: 0,
EName: "double",
XMin: 0.000000,
XMax: 0.000000,
Factor: 0.000000,
}.New()},
&StreamerBasicType{StreamerElement: Element{
Name: *rbase.NewNamed("fMinMarkerSize", "Smallest marker size used to paint the markers"),
Type: rmeta.Double,
Size: 8,
ArrLen: 0,
ArrDim: 0,
MaxIdx: [5]int32{0, 0, 0, 0, 0},
Offset: 0,
EName: "double",
XMin: 0.000000,
XMax: 0.000000,
Factor: 0.000000,
}.New()},
&StreamerBasicType{StreamerElement: Element{
Name: *rbase.NewNamed("fMargin", "Margin around the plot in %"),
Type: rmeta.Double,
Size: 8,
ArrLen: 0,
ArrDim: 0,
MaxIdx: [5]int32{0, 0, 0, 0, 0},
Offset: 0,
EName: "double",
XMin: 0.000000,
XMax: 0.000000,
Factor: 0.000000,
}.New()},
}))
StreamerInfos.Add(NewCxxStreamerInfo("TDirectory", 5, 0x1e9b6f70, []rbytes.StreamerElement{
NewStreamerBase(Element{
Name: *rbase.NewNamed("TNamed", "The basis for a named object (name, title)"),
Expand Down
4 changes: 4 additions & 0 deletions groot/rhist/rw_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,10 @@ func TestWRBuffer(t *testing.T) {
name: "TMultiGraph",
want: loadFrom("../testdata/tgme.root", "mg"),
},
{
name: "TScatter",
want: loadFrom("../testdata/tscatter.root", "scatter"),
},
} {
t.Run(tc.name, func(t *testing.T) {
{
Expand Down
196 changes: 196 additions & 0 deletions groot/rhist/scatter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
// Copyright ©2024 The go-hep Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package rhist

import (
"fmt"
"math"
"reflect"

"go-hep.org/x/hep/groot/rbase"
"go-hep.org/x/hep/groot/rbytes"
"go-hep.org/x/hep/groot/root"
"go-hep.org/x/hep/groot/rtypes"
"go-hep.org/x/hep/groot/rvers"
)

// Scatter implements ROOT's TScatter.
// A scatter plot able to draw four variables on a single plot.
type Scatter struct {
rbase.Named
attline rbase.AttLine
attfill rbase.AttFill
attmarker rbase.AttMarker

npoints int32 // Number of points <= fMaxSize
histo *H2F // Pointer to histogram used for drawing axis
graph *tgraph // Pointer to graph holding X and Y positions
color []float64 // [fNpoints] array of colors
size []float64 // [fNpoints] array of marker sizes

maxMarkerSize float64 // Largest marker size used to paint the markers
minMarkerSize float64 // Smallest marker size used to paint the markers
margin float64 // Margin around the plot in %
}

func newScatter(n int) *Scatter {
return &Scatter{
Named: *rbase.NewNamed("", ""),
attline: *rbase.NewAttLine(),
attfill: *rbase.NewAttFill(),
attmarker: *rbase.NewAttMarker(),
npoints: int32(n),
color: make([]float64, n),
size: make([]float64, n),
maxMarkerSize: 5,
minMarkerSize: 1,
margin: 0.1,
}
}

func (*Scatter) RVersion() int16 {
return rvers.Scatter
}

func (*Scatter) Class() string {
return "TScatter"
}

func (s *Scatter) ROOTMerge(src root.Object) error {
switch src := src.(type) {
case *Scatter:
var err error
s.npoints += src.npoints
// FIXME(sbinet): implement ROOTMerge for TH2x
// err = s.histo.ROOTMerge(src.histo)
// if err != nil {
// return fmt.Errorf("rhist: could not merge Scatter's underlying H2F: %w", err)
// }
err = s.graph.ROOTMerge(src.graph)
if err != nil {
return fmt.Errorf("rhist: could not merge Scatter's underlying Graph: %w", err)
}
s.color = append(s.color, src.color...)
s.size = append(s.size, src.size...)
s.maxMarkerSize = math.Max(s.maxMarkerSize, src.maxMarkerSize)
s.minMarkerSize = math.Min(s.minMarkerSize, src.minMarkerSize)
// FIXME(sbinet): handle margin
return nil
default:
return fmt.Errorf("rhist: can not merge %T into %T", src, s)
}
}

// ROOTMarshaler is the interface implemented by an object that can
// marshal itself to a ROOT buffer
func (s *Scatter) MarshalROOT(w *rbytes.WBuffer) (int, error) {
if w.Err() != nil {
return 0, w.Err()
}

hdr := w.WriteHeader(s.Class(), s.RVersion())

w.WriteObject(&s.Named)
w.WriteObject(&s.attline)
w.WriteObject(&s.attfill)
w.WriteObject(&s.attmarker)

w.WriteI32(s.npoints)
w.WriteObjectAny(s.histo)
w.WriteObjectAny(s.graph)

w.WriteI8(1)
w.WriteArrayF64(s.color)
w.WriteI8(1)
w.WriteArrayF64(s.size)

w.WriteF64(s.maxMarkerSize)
w.WriteF64(s.minMarkerSize)
w.WriteF64(s.margin)

return w.SetHeader(hdr)
}

// ROOTUnmarshaler is the interface implemented by an object that can
// unmarshal itself from a ROOT buffer
func (s *Scatter) UnmarshalROOT(r *rbytes.RBuffer) error {
if r.Err() != nil {
return r.Err()
}

hdr := r.ReadHeader(s.Class(), s.RVersion())

r.ReadObject(&s.Named)
r.ReadObject(&s.attline)
r.ReadObject(&s.attfill)
r.ReadObject(&s.attmarker)

s.npoints = r.ReadI32()
if hdr.Vers < 2 {
r.SetErr(fmt.Errorf("rhist: invalid TScatter version %d", hdr.Vers))
return r.Err()
}

histo := r.ReadObjectAny()
if histo != nil {
s.histo = histo.(*H2F)
}
graph := r.ReadObjectAny()
if graph != nil {
s.graph = graph.(*tgraph)
}

_ = r.ReadI8()
s.color = make([]float64, s.npoints)
r.ReadArrayF64(s.color)
_ = r.ReadI8()
s.size = make([]float64, s.npoints)
r.ReadArrayF64(s.size)

s.maxMarkerSize = r.ReadF64()
s.minMarkerSize = r.ReadF64()
s.margin = r.ReadF64()

r.CheckHeader(hdr)
return r.Err()
}

func (g *Scatter) RMembers() (mbrs []rbytes.Member) {
mbrs = append(mbrs, g.Named.RMembers()...)
mbrs = append(mbrs, g.attline.RMembers()...)
mbrs = append(mbrs, g.attfill.RMembers()...)
mbrs = append(mbrs, g.attmarker.RMembers()...)
mbrs = append(mbrs, []rbytes.Member{
{Name: "fNpoints", Value: &g.npoints},
{Name: "fHistogram", Value: &g.histo},
{Name: "fGraph", Value: &g.graph},
{Name: "fColor", Value: &g.color},
{Name: "fSize", Value: &g.size},
{Name: "fMaxMarkerSize", Value: &g.maxMarkerSize},
{Name: "fMinMarkerSize", Value: &g.minMarkerSize},
{Name: "fMargin", Value: &g.margin},
}...)

return mbrs
}

func init() {
{
f := func() reflect.Value {
o := newScatter(0)
return reflect.ValueOf(o)
}
rtypes.Factory.Add("TScatter", f)
}
}

var (
_ root.Object = (*Scatter)(nil)
_ root.Named = (*Scatter)(nil)
_ root.Merger = (*Scatter)(nil)
_ rbytes.Marshaler = (*Scatter)(nil)
_ rbytes.Unmarshaler = (*Scatter)(nil)
_ rbytes.RSlicer = (*Scatter)(nil)
)
Loading
Loading