Thanks to visit codestin.com
Credit goes to github.com

Skip to content
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
4 changes: 3 additions & 1 deletion examples/grids/grids.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ func main() {
plt := plotcore.NewEditor(ct)
ctb.Maker(plt.MakeToolbar)

cluster.PlotFromTable(plt, pats, metric.MetricL2Norm, cluster.Min, "Input", "Name")
pt := table.New()
cluster.PlotFromTable(pt, pats, metric.MetricL2Norm, cluster.Min, "Input", "Name")
plt.SetTable(pt)

b.RunMainWindow()
}
7 changes: 6 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@ module cogentcore.org/lab
go 1.23.4

// after go mod tidy, you need to run:
// go get google.golang.org/[email protected]
// when updating go version:
// go get google.golang.org/genproto@latest
// otherwise there will be an ambiguous import warning when building baremetal
// https://github.com/googleapis/go-genproto/issues/1015

require (
cogentcore.org/core v0.3.13-0.20250807231547-ae1e4f43215b
cogentcore.org/core v0.3.13-0.20250909222513-1cba37a21a69
github.com/alecthomas/assert/v2 v2.6.0
github.com/cogentcore/readline v0.1.3
github.com/cogentcore/yaegi v0.0.0-20250622201820-b7838bdd95eb
github.com/mitchellh/go-homedir v1.1.0
Expand All @@ -26,6 +29,7 @@ require (
github.com/Masterminds/vcs v1.13.3 // indirect
github.com/adrg/strutil v0.3.1 // indirect
github.com/alecthomas/chroma/v2 v2.13.0 // indirect
github.com/alecthomas/repr v0.4.0 // indirect
github.com/anthonynsimon/bild v0.13.0 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/aymerick/douceur v0.2.0 // indirect
Expand All @@ -45,6 +49,7 @@ require (
github.com/hack-pad/go-indexeddb v0.3.2 // indirect
github.com/hack-pad/hackpadfs v0.2.1 // indirect
github.com/hack-pad/safejs v0.1.1 // indirect
github.com/hexops/gotextdiff v1.0.3 // indirect
github.com/jinzhu/copier v0.4.0 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
cogentcore.org/core v0.3.13-0.20250807231547-ae1e4f43215b h1:tU7qgAArL2VmAFghD6t8KfPUAzveTX5loP3+Dp4Vq90=
cogentcore.org/core v0.3.13-0.20250807231547-ae1e4f43215b/go.mod h1:8zfSRZhuM/4OTMt8i1Q8W0P2VcD1riw2AgEQNmv8wHQ=
cogentcore.org/core v0.3.13-0.20250909222513-1cba37a21a69 h1:P2aEix7cbJtYrRzBU6xtvQDRWt452OPEi1dcoD6SWUQ=
cogentcore.org/core v0.3.13-0.20250909222513-1cba37a21a69/go.mod h1:8zfSRZhuM/4OTMt8i1Q8W0P2VcD1riw2AgEQNmv8wHQ=
github.com/Bios-Marcel/wastebasket/v2 v2.0.3 h1:TkoDPcSqluhLGE+EssHu7UGmLgUEkWg7kNyHyyJ3Q9g=
github.com/Bios-Marcel/wastebasket/v2 v2.0.3/go.mod h1:769oPCv6eH7ugl90DYIsWwjZh4hgNmMS3Zuhe1bH6KU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
Expand Down
7 changes: 7 additions & 0 deletions plot/axis.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,13 @@ func (ax *Axis) SanitizeRange() {
}
}

func (ax *Axis) SetTickLabel(i int, lbl string) {
if len(ax.ticks) <= i {
return
}
ax.ticks[i].Label = lbl
}

// Normalizer rescales values from the data coordinate system to the
// normalized coordinate system.
type Normalizer interface {
Expand Down
14 changes: 14 additions & 0 deletions plot/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,20 @@ func CopyRole(data Data, role Roles) Values {
return v
}

// CopyRoleLabels returns Labels copy of given role from given data map,
// returning nil if role not present.
func CopyRoleLabels(data Data, role Roles) Labels {
d, ok := data[role]
if !ok {
return nil
}
l := make(Labels, d.Len())
for i := range l {
l[i] = d.String1D(i)
}
return l
}

// PlotX returns plot pixel X coordinate values for given data.
func PlotX(plt *Plot, data Valuer) []float32 {
px := make([]float32, data.Len())
Expand Down
28 changes: 27 additions & 1 deletion plot/plots/bar.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
package plots

import (
"fmt"
"math"

"cogentcore.org/core/base/errors"
Expand All @@ -24,7 +25,7 @@ import (
const BarType = "Bar"

func init() {
plot.RegisterPlotter(BarType, "A Bar presents ordinally-organized data with rectangular bars with lengths proportional to the data values, and an optional error bar at the top of the bar using the High data role.", []plot.Roles{plot.Y}, []plot.Roles{plot.High}, func(plt *plot.Plot, data plot.Data) plot.Plotter {
plot.RegisterPlotter(BarType, "A Bar presents ordinally-organized data with rectangular bars with lengths proportional to the data values, and an optional error bar at the top of the bar using the High data role.", []plot.Roles{plot.Y}, []plot.Roles{plot.High, plot.X}, func(plt *plot.Plot, data plot.Data) plot.Plotter {
return NewBar(plt, data)
})
}
Expand All @@ -44,6 +45,9 @@ type Bar struct {
// actual plotting X, Y values in data coordinates, taking into account stacking etc.
X, Yp plot.Values

// optional labels for X axis.
XLabels plot.Labels

// PX, PY are the actual pixel plotting coordinates for each XY value.
PX, PY []float32

Expand Down Expand Up @@ -82,6 +86,7 @@ func NewBar(plt *plot.Plot, data any) *Bar {
if bc.Y == nil {
return nil
}
bc.XLabels = plot.CopyRoleLabels(dt, plot.X)
bc.stylers = plot.GetStylersFromData(dt, plot.Y)
bc.Err = plot.CopyRole(dt, plot.High)
bc.Defaults()
Expand Down Expand Up @@ -224,6 +229,12 @@ func (bc *Bar) UpdateRange(plt *plot.Plot, x, y, yr, z, size *minmax.F64) {
y = yr
}

var ticks plot.ConstantTicks
if bc.XLabels != nil {
ticks = make(plot.ConstantTicks, len(bc.Y))
fmt.Println("ticks:", bc.XLabels)
}

for i, val := range bc.Y {
valBot := bc.StackedOn.BarHeight(i)
valTop := valBot + val
Expand All @@ -237,13 +248,28 @@ func (bc *Bar) UpdateRange(plt *plot.Plot, x, y, yr, z, size *minmax.F64) {
y.FitValInRange(valBot)
y.FitValInRange(valTop)
}
if bc.XLabels != nil {
cat := bw.Offset + float64(i)*bw.Stride
ticks[i].Value = cat
if bc.XLabels.Len() > i {
ticks[i].Label = bc.XLabels[i]
} else {
ticks[i].Label = fmt.Sprintf("%d", i)
}
}
}
if bc.Horizontal {
x.Min, x.Max = bc.Style.Range.Clamp(x.Min, x.Max)
y.FitInRange(minmax.F64{catMin, catMax})
if ticks != nil {
plt.Y.Ticker = ticks
}
} else {
y.Min, y.Max = bc.Style.Range.Clamp(y.Min, y.Max)
x.FitInRange(minmax.F64{catMin, catMax})
if ticks != nil {
plt.X.Ticker = ticks
}
}
}

Expand Down
5 changes: 4 additions & 1 deletion plot/plots/labels.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,10 @@ func (lb *Labels) Plot(plt *plot.Plot) {
nskip := lb.Style.LabelSkip
skip := nskip // start with label
for i, label := range lb.Labels {
if label == "" || skip != nskip {
if label == "" {
continue
}
if skip != nskip {
skip++
continue
}
Expand Down
129 changes: 8 additions & 121 deletions plot/plots/plot_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"math"
"math/rand"
"os"
"slices"
"strconv"
"testing"

Expand All @@ -21,8 +20,6 @@ import (
"cogentcore.org/lab/plot"
"cogentcore.org/lab/table"
"cogentcore.org/lab/tensor"
"github.com/stretchr/testify/assert"
"golang.org/x/exp/maps"
)

func ExampleXY() {
Expand Down Expand Up @@ -555,124 +552,14 @@ func TestTicks(t *testing.T) {
imagex.Assert(t, plt.RenderImage(), "style_noticks")
}

// todo: move into statplot and test everything

func TestTable(t *testing.T) {
rand.Seed(1)
n := 21
tx, ty := tensor.NewFloat64(n), tensor.NewFloat64(n)
tl, th := tensor.NewFloat64(n), tensor.NewFloat64(n)
ts := tensor.NewFloat64(n)
lbls := tensor.NewString(n)
for i := range n {
tx.SetFloat1D(float64(i*5), i)
ty.SetFloat1D(50.0+40*math.Sin((float64(i)/8)*math.Pi), i)
tl.SetFloat1D(5*rand.Float64(), i)
th.SetFloat1D(5*rand.Float64(), i)
ts.SetFloat1D(1+5*rand.Float64(), i)
lbls.SetString1D(strconv.Itoa(i), i)
}
ptyps := maps.Keys(plot.Plotters)
slices.Sort(ptyps)
for _, ttyp := range ptyps {
// attach stylers to the Y axis data: that is where plotter looks for it
genst := func(s *plot.Style) {
s.Plot.Title = "Test " + ttyp
s.Plot.XAxis.Label = "X Axis"
s.Plot.YAxisLabel = "Y Axis"
s.Plotter = plot.PlotterName(ttyp)
s.Plot.SetLinesOn(plot.On).SetPointsOn(plot.On)
s.Line.Color = colors.Uniform(colors.Red)
s.Point.Color = colors.Uniform(colors.Blue)
s.Range.SetMin(0).SetMax(100)
}
plot.SetStyler(ty, genst, func(s *plot.Style) {
s.On = true
s.Role = plot.Y
s.Group = "Y"
})
// others get basic styling
plot.SetStyler(tx, func(s *plot.Style) {
s.Role = plot.X
s.Group = "Y"
})
plot.SetStyler(tl, func(s *plot.Style) {
s.Role = plot.Low
s.Group = "Y"
})
plot.SetStyler(th, genst, func(s *plot.Style) {
s.On = true
s.Role = plot.High
s.Group = "Y"
})
plot.SetStyler(ts, func(s *plot.Style) {
s.Role = plot.Size
s.Group = "Y"
})
plot.SetStyler(lbls, genst, func(s *plot.Style) {
s.On = true
s.Role = plot.Label
s.Group = "Y"
})
dt := table.New("Test Table") // todo: use Name by default for plot.
dt.AddColumn("X", tx)
dt.AddColumn("Y", ty)
dt.AddColumn("Low", tl)
dt.AddColumn("High", th)
dt.AddColumn("Size", ts)
dt.AddColumn("Labels", lbls)

plt, err := plot.NewTablePlot(dt)
assert.NoError(t, err)
fnm := "table_" + ttyp + ".png"
imagex.Assert(t, plt.RenderImage(), fnm)
}
}

func TestTableSplit(t *testing.T) {
ngps := 3
nitms := 4
n := ngps * nitms
lbls := tensor.NewString(n)
tx, ty := tensor.NewFloat64(n), tensor.NewFloat64(n)
groups := []string{"Aaa", "Bbb", "Ccc"}
for i := range n {
tx.SetFloat1D(float64(i*5), i)
ty.SetFloat1D(50.0+40*math.Sin((float64(i)/8)*math.Pi), i)
lbls.SetString1D(groups[i/nitms], i)
}
// attach stylers to the Y axis data: that is where plotter looks for it
genst := func(s *plot.Style) {
s.Plot.Title = "Test Split"
s.Plot.XAxis.Label = "X Axis"
s.Plot.YAxisLabel = "Y Axis"
s.Plotter = plot.PlotterName("XY")
s.Plot.SetLinesOn(plot.On).SetPointsOn(plot.On)
s.Line.Color = colors.Uniform(colors.Red)
s.Point.Color = colors.Uniform(colors.Blue)
s.Range.SetMin(0).SetMax(100)
func TestBarXLabels(t *testing.T) {
yd := make(plot.Values, 3)
xl := plot.Labels{"xv1", "xv2", "xv3"}
for i := range yd {
yd[i] = float64(5) + float64(i)*2
}
plot.SetStyler(ty, genst, func(s *plot.Style) {
s.On = true
s.Role = plot.Y
s.Group = "Y"
})
plot.SetStyler(tx, func(s *plot.Style) {
s.Role = plot.X
s.Group = "Y"
})
plot.SetStyler(lbls, genst, func(s *plot.Style) {
s.On = true
s.Role = plot.Split
s.Group = "Y"
})
dt := table.New("Test Table") // todo: use Name by default for plot.
dt.AddColumn("X", tx)
dt.AddColumn("Y", ty)
dt.AddColumn("Labels", lbls)

plt, err := plot.NewTablePlot(dt)
assert.NoError(t, err)
fnm := "table_split.png"
plt := plot.New()
NewBar(plt, plot.Data{plot.X: xl, plot.Y: yd})
fnm := "bar-x-labels.png"
imagex.Assert(t, plt.RenderImage(), fnm)
}
Loading