From 8075765ac77570c04b523af165ec83454e34adda Mon Sep 17 00:00:00 2001 From: "Randall C. O'Reilly" Date: Fri, 8 May 2026 11:03:09 +0200 Subject: [PATCH 1/8] plotminmax: a fixed min or max value also limits values plotted to that range -- need to signal the omission of out-of-range data somehow. and add style to support current behavior (not the default) --- plot/README.md | 7 ------- 1 file changed, 7 deletions(-) diff --git a/plot/README.md b/plot/README.md index b1e7d9fc..8b607573 100644 --- a/plot/README.md +++ b/plot/README.md @@ -45,10 +45,3 @@ Here is the copyright notice for that package: // license that can be found in the LICENSE file. ``` -# TODO - -* Min / Max not just for extending but also _limiting_ the range -- currently doesn't do - -* tensor index -* Grid? in styling. - From c970c89d8c5343c1e2513ed1e43ac4648112f98c Mon Sep 17 00:00:00 2001 From: "Randall C. O'Reilly" Date: Fri, 8 May 2026 20:58:53 +0200 Subject: [PATCH 2/8] plotminmax: OutOfRange enum added, implemented for XY, including adding to docs. Looks very good to me.. --- docs/content/plot.md | 15 +++ plot/axis.go | 8 +- plot/data.go | 36 ++++++ plot/enumgen.go | 43 +++++++ plot/plot.go | 22 +++- plot/plots/bar.go | 29 +++-- plot/plots/errbars.go | 28 +++-- plot/plots/labels.go | 24 ++-- plot/plots/plot_test.go | 21 ++++ plot/plots/xy.go | 112 ++++++++++++------ plot/plotter.go | 3 +- plot/style.go | 37 ++++++ plot/text.go | 2 - plot/typegen.go | 10 +- .../labsymbols/cogentcore_org-lab-plot.go | 20 ++-- 15 files changed, 332 insertions(+), 78 deletions(-) diff --git a/docs/content/plot.md b/docs/content/plot.md index 5caf5ba2..063c6994 100644 --- a/docs/content/plot.md +++ b/docs/content/plot.md @@ -82,6 +82,21 @@ plt := lab.NewPlot(b) plots.NewLine(plt, data) ``` +## Out-of-Range data + +You can set fixed Min / Max ranges to plot, for either axis. By default, the out-of-range data will show up as a break in the plot line, with red X's marking the out-of-range points. This behavior can be adjusted by changing the `OutOfRange` property in the [[doc:plot.PlotStyle]]. + +```Goal +data := #rand(10)# +plot.SetStyler(data, func(s *plot.Style) { + s.Range.SetMin(0.2) // sets a FixMin flag to indicate a fixed min has been set. + s.Range.SetMax(0.8) + s.Plot.OutOfRange = plot.BreakMark // default +}) +plt := lab.NewPlot(b) +plots.NewLine(plt, data) +``` + ## Plot Types The following are the builtin standard plot types, in the `plots` package: diff --git a/plot/axis.go b/plot/axis.go index 11c0ab33..1b3b7853 100644 --- a/plot/axis.go +++ b/plot/axis.go @@ -104,9 +104,15 @@ func (ax *AxisStyle) Defaults() { // This is the "internal" data structure and should not be used for styling. type Axis struct { - // Range has the Min, Max range of values for the axis (in raw data units.) + // Range has the full Min, Max range of values for the axis + // (in raw data units). This includes extra space needed for plotting. Range minmax.F64 + // DataRange has the Min, Max range for the actual data values + // for the axis (in raw data units), *exclusive* of extra plotting space. + // This is used for OutOfRange clipping. + DataRange minmax.F64 + // specifies which axis this is: X, Y or Z. Axis math32.Dims diff --git a/plot/data.go b/plot/data.go index 580625ea..f652c139 100644 --- a/plot/data.go +++ b/plot/data.go @@ -150,6 +150,18 @@ func Range(data Valuer, rng *minmax.F64) { } } +// RangeLogic processes the OutOfRange setting to set the given axis range +// based on style range settings (i.e., dealing with Stretch vs. other cases). +// Returns true if the range of the data fits entirely within the styleRng +// min / max values. +func RangeLogic(oor OutOfRange, data Valuer, axisRng *minmax.F64, styleRng *minmax.Range64) bool { + if oor == Stretch { + RangeClamp(data, axisRng, styleRng) + return true // by definition + } + return RangeSet(data, axisRng, styleRng) +} + // RangeClamp updates the given axis Min, Max range values based // on the range of values in the given [Data], and the given style range. func RangeClamp(data Valuer, axisRng *minmax.F64, styleRng *minmax.Range64) { @@ -157,6 +169,30 @@ func RangeClamp(data Valuer, axisRng *minmax.F64, styleRng *minmax.Range64) { axisRng.Min, axisRng.Max = styleRng.Clamp(axisRng.Min, axisRng.Max) } +// RangeSetFromStyle sets the axis range based on the given style range, +// where styleRng flags for Min or Max are set, and otherwise gets the range +// from the actual data. This is for the case where the flags indicate a hard, +// non-stretchable extreme, whereas RangeClamp is the stretch case. +// Returns true if the range of the data fits entirely within the styleRng +// min / max values. +func RangeSet(data Valuer, axisRng *minmax.F64, styleRng *minmax.Range64) bool { + fits := true + Range(data, axisRng) + if styleRng.FixMin { + if axisRng.Min < styleRng.Min { + fits = false + } + axisRng.Min = styleRng.Min + } + if styleRng.FixMax { + if axisRng.Max > styleRng.Max { + fits = false + } + axisRng.Max = styleRng.Max + } + return fits +} + // CheckLengths checks that all the data elements have the same length. // Logs and returns an error if not. func (dt Data) CheckLengths() error { diff --git a/plot/enumgen.go b/plot/enumgen.go index d763aa9c..7bd1ebdf 100644 --- a/plot/enumgen.go +++ b/plot/enumgen.go @@ -210,3 +210,46 @@ func (i DefaultOffOn) MarshalText() ([]byte, error) { return []byte(i.String()), func (i *DefaultOffOn) UnmarshalText(text []byte) error { return enums.UnmarshalText(i, text, "DefaultOffOn") } + +var _OutOfRangeValues = []OutOfRange{0, 1, 2, 3} + +// OutOfRangeN is the highest valid value for type OutOfRange, plus one. +const OutOfRangeN OutOfRange = 4 + +var _OutOfRangeValueMap = map[string]OutOfRange{`BreakMark`: 0, `Mark`: 1, `Break`: 2, `Stretch`: 3} + +var _OutOfRangeDescMap = map[OutOfRange]string{0: `BreakMark breaks any continuous line elements and renders a marker for out-of-range values`, 1: `Mark renders a marker for out-of-range values, but does not break continuous line elements.`, 2: `Break breaks any continuous line elements, but does not render a marker, for out-of-range values.`, 3: `Stretch stretches the range to include all values, avoiding the problem of out-of-range values entirely.`} + +var _OutOfRangeMap = map[OutOfRange]string{0: `BreakMark`, 1: `Mark`, 2: `Break`, 3: `Stretch`} + +// String returns the string representation of this OutOfRange value. +func (i OutOfRange) String() string { return enums.String(i, _OutOfRangeMap) } + +// SetString sets the OutOfRange value from its string representation, +// and returns an error if the string is invalid. +func (i *OutOfRange) SetString(s string) error { + return enums.SetString(i, s, _OutOfRangeValueMap, "OutOfRange") +} + +// Int64 returns the OutOfRange value as an int64. +func (i OutOfRange) Int64() int64 { return int64(i) } + +// SetInt64 sets the OutOfRange value from an int64. +func (i *OutOfRange) SetInt64(in int64) { *i = OutOfRange(in) } + +// Desc returns the description of the OutOfRange value. +func (i OutOfRange) Desc() string { return enums.Desc(i, _OutOfRangeDescMap) } + +// OutOfRangeValues returns all possible values for the type OutOfRange. +func OutOfRangeValues() []OutOfRange { return _OutOfRangeValues } + +// Values returns all possible values for the type OutOfRange. +func (i OutOfRange) Values() []enums.Enum { return enums.Values(_OutOfRangeValues) } + +// MarshalText implements the [encoding.TextMarshaler] interface. +func (i OutOfRange) MarshalText() ([]byte, error) { return []byte(i.String()), nil } + +// UnmarshalText implements the [encoding.TextUnmarshaler] interface. +func (i *OutOfRange) UnmarshalText(text []byte) error { + return enums.UnmarshalText(i, text, "OutOfRange") +} diff --git a/plot/plot.go b/plot/plot.go index 99913f6a..7ae7d742 100644 --- a/plot/plot.go +++ b/plot/plot.go @@ -107,6 +107,11 @@ type PlotStyle struct { //types:add -setters // overall Plot level, for elements that plot points (e.g., plots.XY). PointsOn DefaultOffOn + // OutOfRange specifies how to handle out-of-range values, when a + // range has been set with fixed Min or Max values that exclude some + // data points. + OutOfRange OutOfRange + // PointSize sets the default point size at the overall Plot level. PointSize units.Value @@ -130,6 +135,7 @@ func (ps *PlotStyle) Defaults() { ps.TitleStyle.Size.Dp(24) ps.Background = colors.Scheme.Surface ps.Scale = 1 + ps.OutOfRange = BreakMark ps.Legend.Defaults() ps.Axis.Defaults() ps.LineWidth.Pt(1) @@ -353,6 +359,18 @@ func (pt *Plot) PushBounds(tb image.Rectangle) { pt.Painter.PushContext(nil, render.NewBoundsRect(tb, sides.Floats{})) } +// DataBox returns a conservative (errs on side of smaller) estimate +// of the size of the data plotting region of the plot, based on the +// overall PaintBox size. This is used for extending the range for +// extra plot elements beyond those accounted for by the data. +func (pt *Plot) DataBox() image.Point { + // todo: could improve estimate by looking at title, axes, etc. + bsz := pt.PaintBox.Size() + bsz.Y = int(0.75 * float64(bsz.Y)) + bsz.X = int(0.75 * float64(bsz.X)) + return bsz +} + // NominalX configures the plot to have a nominal X // axis—an X axis with names instead of numbers. The // X location corresponding to each name are the integers, @@ -422,7 +440,6 @@ func (pt *Plot) UpdateRange() { pt.YR.Range.SetInfinity() pt.Z.Range.SetInfinity() pt.SizeAxis.Range.SetInfinity() - // note: putting this after allows it to override if pt.Style.XAxis.Range.FixMin { pt.X.Range.Min = pt.Style.XAxis.Range.Min } @@ -430,7 +447,8 @@ func (pt *Plot) UpdateRange() { pt.X.Range.Max = pt.Style.XAxis.Range.Max } for _, pl := range pt.Plotters { - pl.UpdateRange(pt, &pt.X.Range, &pt.Y.Range, &pt.YR.Range, &pt.Z.Range, &pt.SizeAxis.Range) + pl.UpdateRange(pt) + // pl.UpdateRange(pt, &pt.X.Range, &pt.Y.Range, &pt.YR.Range, &pt.Z.Range, &pt.SizeAxis.Range) } pt.X.Range.Sanitize() pt.Y.Range.Sanitize() diff --git a/plot/plots/bar.go b/plot/plots/bar.go index b5665fde..c287606a 100644 --- a/plot/plots/bar.go +++ b/plot/plots/bar.go @@ -228,12 +228,21 @@ func (bc *Bar) Plot(plt *plot.Plot) { } // UpdateRange updates the given ranges. -func (bc *Bar) UpdateRange(plt *plot.Plot, x, y, yr, z, size *minmax.F64) { +func (bc *Bar) UpdateRange(plt *plot.Plot) { bw := bc.Style.Width catMin := bw.Offset - bw.Pad catMax := bw.Offset + float64(len(bc.Y)-1)*bw.Stride + bw.Pad + + yax := &plt.Y if bc.Style.RightY { - y = yr + yax = &plt.YR + } + if bc.Horizontal { + plot.RangeLogic(plt.Style.OutOfRange, bc.Y, &plt.X.Range, &bc.Style.Range) + plot.RangeLogic(plt.Style.OutOfRange, bc.X, &yax.Range, &plt.Style.XAxis.Range) + } else { + plot.RangeLogic(plt.Style.OutOfRange, bc.X, &plt.X.Range, &plt.Style.XAxis.Range) + plot.RangeLogic(plt.Style.OutOfRange, bc.Y, &yax.Range, &bc.Style.Range) } var ticks plot.ConstantTicks @@ -248,11 +257,11 @@ func (bc *Bar) UpdateRange(plt *plot.Plot, x, y, yr, z, size *minmax.F64) { valTop += math.Abs(bc.Err[i]) } if bc.Horizontal { - x.FitValInRange(valBot) - x.FitValInRange(valTop) + plt.X.Range.FitValInRange(valBot) + plt.X.Range.FitValInRange(valTop) } else { - y.FitValInRange(valBot) - y.FitValInRange(valTop) + yax.Range.FitValInRange(valBot) + yax.Range.FitValInRange(valTop) } if bc.XLabels != nil { cat := bw.Offset + float64(i)*bw.Stride @@ -265,18 +274,18 @@ func (bc *Bar) UpdateRange(plt *plot.Plot, x, y, yr, z, size *minmax.F64) { } } if bc.Horizontal { - x.Min, x.Max = bc.Style.Range.Clamp(x.Min, x.Max) - y.FitInRange(minmax.F64{catMin, catMax}) + yax.Range.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}) + plt.X.Range.FitInRange(minmax.F64{catMin, catMax}) if ticks != nil { plt.X.Ticker = ticks } } + plt.X.DataRange = plt.X.Range + yax.DataRange = yax.Range } // Thumbnail fulfills the plot.Thumbnailer interface. diff --git a/plot/plots/errbars.go b/plot/plots/errbars.go index aff51913..aebb7924 100644 --- a/plot/plots/errbars.go +++ b/plot/plots/errbars.go @@ -142,16 +142,20 @@ func (eb *YErrorBars) Plot(plt *plot.Plot) { } // UpdateRange updates the given ranges. -func (eb *YErrorBars) UpdateRange(plt *plot.Plot, x, y, yr, z, size *minmax.F64) { +func (eb *YErrorBars) UpdateRange(plt *plot.Plot) { + yax := &plt.Y if eb.Style.RightY { - y = yr + yax = &plt.YR } - plot.Range(eb.X, x) - plot.RangeClamp(eb.Y, y, &eb.Style.Range) + plot.RangeLogic(plt.Style.OutOfRange, eb.X, &plt.X.Range, &plt.Style.XAxis.Range) + plt.X.DataRange = plt.X.Range + plot.RangeLogic(plt.Style.OutOfRange, eb.Y, &yax.Range, &eb.Style.Range) + yax.DataRange = yax.Range + for i, yv := range eb.Y { ylow := yv - math.Abs(eb.Low[i]) yhigh := yv + math.Abs(eb.High[i]) - y.FitInRange(minmax.F64{ylow, yhigh}) + yax.Range.FitInRange(minmax.F64{ylow, yhigh}) } return } @@ -265,16 +269,20 @@ func (eb *XErrorBars) Plot(plt *plot.Plot) { } // UpdateRange updates the given ranges. -func (eb *XErrorBars) UpdateRange(plt *plot.Plot, x, y, yr, z, size *minmax.F64) { +func (eb *XErrorBars) UpdateRange(plt *plot.Plot) { + yax := &plt.Y if eb.Style.RightY { - y = yr + yax = &plt.YR } - plot.RangeClamp(eb.X, x, &eb.Style.Range) - plot.RangeClamp(eb.Y, y, &eb.yrange) + plot.RangeLogic(plt.Style.OutOfRange, eb.X, &plt.X.Range, &plt.Style.XAxis.Range) + plt.X.DataRange = plt.X.Range + plot.RangeLogic(plt.Style.OutOfRange, eb.Y, &yax.Range, &eb.Style.Range) + yax.DataRange = yax.Range + for i, xv := range eb.X { xlow := xv - math.Abs(eb.Low[i]) xhigh := xv + math.Abs(eb.High[i]) - x.FitInRange(minmax.F64{xlow, xhigh}) + plt.X.Range.FitInRange(minmax.F64{xlow, xhigh}) } return } diff --git a/plot/plots/labels.go b/plot/plots/labels.go index ad39a9ba..72436864 100644 --- a/plot/plots/labels.go +++ b/plot/plots/labels.go @@ -134,16 +134,20 @@ func (lb *Labels) Plot(plt *plot.Plot) { } // UpdateRange updates the given ranges. -func (lb *Labels) UpdateRange(plt *plot.Plot, x, y, yr, z, size *minmax.F64) { +func (lb *Labels) UpdateRange(plt *plot.Plot) { + yax := &plt.Y if lb.Style.RightY { - y = yr + yax = &plt.YR } - // todo: include point sizes! - plot.Range(lb.X, x) - plot.RangeClamp(lb.Y, y, &lb.Style.Range) - pxToData := math32.FromPoint(plt.PaintBox.Size()) - pxToData.X = float32(x.Range()) / pxToData.X - pxToData.Y = float32(y.Range()) / pxToData.Y + plot.RangeLogic(plt.Style.OutOfRange, lb.X, &plt.X.Range, &plt.Style.XAxis.Range) + plt.X.DataRange = plt.X.Range + plot.RangeLogic(plt.Style.OutOfRange, lb.Y, &yax.Range, &lb.Style.Range) + yax.DataRange = yax.Range + + var pxToData math32.Vector2 + bsz := plt.DataBox() + pxToData.X = float32(plt.X.Range.Range()) / float32(bsz.X) + pxToData.Y = float32(yax.Range.Range()) / float32(bsz.Y) st := &lb.Style.Text var ltxt plot.Text ltxt.Style = *st @@ -159,7 +163,7 @@ func (lb *Labels) UpdateRange(plt *plot.Plot, x, y, yr, z, size *minmax.F64) { yv := lb.Y[i] maxx := xv + float64(pxToData.X*st.Offset.X.Dots+twd) maxy := yv + float64(pxToData.Y*st.Offset.Y.Dots+tht) // y is up here - x.FitInRange(minmax.F64{xv, maxx}) - y.FitInRange(minmax.F64{yv, maxy}) + plt.X.Range.FitInRange(minmax.F64{xv, maxx}) + yax.Range.FitInRange(minmax.F64{yv, maxy}) } } diff --git a/plot/plots/plot_test.go b/plot/plots/plot_test.go index 045902d3..0524b4a2 100644 --- a/plot/plots/plot_test.go +++ b/plot/plots/plot_test.go @@ -237,6 +237,27 @@ func TestLine(t *testing.T) { } } +func TestOutOfRange(t *testing.T) { + data := sinDataXY() + for oor := range plot.OutOfRangeN { + plt := plot.New() + plt.Title.Text = "Test Line" + plt.X.Label.Text = "X Axis" + plt.Y.Label.Text = "Y Axis" + plt.Style.OutOfRange = oor + + l1 := NewLine(plt, data).Styler(func(s *plot.Style) { + s.Range.SetMin(20) + s.Range.SetMax(80) + }) + if l1 == nil { + t.Fatal("bad data") + } + + imagex.Assert(t, plt.RenderImage(), "out-of-range-"+oor.String()) + } +} + func TestLineYRight(t *testing.T) { sin := sinDataXY() cos := cosDataXY() diff --git a/plot/plots/xy.go b/plot/plots/xy.go index 18f1c738..ea8e3964 100644 --- a/plot/plots/xy.go +++ b/plot/plots/xy.go @@ -16,7 +16,6 @@ import ( "math" "cogentcore.org/core/math32" - "cogentcore.org/core/math32/minmax" "cogentcore.org/lab/plot" "cogentcore.org/lab/tensor" ) @@ -157,41 +156,47 @@ func (ln *XY) Data() (data plot.Data, pixX, pixY []float32) { // Plot does the drawing, implementing the plot.Plotter interface. func (ln *XY) Plot(plt *plot.Plot) { ln.PX = plot.PlotX(plt, ln.X) - var minY float32 + minX, maxX := plt.PX(plt.X.DataRange.Min), plt.PX(plt.X.DataRange.Max) + var minY, maxY float32 if ln.Style.RightY { ln.PY = plot.PlotYR(plt, ln.Y) - minY = plt.PYR(plt.YR.Range.Min) + minY = plt.PYR(plt.YR.DataRange.Max) // flipped due to Y flip + maxY = plt.PYR(plt.YR.DataRange.Min) } else { ln.PY = plot.PlotY(plt, ln.Y) - minY = plt.PY(plt.Y.Range.Min) + minY = plt.PY(plt.Y.DataRange.Max) + maxY = plt.PY(plt.Y.DataRange.Min) } np := min(len(ln.PX), len(ln.PY)) if np == 0 { return } pc := plt.Painter + oor := plt.Style.OutOfRange + if ln.Style.Line.HasFill() { + botY := maxY // note: min and max are now in pixel coords, not data coords -- y flip! pc.Fill.Color = ln.Style.Line.Fill pc.Stroke.Color = nil prevX := ln.PX[0] - prevY := minY + prevY := botY hasPrev := false for i, ptx := range ln.PX { pty := ln.PY[i] - if math32.IsNaN(pty) { // todo: likely needs more to deal with diff cases + if math32.IsNaN(pty) { continue } if !hasPrev && !math32.IsNaN(ptx) && !math32.IsNaN(pty) { - pc.MoveTo(ptx, minY) + pc.MoveTo(ptx, botY) prevX = ptx hasPrev = true } switch ln.Style.Line.Step { case plot.NoStep: if ptx < prevX { - pc.LineTo(prevX, minY) + pc.LineTo(prevX, botY) pc.Close() - pc.MoveTo(ptx, minY) + pc.MoveTo(ptx, botY) } pc.LineTo(ptx, pty) case plot.PreStep: @@ -199,18 +204,18 @@ func (ln *XY) Plot(plt *plot.Plot) { continue } if ptx < prevX { - pc.LineTo(prevX, minY) + pc.LineTo(prevX, botY) pc.Close() - pc.MoveTo(ptx, minY) + pc.MoveTo(ptx, botY) } else { pc.LineTo(prevX, pty) } pc.LineTo(ptx, pty) case plot.MidStep: if ptx < prevX { - pc.LineTo(prevX, minY) + pc.LineTo(prevX, botY) pc.Close() - pc.MoveTo(ptx, minY) + pc.MoveTo(ptx, botY) } else { pc.LineTo(0.5*(prevX+ptx), prevY) pc.LineTo(0.5*(prevX+ptx), pty) @@ -218,9 +223,9 @@ func (ln *XY) Plot(plt *plot.Plot) { pc.LineTo(ptx, pty) case plot.PostStep: if ptx < prevX { - pc.LineTo(prevX, minY) + pc.LineTo(prevX, botY) pc.Close() - pc.MoveTo(ptx, minY) + pc.MoveTo(ptx, botY) } else { pc.LineTo(ptx, prevY) } @@ -228,12 +233,13 @@ func (ln *XY) Plot(plt *plot.Plot) { } prevX, prevY = ptx, pty } - pc.LineTo(prevX, minY) + pc.LineTo(prevX, botY) pc.Close() pc.Draw() } pc.Fill.Color = nil + hasOORMarks := false if ln.Style.Line.SetStroke(plt) { if plt.HighlightPlotter == ln { pc.Stroke.Width.Dots *= 2 @@ -249,6 +255,24 @@ func (ln *XY) Plot(plt *plot.Plot) { if math32.IsNaN(ptx) || math32.IsNaN(pty) { continue } + if ptx > maxX { + continue // could wrap around + } + if ptx < minX { + hasPrev = false + continue + } + if pty < minY || pty > maxY { + pty = min(pty, maxY) + pty = max(pty, minY) + if oor.HasMark() { + hasOORMarks = true + } + if oor.HasBreak() { + hasPrev = false + continue + } + } if ln.Style.Line.Step != plot.NoStep { if hasPrev && ptx >= prevX { switch ln.Style.Line.Step { @@ -275,12 +299,31 @@ func (ln *XY) Plot(plt *plot.Plot) { } pc.Draw() } + + if hasOORMarks { + ln.Style.OutOfRangeMark.SetStroke(plt) + for i, ptx := range ln.PX { + pty := ln.PY[i] + if math32.IsNaN(ptx) || math32.IsNaN(pty) { + continue + } + if ptx < minX || ptx > maxX { + continue + } + if pty < minY || pty > maxY { + pty = min(pty, maxY) + pty = max(pty, minY) + ln.Style.OutOfRangeMark.DrawShape(pc, math32.Vec2(ptx, pty)) + } + } + } + if ln.Style.Point.SetStroke(plt) { origWidth := ln.Style.Point.Width origSize := ln.Style.Point.Size for i, ptx := range ln.PX { pty := ln.PY[i] - if math32.IsNaN(pty) { + if math32.IsNaN(ptx) || math32.IsNaN(pty) { continue } pc.Stroke.Width = origWidth @@ -319,26 +362,29 @@ func (ln *XY) Plot(plt *plot.Plot) { } // UpdateRange updates the given ranges. -func (ln *XY) UpdateRange(plt *plot.Plot, x, y, yr, z, size *minmax.F64) { +func (ln *XY) UpdateRange(plt *plot.Plot) { + yax := &plt.Y if ln.Style.RightY { - y = yr + yax = &plt.YR } - plot.Range(ln.X, x) - if !ln.Style.Point.IsOn(plt) { - plot.RangeClamp(ln.Y, y, &ln.Style.Range) + plot.RangeLogic(plt.Style.OutOfRange, ln.X, &plt.X.Range, &plt.Style.XAxis.Range) + plt.X.DataRange = plt.X.Range + yFits := plot.RangeLogic(plt.Style.OutOfRange, ln.Y, &yax.Range, &ln.Style.Range) + yax.DataRange = yax.Range + + ln.Style.OutOfRangeMark.IsOn(plt) // does dots + if !ln.Style.Point.IsOn(plt) && (!plt.Style.OutOfRange.HasMark() || yFits) { return } - plot.Range(ln.Y, y) - psz := ln.Style.Point.Size.Dots - ptb := plt.PaintBox - dy := (float64(psz) / float64(ptb.Size().Y)) * y.Range() - y.Min -= dy - y.Max += dy - y.Min, y.Max = ln.Style.Range.Clamp(y.Min, y.Max) - dx := (float64(psz) / float64(ptb.Size().X)) * x.Range() - x.Min -= dx - x.Max += dx - plot.Range(ln.Size, size) + psz := max(ln.Style.Point.Size.Dots, ln.Style.OutOfRangeMark.Size.Dots) + bsz := plt.DataBox() + dy := (float64(psz) / float64(bsz.Y)) * yax.Range.Range() + yax.Range.Min -= dy + yax.Range.Max += dy + dx := (float64(psz) / float64(bsz.X)) * plt.X.Range.Range() + plt.X.Range.Min -= dx + plt.X.Range.Max += dx + plot.Range(ln.Size, &plt.SizeAxis.Range) } // Thumbnail returns the thumbnail, implementing the plot.Thumbnailer interface. diff --git a/plot/plotter.go b/plot/plotter.go index c8bd3d07..739eb9a3 100644 --- a/plot/plotter.go +++ b/plot/plotter.go @@ -8,7 +8,6 @@ import ( "fmt" "cogentcore.org/core/base/errors" - "cogentcore.org/core/math32/minmax" ) // Plotter is an interface that wraps the Plot method. @@ -19,7 +18,7 @@ type Plotter interface { Plot(pt *Plot) // UpdateRange updates the given ranges. - UpdateRange(plt *Plot, x, y, yr, z, size *minmax.F64) + UpdateRange(plt *Plot) // Data returns the data by roles for this plot, for both the original // data and the pixel-transformed X,Y coordinates for that data. diff --git a/plot/style.go b/plot/style.go index 587df90b..6ecb028f 100644 --- a/plot/style.go +++ b/plot/style.go @@ -6,6 +6,7 @@ package plot import ( "cogentcore.org/core/base/metadata" + "cogentcore.org/core/colors" "cogentcore.org/core/math32/minmax" "cogentcore.org/core/styles/units" "cogentcore.org/lab/table" @@ -38,6 +39,7 @@ type Style struct { //types:add -setters Group string // Range is the effective range of data to plot, where either end can be fixed. + // See [OutofRange] for plotting behavior for data outside of fixed range. Range minmax.Range64 `display:"inline"` // Label provides an alternative label to use for axis, if set. @@ -69,6 +71,9 @@ type Style struct { //types:add -setters // Width has various plot width properties. Width WidthStyle `display:"inline"` + + // OutOfRangeMark has style properties for drawing points when out of range. + OutOfRangeMark PointStyle `display:"add-fields"` } // NewStyle returns a new Style object with defaults applied. @@ -84,6 +89,9 @@ func (st *Style) Defaults() { st.Point.Defaults() st.Text.Defaults() st.Width.Defaults() + st.OutOfRangeMark.Defaults() + st.OutOfRangeMark.Color = colors.Scheme.Error.Base + st.OutOfRangeMark.Shape = Cross } // WidthStyle contains various plot width properties relevant across @@ -237,3 +245,32 @@ const ( // On means to override the default and turn On. On ) + +// OutOfRange specifies how to plot out-of-range values. +type OutOfRange int32 //enums:enum + +const ( + // BreakMark breaks any continuous line elements and renders a marker + // for out-of-range values + BreakMark OutOfRange = iota + + // Mark renders a marker for out-of-range values, but does not break + // continuous line elements. + Mark + + // Break breaks any continuous line elements, but does not render + // a marker, for out-of-range values. + Break + + // Stretch stretches the range to include all values, + // avoiding the problem of out-of-range values entirely. + Stretch +) + +func (or OutOfRange) HasMark() bool { + return or == BreakMark || or == Mark +} + +func (or OutOfRange) HasBreak() bool { + return or == BreakMark || or == Break +} diff --git a/plot/text.go b/plot/text.go index c5188b43..fe0c7c47 100644 --- a/plot/text.go +++ b/plot/text.go @@ -95,8 +95,6 @@ func (tx *Text) Config(pt *Plot) { tx.Style.Align = styles.End } ts.ToDots(uc) - // fmt.Printf("%p\n", pt.Painter) - // fmt.Println("tdots:", ts.FontSize.Dots) tx.Style.Padding.ToDots(uc) txln := float32(len(tx.Text)) fht := tx.textStyle.FontHeight(fs) diff --git a/plot/typegen.go b/plot/typegen.go index f4d9bc39..9ddda05b 100644 --- a/plot/typegen.go +++ b/plot/typegen.go @@ -187,7 +187,7 @@ func (t *XAxisStyle) SetRange(v minmax.Range64) *XAxisStyle { t.Range = v; retur // Linear, Log, Inverted func (t *XAxisStyle) SetScale(v AxisScales) *XAxisStyle { t.Scale = v; return t } -var _ = types.AddType(&types.Type{Name: "cogentcore.org/lab/plot.PlotStyle", IDName: "plot-style", Doc: "PlotStyle has overall plot level styling properties.\nSome properties provide defaults for individual elements, which can\nthen be overwritten by element-level properties.", Directives: []types.Directive{{Tool: "types", Directive: "add", Args: []string{"-setters"}}}, Fields: []types.Field{{Name: "Title", Doc: "Title is the overall title of the plot."}, {Name: "TitleStyle", Doc: "TitleStyle is the text styling parameters for the title."}, {Name: "Background", Doc: "Background is the background of the plot.\nThe default is [colors.Scheme.Surface]."}, {Name: "Scale", Doc: "Scale multiplies the plot DPI value, to change the overall scale\nof the rendered plot. Larger numbers produce larger scaling.\nTypically use larger numbers when generating plots for inclusion in\ndocuments or other cases where the overall plot size will be small."}, {Name: "Legend", Doc: "Legend has the styling properties for the Legend."}, {Name: "Axis", Doc: "Axis has the styling properties for the Axis associated with this Data."}, {Name: "XAxis", Doc: "XAxis has plot-level properties specific to the XAxis."}, {Name: "YAxisLabel", Doc: "YAxisLabel is the optional label to use for the YAxis instead of the default."}, {Name: "SizeAxis", Doc: "SizeAxis has plot-level properties specific to the Size virtual axis."}, {Name: "LinesOn", Doc: "LinesOn determines whether lines are plotted by default at the overall,\nPlot level, for elements that plot lines (e.g., plots.XY)."}, {Name: "LineWidth", Doc: "LineWidth sets the default line width for data plotting lines at the\noverall Plot level."}, {Name: "PointsOn", Doc: "PointsOn determines whether points are plotted by default at the\noverall Plot level, for elements that plot points (e.g., plots.XY)."}, {Name: "PointSize", Doc: "PointSize sets the default point size at the overall Plot level."}, {Name: "LabelSize", Doc: "LabelSize sets the default label text size at the overall Plot level."}, {Name: "BarWidth", Doc: "BarWidth for Bar plot sets the default width of the bars,\nwhich should be less than the Stride (1 typically) to prevent\nbar overlap. Defaults to .8."}, {Name: "ShowErrors", Doc: "ShowErrors can be set to have Plot configuration errors reported.\nThis is particularly important for table-driven plots (e.g., [plotcore.Editor]),\nbut it is not on by default because often there are transitional states\nwith known errors that can lead to false alarms."}}}) +var _ = types.AddType(&types.Type{Name: "cogentcore.org/lab/plot.PlotStyle", IDName: "plot-style", Doc: "PlotStyle has overall plot level styling properties.\nSome properties provide defaults for individual elements, which can\nthen be overwritten by element-level properties.", Directives: []types.Directive{{Tool: "types", Directive: "add", Args: []string{"-setters"}}}, Fields: []types.Field{{Name: "Title", Doc: "Title is the overall title of the plot."}, {Name: "TitleStyle", Doc: "TitleStyle is the text styling parameters for the title."}, {Name: "Background", Doc: "Background is the background of the plot.\nThe default is [colors.Scheme.Surface]."}, {Name: "Scale", Doc: "Scale multiplies the plot DPI value, to change the overall scale\nof the rendered plot. Larger numbers produce larger scaling.\nTypically use larger numbers when generating plots for inclusion in\ndocuments or other cases where the overall plot size will be small."}, {Name: "Legend", Doc: "Legend has the styling properties for the Legend."}, {Name: "Axis", Doc: "Axis has the styling properties for the Axis associated with this Data."}, {Name: "XAxis", Doc: "XAxis has plot-level properties specific to the XAxis."}, {Name: "YAxisLabel", Doc: "YAxisLabel is the optional label to use for the YAxis instead of the default."}, {Name: "SizeAxis", Doc: "SizeAxis has plot-level properties specific to the Size virtual axis."}, {Name: "LinesOn", Doc: "LinesOn determines whether lines are plotted by default at the overall,\nPlot level, for elements that plot lines (e.g., plots.XY)."}, {Name: "LineWidth", Doc: "LineWidth sets the default line width for data plotting lines at the\noverall Plot level."}, {Name: "PointsOn", Doc: "PointsOn determines whether points are plotted by default at the\noverall Plot level, for elements that plot points (e.g., plots.XY)."}, {Name: "OutOfRange", Doc: "OutOfRange specifies how to handle out-of-range values, when a\nrange has been set with fixed Min or Max values that exclude some\ndata points."}, {Name: "PointSize", Doc: "PointSize sets the default point size at the overall Plot level."}, {Name: "LabelSize", Doc: "LabelSize sets the default label text size at the overall Plot level."}, {Name: "BarWidth", Doc: "BarWidth for Bar plot sets the default width of the bars,\nwhich should be less than the Stride (1 typically) to prevent\nbar overlap. Defaults to .8."}, {Name: "ShowErrors", Doc: "ShowErrors can be set to have Plot configuration errors reported.\nThis is particularly important for table-driven plots (e.g., [plotcore.Editor]),\nbut it is not on by default because often there are transitional states\nwith known errors that can lead to false alarms."}}}) // SetTitle sets the [PlotStyle.Title]: // Title is the overall title of the plot. @@ -244,6 +244,12 @@ func (t *PlotStyle) SetLineWidth(v units.Value) *PlotStyle { t.LineWidth = v; re // overall Plot level, for elements that plot points (e.g., plots.XY). func (t *PlotStyle) SetPointsOn(v DefaultOffOn) *PlotStyle { t.PointsOn = v; return t } +// SetOutOfRange sets the [PlotStyle.OutOfRange]: +// OutOfRange specifies how to handle out-of-range values, when a +// range has been set with fixed Min or Max values that exclude some +// data points. +func (t *PlotStyle) SetOutOfRange(v OutOfRange) *PlotStyle { t.OutOfRange = v; return t } + // SetPointSize sets the [PlotStyle.PointSize]: // PointSize sets the default point size at the overall Plot level. func (t *PlotStyle) SetPointSize(v units.Value) *PlotStyle { t.PointSize = v; return t } @@ -422,6 +428,8 @@ var _ = types.AddType(&types.Type{Name: "cogentcore.org/lab/plot.Stylers", IDNam var _ = types.AddType(&types.Type{Name: "cogentcore.org/lab/plot.DefaultOffOn", IDName: "default-off-on", Doc: "DefaultOffOn specifies whether to use the default value for a bool option,\nor to override the default and set Off or On."}) +var _ = types.AddType(&types.Type{Name: "cogentcore.org/lab/plot.OutOfRange", IDName: "out-of-range", Doc: "OutOfRange specifies how to plot out-of-range values."}) + var _ = types.AddType(&types.Type{Name: "cogentcore.org/lab/plot.pitem", IDName: "pitem", Fields: []types.Field{{Name: "ptyp"}, {Name: "pt"}, {Name: "data"}, {Name: "lbl"}, {Name: "ci"}, {Name: "clr"}}}) var _ = types.AddType(&types.Type{Name: "cogentcore.org/lab/plot.TextStyle", IDName: "text-style", Doc: "TextStyle specifies styling parameters for Text elements.", Directives: []types.Directive{{Tool: "types", Directive: "add", Args: []string{"-setters"}}}, Fields: []types.Field{{Name: "Size", Doc: "Size of font to render. Default is 16dp"}, {Name: "Family", Doc: "Family name for font (inherited): ordered list of comma-separated names\nfrom more general to more specific to use. Use split on, to parse."}, {Name: "Color", Doc: "Color of text."}, {Name: "Align", Doc: "Align specifies how to align text along the relevant\ndimension for the text element."}, {Name: "Padding", Doc: "Padding is used in a case-dependent manner to add\nspace around text elements."}, {Name: "Rotation", Doc: "Rotation of the text, in degrees."}, {Name: "Offset", Doc: "Offset is added directly to the final label location."}}}) diff --git a/yaegilab/labsymbols/cogentcore_org-lab-plot.go b/yaegilab/labsymbols/cogentcore_org-lab-plot.go index 6d81d467..0c3e9cec 100644 --- a/yaegilab/labsymbols/cogentcore_org-lab-plot.go +++ b/yaegilab/labsymbols/cogentcore_org-lab-plot.go @@ -3,7 +3,6 @@ package labsymbols import ( - "cogentcore.org/core/math32/minmax" "cogentcore.org/lab/plot" "reflect" ) @@ -15,6 +14,8 @@ func init() { "AxisScalesValues": reflect.ValueOf(plot.AxisScalesValues), "BasicStylers": reflect.ValueOf(plot.BasicStylers), "Box": reflect.ValueOf(plot.Box), + "Break": reflect.ValueOf(plot.Break), + "BreakMark": reflect.ValueOf(plot.BreakMark), "CheckFloats": reflect.ValueOf(plot.CheckFloats), "CheckNaNs": reflect.ValueOf(plot.CheckNaNs), "Circle": reflect.ValueOf(plot.Circle), @@ -46,6 +47,7 @@ func init() { "Linear": reflect.ValueOf(plot.Linear), "Log": reflect.ValueOf(plot.Log), "Low": reflect.ValueOf(plot.Low), + "Mark": reflect.ValueOf(plot.Mark), "MidStep": reflect.ValueOf(plot.MidStep), "MustCopyRole": reflect.ValueOf(plot.MustCopyRole), "New": reflect.ValueOf(plot.New), @@ -58,6 +60,8 @@ func init() { "NoStep": reflect.ValueOf(plot.NoStep), "Off": reflect.ValueOf(plot.Off), "On": reflect.ValueOf(plot.On), + "OutOfRangeN": reflect.ValueOf(plot.OutOfRangeN), + "OutOfRangeValues": reflect.ValueOf(plot.OutOfRangeValues), "PlotX": reflect.ValueOf(plot.PlotX), "PlotY": reflect.ValueOf(plot.PlotY), "PlotYR": reflect.ValueOf(plot.PlotYR), @@ -69,6 +73,8 @@ func init() { "Pyramid": reflect.ValueOf(plot.Pyramid), "Range": reflect.ValueOf(plot.Range), "RangeClamp": reflect.ValueOf(plot.RangeClamp), + "RangeLogic": reflect.ValueOf(plot.RangeLogic), + "RangeSet": reflect.ValueOf(plot.RangeSet), "RegisterPlotter": reflect.ValueOf(plot.RegisterPlotter), "Ring": reflect.ValueOf(plot.Ring), "RolesN": reflect.ValueOf(plot.RolesN), @@ -83,6 +89,7 @@ func init() { "Square": reflect.ValueOf(plot.Square), "StepKindN": reflect.ValueOf(plot.StepKindN), "StepKindValues": reflect.ValueOf(plot.StepKindValues), + "Stretch": reflect.ValueOf(plot.Stretch), "Styler": reflect.ValueOf(plot.Styler), "Triangle": reflect.ValueOf(plot.Triangle), "U": reflect.ValueOf(plot.U), @@ -113,6 +120,7 @@ func init() { "LogScale": reflect.ValueOf((*plot.LogScale)(nil)), "LogTicks": reflect.ValueOf((*plot.LogTicks)(nil)), "Normalizer": reflect.ValueOf((*plot.Normalizer)(nil)), + "OutOfRange": reflect.ValueOf((*plot.OutOfRange)(nil)), "PanZoom": reflect.ValueOf((*plot.PanZoom)(nil)), "Plot": reflect.ValueOf((*plot.Plot)(nil)), "PlotStyle": reflect.ValueOf((*plot.PlotStyle)(nil)), @@ -164,7 +172,7 @@ type _cogentcore_org_lab_plot_Plotter struct { WData func() (data plot.Data, pixX []float32, pixY []float32) WPlot func(pt *plot.Plot) WStylers func() *plot.Stylers - WUpdateRange func(plt *plot.Plot, x *minmax.F64, y *minmax.F64, yr *minmax.F64, z *minmax.F64, size *minmax.F64) + WUpdateRange func(plt *plot.Plot) } func (W _cogentcore_org_lab_plot_Plotter) ApplyStyle(plotStyle *plot.PlotStyle, idx int) { @@ -173,11 +181,9 @@ func (W _cogentcore_org_lab_plot_Plotter) ApplyStyle(plotStyle *plot.PlotStyle, func (W _cogentcore_org_lab_plot_Plotter) Data() (data plot.Data, pixX []float32, pixY []float32) { return W.WData() } -func (W _cogentcore_org_lab_plot_Plotter) Plot(pt *plot.Plot) { W.WPlot(pt) } -func (W _cogentcore_org_lab_plot_Plotter) Stylers() *plot.Stylers { return W.WStylers() } -func (W _cogentcore_org_lab_plot_Plotter) UpdateRange(plt *plot.Plot, x *minmax.F64, y *minmax.F64, yr *minmax.F64, z *minmax.F64, size *minmax.F64) { - W.WUpdateRange(plt, x, y, yr, z, size) -} +func (W _cogentcore_org_lab_plot_Plotter) Plot(pt *plot.Plot) { W.WPlot(pt) } +func (W _cogentcore_org_lab_plot_Plotter) Stylers() *plot.Stylers { return W.WStylers() } +func (W _cogentcore_org_lab_plot_Plotter) UpdateRange(plt *plot.Plot) { W.WUpdateRange(plt) } // _cogentcore_org_lab_plot_Thumbnailer is an interface wrapper for Thumbnailer type type _cogentcore_org_lab_plot_Thumbnailer struct { From 413b2d1e9d207e2a7d5e122b1c1ef6822c1b602e Mon Sep 17 00:00:00 2001 From: "Randall C. O'Reilly" Date: Fri, 8 May 2026 22:03:33 +0200 Subject: [PATCH 3/8] plotminmax: OutOfRange bar plot logic working --- plot/data.go | 17 +++---- plot/plots/bar.go | 103 +++++++++++++++++++++++++++++++++------- plot/plots/plot_test.go | 25 +++++++++- plot/plots/xy.go | 16 +++---- 4 files changed, 127 insertions(+), 34 deletions(-) diff --git a/plot/data.go b/plot/data.go index f652c139..ca46332a 100644 --- a/plot/data.go +++ b/plot/data.go @@ -155,29 +155,30 @@ func Range(data Valuer, rng *minmax.F64) { // Returns true if the range of the data fits entirely within the styleRng // min / max values. func RangeLogic(oor OutOfRange, data Valuer, axisRng *minmax.F64, styleRng *minmax.Range64) bool { + Range(data, axisRng) if oor == Stretch { - RangeClamp(data, axisRng, styleRng) + RangeClamp(axisRng, styleRng) return true // by definition } - return RangeSet(data, axisRng, styleRng) + return RangeSet(axisRng, styleRng) } // RangeClamp updates the given axis Min, Max range values based -// on the range of values in the given [Data], and the given style range. -func RangeClamp(data Valuer, axisRng *minmax.F64, styleRng *minmax.Range64) { - Range(data, axisRng) +// on the axis range (from data values), and the given style range. +// The style can only stretch the range, not shrink it. +func RangeClamp(axisRng *minmax.F64, styleRng *minmax.Range64) { axisRng.Min, axisRng.Max = styleRng.Clamp(axisRng.Min, axisRng.Max) } // RangeSetFromStyle sets the axis range based on the given style range, // where styleRng flags for Min or Max are set, and otherwise gets the range -// from the actual data. This is for the case where the flags indicate a hard, +// from the axis range (based on actual data). +// This is for the case where the flags indicate a hard, // non-stretchable extreme, whereas RangeClamp is the stretch case. // Returns true if the range of the data fits entirely within the styleRng // min / max values. -func RangeSet(data Valuer, axisRng *minmax.F64, styleRng *minmax.Range64) bool { +func RangeSet(axisRng *minmax.F64, styleRng *minmax.Range64) bool { fits := true - Range(data, axisRng) if styleRng.FixMin { if axisRng.Min < styleRng.Min { fits = false diff --git a/plot/plots/bar.go b/plot/plots/bar.go index c287606a..42f9c835 100644 --- a/plot/plots/bar.go +++ b/plot/plots/bar.go @@ -154,6 +154,7 @@ func (bc *Bar) Plot(plt *plot.Plot) { bc.Style.Line.SetStroke(plt) pc.Fill.Color = bc.Style.Line.Fill bw := bc.Style.Width + oor := plt.Style.OutOfRange nv := len(bc.Y) bc.X = make(plot.Values, nv) @@ -161,24 +162,43 @@ func (bc *Bar) Plot(plt *plot.Plot) { bc.PX = make([]float32, nv) bc.PY = make([]float32, nv) + var minY, maxY float64 + if bc.Horizontal { + minY, maxY = plt.X.DataRange.Min, plt.X.DataRange.Max + } else { + if bc.Style.RightY { + minY, maxY = plt.YR.DataRange.Min, plt.YR.DataRange.Max + } else { + minY, maxY = plt.Y.DataRange.Min, plt.Y.DataRange.Max + } + } + hw := 0.5 * bw.Width ew := bw.Width / 3 + hasOORMarks := false for i, ht := range bc.Y { if math.IsNaN(ht) { continue } cat := bw.Offset + float64(i)*bw.Stride - var bottom float64 + bottom := bc.StackedOn.BarHeight(i) // nil safe + val := bottom + ht + if val < minY || val > maxY { + if oor.HasMark() { + hasOORMarks = true + } + continue + } + var catVal, catMin, catMax, valMin, valMax float32 var box math32.Box2 if bc.Horizontal { catVal = plt.PY(cat) catMin = plt.PY(cat - hw) catMax = plt.PY(cat + hw) - bottom = bc.StackedOn.BarHeight(i) // nil safe valMin = plt.PX(bottom) - valMax = plt.PX(bottom + ht) - bc.X[i] = bottom + ht + valMax = plt.PX(val) + bc.X[i] = val bc.Yp[i] = cat bc.PX[i] = valMax bc.PY[i] = catVal @@ -188,11 +208,10 @@ func (bc *Bar) Plot(plt *plot.Plot) { catVal = plt.PX(cat) catMin = plt.PX(cat - hw) catMax = plt.PX(cat + hw) - bottom = bc.StackedOn.BarHeight(i) // nil safe valMin = plt.PY(bottom) - valMax = plt.PY(bottom + ht) + valMax = plt.PY(val) bc.X[i] = cat - bc.Yp[i] = bottom + ht + bc.Yp[i] = val bc.PX[i] = catVal bc.PY[i] = valMax box.Min.Set(catMin, valMin) @@ -224,7 +243,34 @@ func (bc *Bar) Plot(plt *plot.Plot) { pc.Draw() } } + pc.Fill.Color = nil + if hasOORMarks { + bc.Style.OutOfRangeMark.SetStroke(plt) + for i, ht := range bc.Y { + if math.IsNaN(ht) { + continue + } + bottom := bc.StackedOn.BarHeight(i) // nil safe + val := bottom + ht + if val >= minY && val <= maxY { + continue + } + val = max(val, minY) + val = min(val, maxY) + + cat := bw.Offset + float64(i)*bw.Stride + var ptx, pty float32 + if bc.Horizontal { + ptx = plt.PX(val) + pty = plt.PY(cat) + } else { + ptx = plt.PX(cat) + pty = plt.PY(val) + } + bc.Style.OutOfRangeMark.DrawShape(pc, math32.Vec2(ptx, pty)) + } + } } // UpdateRange updates the given ranges. @@ -232,24 +278,14 @@ func (bc *Bar) UpdateRange(plt *plot.Plot) { bw := bc.Style.Width catMin := bw.Offset - bw.Pad catMax := bw.Offset + float64(len(bc.Y)-1)*bw.Stride + bw.Pad - yax := &plt.Y if bc.Style.RightY { yax = &plt.YR } - if bc.Horizontal { - plot.RangeLogic(plt.Style.OutOfRange, bc.Y, &plt.X.Range, &bc.Style.Range) - plot.RangeLogic(plt.Style.OutOfRange, bc.X, &yax.Range, &plt.Style.XAxis.Range) - } else { - plot.RangeLogic(plt.Style.OutOfRange, bc.X, &plt.X.Range, &plt.Style.XAxis.Range) - plot.RangeLogic(plt.Style.OutOfRange, bc.Y, &yax.Range, &bc.Style.Range) - } - var ticks plot.ConstantTicks if bc.XLabels != nil { ticks = make(plot.ConstantTicks, len(bc.Y)) } - for i, val := range bc.Y { valBot := bc.StackedOn.BarHeight(i) valTop := valBot + val @@ -284,8 +320,41 @@ func (bc *Bar) UpdateRange(plt *plot.Plot) { plt.X.Ticker = ticks } } + + yFits := true + if bc.Horizontal { + if plt.Style.OutOfRange == plot.Stretch { + plot.RangeClamp(&plt.X.Range, &bc.Style.Range) + plot.RangeClamp(&yax.Range, &plt.Style.XAxis.Range) + } else { + yFits = plot.RangeSet(&plt.X.Range, &bc.Style.Range) + plot.RangeSet(&yax.Range, &plt.Style.XAxis.Range) + } + } else { + if plt.Style.OutOfRange == plot.Stretch { + plot.RangeClamp(&plt.X.Range, &plt.Style.XAxis.Range) + plot.RangeClamp(&yax.Range, &bc.Style.Range) + } else { + plot.RangeSet(&plt.X.Range, &plt.Style.XAxis.Range) + yFits = plot.RangeSet(&yax.Range, &bc.Style.Range) + } + } + plt.X.DataRange = plt.X.Range yax.DataRange = yax.Range + + bc.Style.OutOfRangeMark.IsOn(plt) // does dots + if !plt.Style.OutOfRange.HasMark() || yFits { + return + } + psz := bc.Style.OutOfRangeMark.Size.Dots + bsz := plt.DataBox() + dy := (float64(psz) / float64(bsz.Y)) * yax.Range.Range() + yax.Range.Min -= dy + yax.Range.Max += dy + dx := (float64(psz) / float64(bsz.X)) * plt.X.Range.Range() + plt.X.Range.Min -= dx + plt.X.Range.Max += dx } // Thumbnail fulfills the plot.Thumbnailer interface. diff --git a/plot/plots/plot_test.go b/plot/plots/plot_test.go index 0524b4a2..72a2f6c4 100644 --- a/plot/plots/plot_test.go +++ b/plot/plots/plot_test.go @@ -254,7 +254,30 @@ func TestOutOfRange(t *testing.T) { t.Fatal("bad data") } - imagex.Assert(t, plt.RenderImage(), "out-of-range-"+oor.String()) + imagex.Assert(t, plt.RenderImage(), "out-of-range-line-"+oor.String()) + } + for i := range 2 { + for oor := range plot.OutOfRangeN { + plt := plot.New() + plt.Title.Text = "Test Bar" + plt.X.Label.Text = "X Axis" + plt.Y.Label.Text = "Y Axis" + plt.Style.OutOfRange = oor + + l1 := NewBar(plt, data).Styler(func(s *plot.Style) { + s.Range.SetMin(20) + s.Range.SetMax(80) + }) + if l1 == nil { + t.Fatal("bad data") + } + if i == 0 { + imagex.Assert(t, plt.RenderImage(), "out-of-range-bar-"+oor.String()) + } else { + l1.Horizontal = true + imagex.Assert(t, plt.RenderImage(), "out-of-range-bar-horiz-"+oor.String()) + } + } } } diff --git a/plot/plots/xy.go b/plot/plots/xy.go index ea8e3964..c2e36d25 100644 --- a/plot/plots/xy.go +++ b/plot/plots/xy.go @@ -160,12 +160,11 @@ func (ln *XY) Plot(plt *plot.Plot) { var minY, maxY float32 if ln.Style.RightY { ln.PY = plot.PlotYR(plt, ln.Y) - minY = plt.PYR(plt.YR.DataRange.Max) // flipped due to Y flip - maxY = plt.PYR(plt.YR.DataRange.Min) + // flipped due to Y flip + minY, maxY = plt.PYR(plt.YR.DataRange.Max), plt.PYR(plt.YR.DataRange.Min) } else { ln.PY = plot.PlotY(plt, ln.Y) - minY = plt.PY(plt.Y.DataRange.Max) - maxY = plt.PY(plt.Y.DataRange.Min) + minY, maxY = plt.PY(plt.Y.DataRange.Max), plt.PY(plt.Y.DataRange.Min) } np := min(len(ln.PX), len(ln.PY)) if np == 0 { @@ -310,11 +309,12 @@ func (ln *XY) Plot(plt *plot.Plot) { if ptx < minX || ptx > maxX { continue } - if pty < minY || pty > maxY { - pty = min(pty, maxY) - pty = max(pty, minY) - ln.Style.OutOfRangeMark.DrawShape(pc, math32.Vec2(ptx, pty)) + if pty >= minY && pty <= maxY { + continue } + pty = min(pty, maxY) + pty = max(pty, minY) + ln.Style.OutOfRangeMark.DrawShape(pc, math32.Vec2(ptx, pty)) } } From 4b6cc727e1209b7fb8d9ad91ac27a3aeed3daf27 Mon Sep 17 00:00:00 2001 From: "Randall C. O'Reilly" Date: Fri, 8 May 2026 22:32:10 +0200 Subject: [PATCH 4/8] plotminmax: all the other plots cases updated --- plot/data.go | 7 ++-- plot/plots/bar.go | 24 +++++--------- plot/plots/errbars.go | 74 ++++++++++++++++++++++++++++++++++--------- plot/plots/labels.go | 34 ++++++++++++++++---- plot/plots/xy.go | 17 ++++++++-- 5 files changed, 112 insertions(+), 44 deletions(-) diff --git a/plot/data.go b/plot/data.go index ca46332a..511a2885 100644 --- a/plot/data.go +++ b/plot/data.go @@ -153,9 +153,8 @@ func Range(data Valuer, rng *minmax.F64) { // RangeLogic processes the OutOfRange setting to set the given axis range // based on style range settings (i.e., dealing with Stretch vs. other cases). // Returns true if the range of the data fits entirely within the styleRng -// min / max values. -func RangeLogic(oor OutOfRange, data Valuer, axisRng *minmax.F64, styleRng *minmax.Range64) bool { - Range(data, axisRng) +// min / max values (according to axisRng which must already be updated from data). +func RangeLogic(oor OutOfRange, axisRng *minmax.F64, styleRng *minmax.Range64) bool { if oor == Stretch { RangeClamp(axisRng, styleRng) return true // by definition @@ -170,7 +169,7 @@ func RangeClamp(axisRng *minmax.F64, styleRng *minmax.Range64) { axisRng.Min, axisRng.Max = styleRng.Clamp(axisRng.Min, axisRng.Max) } -// RangeSetFromStyle sets the axis range based on the given style range, +// RangeSet sets the axis range based on the given style range, // where styleRng flags for Min or Max are set, and otherwise gets the range // from the axis range (based on actual data). // This is for the case where the flags indicate a hard, diff --git a/plot/plots/bar.go b/plot/plots/bar.go index 42f9c835..1d0f062d 100644 --- a/plot/plots/bar.go +++ b/plot/plots/bar.go @@ -289,6 +289,9 @@ func (bc *Bar) UpdateRange(plt *plot.Plot) { for i, val := range bc.Y { valBot := bc.StackedOn.BarHeight(i) valTop := valBot + val + if math.IsNaN(valBot) || math.IsNaN(valTop) { + continue + } if i < len(bc.Err) { valTop += math.Abs(bc.Err[i]) } @@ -321,25 +324,14 @@ func (bc *Bar) UpdateRange(plt *plot.Plot) { } } - yFits := true + yFits := false if bc.Horizontal { - if plt.Style.OutOfRange == plot.Stretch { - plot.RangeClamp(&plt.X.Range, &bc.Style.Range) - plot.RangeClamp(&yax.Range, &plt.Style.XAxis.Range) - } else { - yFits = plot.RangeSet(&plt.X.Range, &bc.Style.Range) - plot.RangeSet(&yax.Range, &plt.Style.XAxis.Range) - } + yFits = plot.RangeLogic(plt.Style.OutOfRange, &plt.X.Range, &bc.Style.Range) + plot.RangeLogic(plt.Style.OutOfRange, &yax.Range, &plt.Style.XAxis.Range) } else { - if plt.Style.OutOfRange == plot.Stretch { - plot.RangeClamp(&plt.X.Range, &plt.Style.XAxis.Range) - plot.RangeClamp(&yax.Range, &bc.Style.Range) - } else { - plot.RangeSet(&plt.X.Range, &plt.Style.XAxis.Range) - yFits = plot.RangeSet(&yax.Range, &bc.Style.Range) - } + plot.RangeLogic(plt.Style.OutOfRange, &plt.X.Range, &plt.Style.XAxis.Range) + yFits = plot.RangeLogic(plt.Style.OutOfRange, &yax.Range, &bc.Style.Range) } - plt.X.DataRange = plt.X.Range yax.DataRange = yax.Range diff --git a/plot/plots/errbars.go b/plot/plots/errbars.go index aebb7924..9b6a7358 100644 --- a/plot/plots/errbars.go +++ b/plot/plots/errbars.go @@ -112,19 +112,32 @@ func (eb *YErrorBars) Plot(plt *plot.Plot) { nv := len(eb.X) eb.PX = make([]float32, nv) eb.PY = make([]float32, nv) + + minX, maxX := plt.PX(plt.X.DataRange.Min), plt.PX(plt.X.DataRange.Max) + var minY, maxY float32 + if eb.Style.RightY { + minY, maxY = plt.PYR(plt.YR.DataRange.Max), plt.PYR(plt.YR.DataRange.Min) + } else { + minY, maxY = plt.PY(plt.Y.DataRange.Max), plt.PY(plt.Y.DataRange.Min) + } + eb.Style.Line.SetStroke(plt) for i, y := range eb.Y { x := plt.PX(eb.X.Float1D(i)) if math32.IsNaN(x) || math.IsNaN(y) { continue } - ylow := float32(eb.Low[i]) - yhigh := float32(eb.High[i]) + if x < minX || x > maxX { + continue + } + ylow := plt.PY(y - math.Abs(eb.Low[i])) + yhigh := plt.PY(y + math.Abs(eb.High[i])) if math32.IsNaN(ylow) || math32.IsNaN(yhigh) { continue } - ylow = plt.PY(y - float64(math32.Abs(ylow))) - yhigh = plt.PY(y + float64(math32.Abs(yhigh))) + if ylow < minY || yhigh > maxY { + continue + } eb.PX[i] = x eb.PY[i] = yhigh @@ -147,17 +160,22 @@ func (eb *YErrorBars) UpdateRange(plt *plot.Plot) { if eb.Style.RightY { yax = &plt.YR } - plot.RangeLogic(plt.Style.OutOfRange, eb.X, &plt.X.Range, &plt.Style.XAxis.Range) - plt.X.DataRange = plt.X.Range - plot.RangeLogic(plt.Style.OutOfRange, eb.Y, &yax.Range, &eb.Style.Range) - yax.DataRange = yax.Range + plot.Range(eb.X, &plt.X.Range) + plot.Range(eb.Y, &yax.Range) for i, yv := range eb.Y { ylow := yv - math.Abs(eb.Low[i]) yhigh := yv + math.Abs(eb.High[i]) + if math.IsNaN(ylow) || math.IsNaN(yhigh) { + continue + } yax.Range.FitInRange(minmax.F64{ylow, yhigh}) } - return + + plot.RangeLogic(plt.Style.OutOfRange, &plt.X.Range, &plt.Style.XAxis.Range) + plt.X.DataRange = plt.X.Range + plot.RangeLogic(plt.Style.OutOfRange, &yax.Range, &eb.Style.Range) + yax.DataRange = yax.Range } //////// XErrorBars @@ -247,11 +265,32 @@ func (eb *XErrorBars) Plot(plt *plot.Plot) { nv := len(eb.X) eb.PX = make([]float32, nv) eb.PY = make([]float32, nv) + + minX, maxX := plt.PX(plt.X.DataRange.Min), plt.PX(plt.X.DataRange.Max) + var minY, maxY float32 + if eb.Style.RightY { + minY, maxY = plt.PYR(plt.YR.DataRange.Max), plt.PYR(plt.YR.DataRange.Min) + } else { + minY, maxY = plt.PY(plt.Y.DataRange.Max), plt.PY(plt.Y.DataRange.Min) + } + eb.Style.Line.SetStroke(plt) for i, x := range eb.X { y := plt.PY(eb.Y.Float1D(i)) + if math32.IsNaN(y) || math.IsNaN(x) { + continue + } + if y < minY || y > maxY { + continue + } xlow := plt.PX(x - math.Abs(eb.Low[i])) xhigh := plt.PX(x + math.Abs(eb.High[i])) + if math32.IsNaN(xlow) || math32.IsNaN(xhigh) { + continue + } + if xlow < minX || xhigh > maxX { + continue + } eb.PX[i] = xhigh eb.PY[i] = y @@ -274,15 +313,20 @@ func (eb *XErrorBars) UpdateRange(plt *plot.Plot) { if eb.Style.RightY { yax = &plt.YR } - plot.RangeLogic(plt.Style.OutOfRange, eb.X, &plt.X.Range, &plt.Style.XAxis.Range) - plt.X.DataRange = plt.X.Range - plot.RangeLogic(plt.Style.OutOfRange, eb.Y, &yax.Range, &eb.Style.Range) - yax.DataRange = yax.Range - + plot.Range(eb.X, &plt.X.Range) + plot.Range(eb.Y, &yax.Range) for i, xv := range eb.X { xlow := xv - math.Abs(eb.Low[i]) xhigh := xv + math.Abs(eb.High[i]) + if math.IsNaN(xlow) || math.IsNaN(xhigh) { + continue + } plt.X.Range.FitInRange(minmax.F64{xlow, xhigh}) } - return + + plot.RangeLogic(plt.Style.OutOfRange, &plt.X.Range, &plt.Style.XAxis.Range) + plt.X.DataRange = plt.X.Range + + plot.RangeLogic(plt.Style.OutOfRange, &yax.Range, &eb.Style.Range) + yax.DataRange = yax.Range } diff --git a/plot/plots/labels.go b/plot/plots/labels.go index 72436864..519c9b78 100644 --- a/plot/plots/labels.go +++ b/plot/plots/labels.go @@ -6,6 +6,7 @@ package plots import ( "image" + "math" "cogentcore.org/core/math32" "cogentcore.org/core/math32/minmax" @@ -104,7 +105,16 @@ func (lb *Labels) Plot(plt *plot.Plot) { pc := plt.Painter uc := &pc.UnitContext lb.PX = plot.PlotX(plt, lb.X) - lb.PY = plot.PlotY(plt, lb.Y) + minX, maxX := plt.PX(plt.X.DataRange.Min), plt.PX(plt.X.DataRange.Max) + var minY, maxY float32 + if lb.Style.RightY { + lb.PY = plot.PlotYR(plt, lb.Y) + // flipped due to Y flip + minY, maxY = plt.PYR(plt.YR.DataRange.Max), plt.PYR(plt.YR.DataRange.Min) + } else { + lb.PY = plot.PlotY(plt, lb.Y) + minY, maxY = plt.PY(plt.Y.DataRange.Max), plt.PY(plt.Y.DataRange.Min) + } st := &lb.Style.Text st.Offset.ToDots(uc) var ltxt plot.Text @@ -126,6 +136,9 @@ func (lb *Labels) Plot(plt *plot.Plot) { if math32.IsNaN(ptx) || math32.IsNaN(pty) { continue } + if ptx < minX || ptx > maxX || pty < minY || pty > maxY { + continue + } ltxt.Text = label ltxt.Config(plt) tht := ltxt.Size().Y @@ -139,10 +152,8 @@ func (lb *Labels) UpdateRange(plt *plot.Plot) { if lb.Style.RightY { yax = &plt.YR } - plot.RangeLogic(plt.Style.OutOfRange, lb.X, &plt.X.Range, &plt.Style.XAxis.Range) - plt.X.DataRange = plt.X.Range - plot.RangeLogic(plt.Style.OutOfRange, lb.Y, &yax.Range, &lb.Style.Range) - yax.DataRange = yax.Range + plot.Range(lb.X, &plt.X.Range) + plot.Range(lb.Y, &yax.Range) var pxToData math32.Vector2 bsz := plt.DataBox() @@ -155,15 +166,24 @@ func (lb *Labels) UpdateRange(plt *plot.Plot) { if label == "" { continue } + xv := lb.X[i] + yv := lb.Y[i] + if math.IsNaN(xv) || math.IsNaN(yv) { + continue + } ltxt.Text = label ltxt.Config(plt) tht := pxToData.Y * ltxt.Size().Y twd := 1.1 * pxToData.X * ltxt.Size().X - xv := lb.X[i] - yv := lb.Y[i] maxx := xv + float64(pxToData.X*st.Offset.X.Dots+twd) maxy := yv + float64(pxToData.Y*st.Offset.Y.Dots+tht) // y is up here plt.X.Range.FitInRange(minmax.F64{xv, maxx}) yax.Range.FitInRange(minmax.F64{yv, maxy}) } + + plot.RangeLogic(plt.Style.OutOfRange, &plt.X.Range, &plt.Style.XAxis.Range) + plt.X.DataRange = plt.X.Range + + plot.RangeLogic(plt.Style.OutOfRange, &yax.Range, &lb.Style.Range) + yax.DataRange = yax.Range } diff --git a/plot/plots/xy.go b/plot/plots/xy.go index c2e36d25..2231d7eb 100644 --- a/plot/plots/xy.go +++ b/plot/plots/xy.go @@ -185,6 +185,13 @@ func (ln *XY) Plot(plt *plot.Plot) { if math32.IsNaN(pty) { continue } + if ptx > maxX { + continue // could wrap around + } + if ptx < minX { + hasPrev = false + continue + } if !hasPrev && !math32.IsNaN(ptx) && !math32.IsNaN(pty) { pc.MoveTo(ptx, botY) prevX = ptx @@ -326,6 +333,9 @@ func (ln *XY) Plot(plt *plot.Plot) { if math32.IsNaN(ptx) || math32.IsNaN(pty) { continue } + if ptx < minX || ptx > maxX || pty < minY || pty > maxY { + continue + } pc.Stroke.Width = origWidth ln.Style.Point.Size = origSize if plt.HighlightPlotter == ln { @@ -367,9 +377,12 @@ func (ln *XY) UpdateRange(plt *plot.Plot) { if ln.Style.RightY { yax = &plt.YR } - plot.RangeLogic(plt.Style.OutOfRange, ln.X, &plt.X.Range, &plt.Style.XAxis.Range) + plot.Range(ln.X, &plt.X.Range) + plot.Range(ln.Y, &yax.Range) + + plot.RangeLogic(plt.Style.OutOfRange, &plt.X.Range, &plt.Style.XAxis.Range) plt.X.DataRange = plt.X.Range - yFits := plot.RangeLogic(plt.Style.OutOfRange, ln.Y, &yax.Range, &ln.Style.Range) + yFits := plot.RangeLogic(plt.Style.OutOfRange, &yax.Range, &ln.Style.Range) yax.DataRange = yax.Range ln.Style.OutOfRangeMark.IsOn(plt) // does dots From a8f5ccc18b5471736d8eaa5d15a321dd43d7fd2c Mon Sep 17 00:00:00 2001 From: "Randall C. O'Reilly" Date: Mon, 11 May 2026 12:45:03 +0200 Subject: [PATCH 5/8] plotminmax: gosl: add MaxStorageBuffersPerShaderStage var to config, set to 16 as new default. Should be true soon on chrome, firefox. --- go.mod | 14 +++++++++----- go.sum | 28 ++++++++++++++++++---------- gosl/gotosl/config.go | 6 ++++++ gosl/gotosl/translate.go | 6 +++--- gosl/gotosl/typegen.go | 6 ++++-- 5 files changed, 40 insertions(+), 20 deletions(-) diff --git a/go.mod b/go.mod index a66108db..423f19eb 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ go 1.25.6 // https://github.com/googleapis/go-genproto/issues/1015 require ( - cogentcore.org/core v0.3.25 + cogentcore.org/core v0.3.26-0.20260510231010-7a87368671eb github.com/cogentcore/readline v0.1.3 github.com/cogentcore/yaegi v0.0.0-20260116172027-700fbf8949f3 github.com/mitchellh/go-homedir v1.1.0 @@ -32,16 +32,15 @@ require ( github.com/aymerick/douceur v0.2.0 // indirect github.com/bramvdbogaerde/go-scp v1.6.0 // indirect github.com/chewxy/math32 v1.11.1 // indirect - github.com/cogentcore/webgpu v0.23.1-0.20260410073005-a2ae7d757168 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dlclark/regexp2 v1.11.5 // indirect github.com/ericchiang/css v1.4.0 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/go-fonts/latin-modern v0.3.3 // indirect - github.com/go-gl/glfw/v3.4/glfw v0.1.0-pre.1 // indirect + github.com/go-gl/glfw/v3.4/glfw v0.1.0-pre.1.0.20260406072232-3ac4aa2bb164 // indirect github.com/go-text/typesetting v0.3.5-0.20260418130854-c41d02a44bec // indirect github.com/gobwas/glob v0.2.3 // indirect - github.com/gomarkdown/markdown v0.0.0-20250810172220-2e2c11897d1a // indirect + github.com/gomarkdown/markdown v0.0.0-20260417124207-7d523f7318df // indirect github.com/gorilla/css v1.0.1 // indirect github.com/h2non/filetype v1.1.3 // indirect github.com/hack-pad/go-indexeddb v0.3.2 // indirect @@ -55,6 +54,12 @@ require ( github.com/mattn/go-runewidth v0.0.15 // indirect github.com/mattn/go-shellwords v1.0.12 // indirect github.com/muesli/termenv v0.16.0 // indirect + github.com/oliverbestmann/webgpu v1.33.0 // indirect + github.com/oliverbestmann/webgpu/libs-android v0.0.0-20260509160813-48db59792a15 // indirect + github.com/oliverbestmann/webgpu/libs-darwin v0.0.0-20260509160802-b09403b07cd3 // indirect + github.com/oliverbestmann/webgpu/libs-ios v0.0.0-20260509160803-765e39d2a48b // indirect + github.com/oliverbestmann/webgpu/libs-linux v0.0.0-20260509160809-2fefaf7c9ead // indirect + github.com/oliverbestmann/webgpu/libs-windows v0.0.0-20260509160807-0bc32b12c7bc // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/rivo/uniseg v0.4.7 // indirect @@ -66,7 +71,6 @@ require ( golang.org/x/sync v0.20.0 // indirect golang.org/x/sys v0.42.0 // indirect golang.org/x/text v0.36.0 // indirect - google.golang.org/genproto v0.0.0-20260420184626-e10c466a9529 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect modernc.org/knuth v0.5.4 // indirect diff --git a/go.sum b/go.sum index c333e856..f1c8c5df 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ codeberg.org/go-pdf/fpdf v0.11.0 h1:n3I8WISQ1cr0S2rvx9DOlE/GypbcimMWqLpel3slHmY= codeberg.org/go-pdf/fpdf v0.11.0/go.mod h1:Y0DGRAdZ0OmnZPvjbMp/1bYxmIPxm0ws4tfoPOc4LjU= -cogentcore.org/core v0.3.25 h1:nrECnVQIl/JvyGFae5c/KystUAlLwSmIsjW1MkpkpiU= -cogentcore.org/core v0.3.25/go.mod h1:+5R2kihBnWrFmRlYd8yJ8JmRuLsGgCXXgvcgLk/YDEI= +cogentcore.org/core v0.3.26-0.20260510231010-7a87368671eb h1:VOuJQEOc9XKhmnu33bL90WWujasVbLUxGjf5bTimoDs= +cogentcore.org/core v0.3.26-0.20260510231010-7a87368671eb/go.mod h1:6h+YTWqpJSbewcM17zvj2FijuvkA+Yr55SNQbFIoGGM= git.sr.ht/~sbinet/cmpimg v0.1.0 h1:E0zPRk2muWuCqSKSVZIWsgtU9pjsw3eKHi8VmQeScxo= git.sr.ht/~sbinet/cmpimg v0.1.0/go.mod h1:FU12psLbF4TfNXkKH2ZZQ29crIqoiqTZmeQ7dkp/pxE= github.com/Bios-Marcel/wastebasket/v2 v2.0.3 h1:TkoDPcSqluhLGE+EssHu7UGmLgUEkWg7kNyHyyJ3Q9g= @@ -30,8 +30,6 @@ github.com/chewxy/math32 v1.11.1 h1:b7PGHlp8KjylDoU8RrcEsRuGZhJuz8haxnKfuMMRqy8= github.com/chewxy/math32 v1.11.1/go.mod h1:dOB2rcuFrCn6UHrze36WSLVPKtzPMRAQvBvUwkSsLqs= github.com/cogentcore/readline v0.1.3 h1:tYmjP3XHvsGwhsDLkAp+vBhkERmLFENZfftyPOR/PBE= github.com/cogentcore/readline v0.1.3/go.mod h1:IHVtJHSKXspK7CMg3OC/bbPEXxO++dFlug/vsPktvas= -github.com/cogentcore/webgpu v0.23.1-0.20260410073005-a2ae7d757168 h1:K5en4IrBrolIAWvjrLuXRb9CvU1w+WMMi0Eu0KmcMfQ= -github.com/cogentcore/webgpu v0.23.1-0.20260410073005-a2ae7d757168/go.mod h1:DQLhF8pM/WkdaGpX6pKmZJPYsoR9x+hohhA1nnNuCa8= github.com/cogentcore/yaegi v0.0.0-20260116172027-700fbf8949f3 h1:y3Djpt/g3QTjFdj8cpvy/r8FsZsEa7PqHGjgsKXbta0= github.com/cogentcore/yaegi v0.0.0-20260116172027-700fbf8949f3/go.mod h1:XkOm++pRmWlk85p+hw71ZItfTeRdzqG23+2xjP9eb+M= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -47,8 +45,8 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/go-fonts/latin-modern v0.3.3 h1:g2xNgI8yzdNzIVm+qvbMryB6yGPe0pSMss8QT3QwlJ0= github.com/go-fonts/latin-modern v0.3.3/go.mod h1:tHaiWDGze4EPB0Go4cLT5M3QzRY3peya09Z/8KSCrpY= -github.com/go-gl/glfw/v3.4/glfw v0.1.0-pre.1 h1:nIVzcwqIaO1mK8LFr0fGkKpgQD4wJDDHRyv4t5k40Ps= -github.com/go-gl/glfw/v3.4/glfw v0.1.0-pre.1/go.mod h1:T5Dn0JwIJOX1euPZ/iT4tq6nFYtmukjcYa7937HuYK8= +github.com/go-gl/glfw/v3.4/glfw v0.1.0-pre.1.0.20260406072232-3ac4aa2bb164 h1:c87Nyz3ox3QbCl0yozQPeVPW4mmgFOSKY4yyc1TrS0w= +github.com/go-gl/glfw/v3.4/glfw v0.1.0-pre.1.0.20260406072232-3ac4aa2bb164/go.mod h1:T5Dn0JwIJOX1euPZ/iT4tq6nFYtmukjcYa7937HuYK8= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= @@ -61,8 +59,8 @@ github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/gomarkdown/markdown v0.0.0-20250810172220-2e2c11897d1a h1:l7A0loSszR5zHd/qK53ZIHMO8b3bBSmENnQ6eKnUT0A= -github.com/gomarkdown/markdown v0.0.0-20250810172220-2e2c11897d1a/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= +github.com/gomarkdown/markdown v0.0.0-20260417124207-7d523f7318df h1:Mwihr/o+v4L5h56rwHLOE20+hh7Okhwno5BHz3zDuao= +github.com/gomarkdown/markdown v0.0.0-20260417124207-7d523f7318df/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= @@ -103,6 +101,18 @@ github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= github.com/nsf/termbox-go v1.1.1 h1:nksUPLCb73Q++DwbYUBEglYBRPZyoXJdrj5L+TkjyZY= github.com/nsf/termbox-go v1.1.1/go.mod h1:T0cTdVuOwf7pHQNtfhnEbzHbcNyCEcVU4YPpouCbVxo= +github.com/oliverbestmann/webgpu v1.33.0 h1:Nr0IYIApoELWwDrF42nlEmgnuI0F517J4kbWPK9ZNIM= +github.com/oliverbestmann/webgpu v1.33.0/go.mod h1:0UEcoJ8VnwnAqo3JfzdFptplxtjhaQasc3n/nYZOrPA= +github.com/oliverbestmann/webgpu/libs-android v0.0.0-20260509160813-48db59792a15 h1:HPxVSV8C8JaxGfa9hjDhzNmryoqPF3EwESBTFWpxNBo= +github.com/oliverbestmann/webgpu/libs-android v0.0.0-20260509160813-48db59792a15/go.mod h1:tczQXCdsoFy+FTJVsZSve/vF8cmWEkxhvjcyY2Rujp8= +github.com/oliverbestmann/webgpu/libs-darwin v0.0.0-20260509160802-b09403b07cd3 h1:NbBG2+pwqKcNfKUKtjWOj+02RkXSUWVkxY3hqzgyjSA= +github.com/oliverbestmann/webgpu/libs-darwin v0.0.0-20260509160802-b09403b07cd3/go.mod h1:XoHM/ZcjQqJQyEfQjU0ScDkxvQRWfZLxKP8IrEz4xyo= +github.com/oliverbestmann/webgpu/libs-ios v0.0.0-20260509160803-765e39d2a48b h1:j+uRWcmAl3Y4RPJ4rmxnc1DRHgZ6VNywZPsRHUEuD0M= +github.com/oliverbestmann/webgpu/libs-ios v0.0.0-20260509160803-765e39d2a48b/go.mod h1:IV+TkwmPA0yMzZZoz0Aj4X+22WLEQq2TOyN4/0k8lgs= +github.com/oliverbestmann/webgpu/libs-linux v0.0.0-20260509160809-2fefaf7c9ead h1:kkY04PFBq6I58BwK5cwJ3LRp+xy7Y5/jrkLHBdcBL68= +github.com/oliverbestmann/webgpu/libs-linux v0.0.0-20260509160809-2fefaf7c9ead/go.mod h1:SOeo2YWe2UxWxOeAHyZtwaSXkBbP78cGnm7I+6lIWV0= +github.com/oliverbestmann/webgpu/libs-windows v0.0.0-20260509160807-0bc32b12c7bc h1:YVCfgeByW1ibKniigozHCwF2wC26TDmAIJwQG40bCBM= +github.com/oliverbestmann/webgpu/libs-windows v0.0.0-20260509160807-0bc32b12c7bc/go.mod h1:58qRJHG2+mjEu/AKJFh026bz3xE1zEHYt41i4TBM8NE= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -167,8 +177,6 @@ golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= -google.golang.org/genproto v0.0.0-20260420184626-e10c466a9529 h1:QoMBg0moLIlB/eucPzc+ID5SgPZWuirtjAn3l8nW2Dg= -google.golang.org/genproto v0.0.0-20260420184626-e10c466a9529/go.mod h1:EjLmDZ8liSLBrCTK5vP+bGIxRQHE3ovGvOI0CzGk1PI= google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 h1:RmoJA1ujG+/lRGNfUnOMfhCy5EipVMyvUE+KNbPbTlw= google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM= diff --git a/gosl/gotosl/config.go b/gosl/gotosl/config.go index 162df9fc..f5aa37a1 100644 --- a/gosl/gotosl/config.go +++ b/gosl/gotosl/config.go @@ -41,6 +41,12 @@ type Config struct { // and must fit in a uint32 number. // The default is 32 byte aligned down version of 2147483647 max for nvidia MaxBufferSize uint32 `default:"2147483616"` + + // MaxStorageBuffersPerShaderStage is used to flag shaders that use more + // than this maximum number, which is the default max for web-based apps + // based on all the various backends. Specific backends may have more + // but using more will affect portability. + MaxStorageBuffersPerShaderStage int `default:"16"` } //cli:cmd -root diff --git a/gosl/gotosl/translate.go b/gosl/gotosl/translate.go index 44e87757..055c559c 100644 --- a/gosl/gotosl/translate.go +++ b/gosl/gotosl/translate.go @@ -137,8 +137,8 @@ func (st *State) TranslateDir(pf string) error { kn.Atomics, kn.VarsUsed, nvars = st.VarsUsed(st.KernelFuncs) maxVarsUsed = max(maxVarsUsed, nvars) fmt.Printf("###################################\nTranslating Kernel file: %s NVars: %d (atomic: %d)\n", kn.Name, nvars, len(kn.Atomics)) - if nvars > 10 { // todo: change when limit is raised to 16 - fmt.Println("WARNING: NVars exceeds maxStorageBuffersPerShaderStage min of 10") + if nvars > st.Config.MaxStorageBuffersPerShaderStage { + fmt.Println("WARNING: NVars exceeds maxStorageBuffersPerShaderStage min of:", st.Config.MaxStorageBuffersPerShaderStage) nOverBase++ } hdr := st.GenKernelHeader(sy, kn) @@ -193,7 +193,7 @@ func (st *State) TranslateDir(pf string) error { } fmt.Println("\n###################################\nMaximum number of variables used per shader:", maxVarsUsed) if nOverBase > 0 { - fmt.Printf("WARNING: %d shaders exceed maxStorageBuffersPerShaderStage min of 10\n", nOverBase) + fmt.Printf("WARNING: %d shaders exceed maxStorageBuffersPerShaderStage min of: %d\n", nOverBase, st.Config.MaxStorageBuffersPerShaderStage) } //////// check types diff --git a/gosl/gotosl/typegen.go b/gosl/gotosl/typegen.go index 56094949..c9d39244 100644 --- a/gosl/gotosl/typegen.go +++ b/gosl/gotosl/typegen.go @@ -8,7 +8,7 @@ import ( var _ = types.AddType(&types.Type{Name: "cogentcore.org/lab/gosl/gotosl.Function", IDName: "function", Doc: "Function represents the call graph of functions", Fields: []types.Field{{Name: "Name"}, {Name: "Funcs"}, {Name: "Atomics"}, {Name: "VarsUsed"}}}) -var _ = types.AddType(&types.Type{Name: "cogentcore.org/lab/gosl/gotosl.Config", IDName: "config", Doc: "Config has the configuration info for the gosl system.", Fields: []types.Field{{Name: "Output", Doc: "Output is the output directory for shader code,\nrelative to where gosl is invoked; must not be an empty string."}, {Name: "Exclude", Doc: "Exclude is a comma-separated list of names of functions to exclude from exporting to WGSL."}, {Name: "Keep", Doc: "Keep keeps temporary converted versions of the source files, for debugging."}, {Name: "Debug", Doc: "Debug enables debugging messages while running."}, {Name: "MaxBufferSize", Doc: "MaxBufferSize is the maximum size for any buffer.\nThis is often platform-dependent, but is needed for\naccessing variables that have multiple buffers.\nIt is compiled into the kernel code as a constant,\nand must fit in a uint32 number.\nThe default is 32 byte aligned down version of 2147483647 max for nvidia"}}}) +var _ = types.AddType(&types.Type{Name: "cogentcore.org/lab/gosl/gotosl.Config", IDName: "config", Doc: "Config has the configuration info for the gosl system.", Fields: []types.Field{{Name: "Output", Doc: "Output is the output directory for shader code,\nrelative to where gosl is invoked; must not be an empty string."}, {Name: "Exclude", Doc: "Exclude is a comma-separated list of names of functions to exclude from exporting to WGSL."}, {Name: "Keep", Doc: "Keep keeps temporary converted versions of the source files, for debugging."}, {Name: "Debug", Doc: "Debug enables debugging messages while running."}, {Name: "MaxBufferSize", Doc: "MaxBufferSize is the maximum size for any buffer.\nThis is often platform-dependent, but is needed for\naccessing variables that have multiple buffers.\nIt is compiled into the kernel code as a constant,\nand must fit in a uint32 number.\nThe default is 32 byte aligned down version of 2147483647 max for nvidia"}, {Name: "MaxStorageBuffersPerShaderStage", Doc: "MaxStorageBuffersPerShaderStage is used to flag shaders that use more\nthan this maximum number, which is the default max for web-based apps\nbased on all the various backends. Specific backends may have more\nbut using more will affect portability."}}}) var _ = types.AddType(&types.Type{Name: "cogentcore.org/lab/gosl/gotosl.System", IDName: "system", Doc: "System represents a ComputeSystem, and its kernels and variables.", Fields: []types.Field{{Name: "Name"}, {Name: "Kernels", Doc: "Kernels are the kernels using this compute system."}, {Name: "Groups", Doc: "Groups are the variables for this compute system."}, {Name: "NTensors", Doc: "NTensors is the number of tensor vars."}}}) @@ -22,7 +22,7 @@ var _ = types.AddType(&types.Type{Name: "cogentcore.org/lab/gosl/gotosl.File", I var _ = types.AddType(&types.Type{Name: "cogentcore.org/lab/gosl/gotosl.GetGlobalVar", IDName: "get-global-var", Doc: "GetGlobalVar holds GetVar expression, to Set variable back when done.", Fields: []types.Field{{Name: "Var", Doc: "global variable"}, {Name: "TmpVar", Doc: "name of temporary variable"}, {Name: "IdxExpr", Doc: "index passed to the Get function"}, {Name: "ReadWrite", Doc: "rw override"}}}) -var _ = types.AddType(&types.Type{Name: "cogentcore.org/lab/gosl/gotosl.State", IDName: "state", Doc: "State holds the current Go -> WGSL processing state.", Fields: []types.Field{{Name: "Config", Doc: "Config options."}, {Name: "ImportsDir", Doc: "path to shaders/imports directory."}, {Name: "Package", Doc: "name of the package"}, {Name: "GoFiles", Doc: "GoFiles are all the files with gosl content in current directory."}, {Name: "GoVarsFiles", Doc: "GoVarsFiles are all the files with gosl:vars content in current directory.\nThese must be processed first! they are moved from GoFiles to here."}, {Name: "GoImports", Doc: "GoImports has all the imported files."}, {Name: "ImportPackages", Doc: "ImportPackages has short package names, to remove from go code\nso everything lives in same main package."}, {Name: "Systems", Doc: "Systems has the kernels and variables for each system.\nThere is an initial \"Default\" system when system is not specified."}, {Name: "GetFuncs", Doc: "GetFuncs is a map of GetVar, SetVar function names for global vars."}, {Name: "SLImportFiles", Doc: "SLImportFiles are all the extracted and translated WGSL files in shaders/imports,\nwhich are copied into the generated shader kernel files."}, {Name: "GPUFile", Doc: "generated Go GPU gosl.go file contents"}, {Name: "ExcludeMap", Doc: "ExcludeMap is the compiled map of functions to exclude in Go -> WGSL translation."}, {Name: "GetVarStack", Doc: "GetVarStack is a stack per function definition of GetVar variables\nthat need to be set at the end."}, {Name: "GetFuncGraph", Doc: "GetFuncGraph is true if getting the function graph (first pass)."}, {Name: "CurKernel", Doc: "CurKernel is the current Kernel for second pass processing."}, {Name: "KernelFuncs", Doc: "KernelFuncs are the list of functions to include for current kernel."}, {Name: "FuncGraph", Doc: "FuncGraph is the call graph of functions, for dead code elimination"}}}) +var _ = types.AddType(&types.Type{Name: "cogentcore.org/lab/gosl/gotosl.State", IDName: "state", Doc: "State holds the current Go -> WGSL processing state.", Fields: []types.Field{{Name: "Config", Doc: "Config options."}, {Name: "ImportsDir", Doc: "path to shaders/imports directory."}, {Name: "Package", Doc: "name of the package"}, {Name: "GoFiles", Doc: "GoFiles are all the files with gosl content in current directory."}, {Name: "GoVarsFiles", Doc: "GoVarsFiles are all the files with gosl:vars content in current directory.\nThese must be processed first! they are moved from GoFiles to here."}, {Name: "GoImports", Doc: "GoImports has all the imported files."}, {Name: "ImportPackages", Doc: "ImportPackages has short package names, to remove from go code\nso everything lives in same main package."}, {Name: "Systems", Doc: "Systems has the kernels and variables for each system.\nThere is an initial \"Default\" system when system is not specified."}, {Name: "GetFuncs", Doc: "GetFuncs is a map of GetVar, SetVar function names for global vars."}, {Name: "VarStructTypes", Doc: "VarStructTypes is a map of struct type names to vars that use them."}, {Name: "SLImportFiles", Doc: "SLImportFiles are all the extracted and translated WGSL files in shaders/imports,\nwhich are copied into the generated shader kernel files."}, {Name: "GPUFile", Doc: "generated Go GPU gosl.go file contents"}, {Name: "ExcludeMap", Doc: "ExcludeMap is the compiled map of functions to exclude in Go -> WGSL translation."}, {Name: "GetVarStack", Doc: "GetVarStack is a stack per function definition of GetVar variables\nthat need to be set at the end."}, {Name: "GetFuncGraph", Doc: "GetFuncGraph is true if getting the function graph (first pass)."}, {Name: "CurKernel", Doc: "CurKernel is the current Kernel for second pass processing."}, {Name: "KernelFuncs", Doc: "KernelFuncs are the list of functions to include for current kernel."}, {Name: "FuncGraph", Doc: "FuncGraph is the call graph of functions, for dead code elimination"}}}) var _ = types.AddType(&types.Type{Name: "cogentcore.org/lab/gosl/gotosl.exprListMode", IDName: "expr-list-mode"}) @@ -110,6 +110,8 @@ var _ = types.AddFunc(&types.Func{Name: "cogentcore.org/lab/gosl/gotosl.fieldByN var _ = types.AddFunc(&types.Func{Name: "cogentcore.org/lab/gosl/gotosl.getLocalTypeName", Args: []string{"typ"}, Returns: []string{"string"}}) +var _ = types.AddFunc(&types.Func{Name: "cogentcore.org/lab/gosl/gotosl.typeIsInvalid", Args: []string{"typ"}, Returns: []string{"bool"}}) + var _ = types.AddFunc(&types.Func{Name: "cogentcore.org/lab/gosl/gotosl.isTypeName", Args: []string{"x"}, Returns: []string{"bool"}}) var _ = types.AddFunc(&types.Func{Name: "cogentcore.org/lab/gosl/gotosl.stripParens", Args: []string{"x"}, Returns: []string{"Expr"}}) From 07f9ff56f7651129b861cfa90dd52c57aefd9183 Mon Sep 17 00:00:00 2001 From: "Randall C. O'Reilly" Date: Tue, 12 May 2026 00:20:53 +0200 Subject: [PATCH 6/8] plotminmax: update to latest core mod --- go.mod | 7 ++++--- go.sum | 12 ++++++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 423f19eb..48afdc45 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ go 1.25.6 // https://github.com/googleapis/go-genproto/issues/1015 require ( - cogentcore.org/core v0.3.26-0.20260510231010-7a87368671eb + cogentcore.org/core v0.3.26 github.com/cogentcore/readline v0.1.3 github.com/cogentcore/yaegi v0.0.0-20260116172027-700fbf8949f3 github.com/mitchellh/go-homedir v1.1.0 @@ -54,7 +54,7 @@ require ( github.com/mattn/go-runewidth v0.0.15 // indirect github.com/mattn/go-shellwords v1.0.12 // indirect github.com/muesli/termenv v0.16.0 // indirect - github.com/oliverbestmann/webgpu v1.33.0 // indirect + github.com/oliverbestmann/webgpu v1.33.2 // indirect github.com/oliverbestmann/webgpu/libs-android v0.0.0-20260509160813-48db59792a15 // indirect github.com/oliverbestmann/webgpu/libs-darwin v0.0.0-20260509160802-b09403b07cd3 // indirect github.com/oliverbestmann/webgpu/libs-ios v0.0.0-20260509160803-765e39d2a48b // indirect @@ -71,7 +71,8 @@ require ( golang.org/x/sync v0.20.0 // indirect golang.org/x/sys v0.42.0 // indirect golang.org/x/text v0.36.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 // indirect + google.golang.org/genproto v0.0.0-20260511170946-3700d4141b60 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260504160031-60b97b32f348 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect modernc.org/knuth v0.5.4 // indirect modernc.org/token v1.1.0 // indirect diff --git a/go.sum b/go.sum index f1c8c5df..680d18bb 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ codeberg.org/go-pdf/fpdf v0.11.0 h1:n3I8WISQ1cr0S2rvx9DOlE/GypbcimMWqLpel3slHmY= codeberg.org/go-pdf/fpdf v0.11.0/go.mod h1:Y0DGRAdZ0OmnZPvjbMp/1bYxmIPxm0ws4tfoPOc4LjU= -cogentcore.org/core v0.3.26-0.20260510231010-7a87368671eb h1:VOuJQEOc9XKhmnu33bL90WWujasVbLUxGjf5bTimoDs= -cogentcore.org/core v0.3.26-0.20260510231010-7a87368671eb/go.mod h1:6h+YTWqpJSbewcM17zvj2FijuvkA+Yr55SNQbFIoGGM= +cogentcore.org/core v0.3.26 h1:KaMYB39EAe5rrzmOUQcSVRg0GXPo20cVOL30OgYW5Ow= +cogentcore.org/core v0.3.26/go.mod h1:WSfT4hTHjRHHVkaht8Xix1JRbzvojBfU6kGu9eplZXw= git.sr.ht/~sbinet/cmpimg v0.1.0 h1:E0zPRk2muWuCqSKSVZIWsgtU9pjsw3eKHi8VmQeScxo= git.sr.ht/~sbinet/cmpimg v0.1.0/go.mod h1:FU12psLbF4TfNXkKH2ZZQ29crIqoiqTZmeQ7dkp/pxE= github.com/Bios-Marcel/wastebasket/v2 v2.0.3 h1:TkoDPcSqluhLGE+EssHu7UGmLgUEkWg7kNyHyyJ3Q9g= @@ -101,8 +101,8 @@ github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= github.com/nsf/termbox-go v1.1.1 h1:nksUPLCb73Q++DwbYUBEglYBRPZyoXJdrj5L+TkjyZY= github.com/nsf/termbox-go v1.1.1/go.mod h1:T0cTdVuOwf7pHQNtfhnEbzHbcNyCEcVU4YPpouCbVxo= -github.com/oliverbestmann/webgpu v1.33.0 h1:Nr0IYIApoELWwDrF42nlEmgnuI0F517J4kbWPK9ZNIM= -github.com/oliverbestmann/webgpu v1.33.0/go.mod h1:0UEcoJ8VnwnAqo3JfzdFptplxtjhaQasc3n/nYZOrPA= +github.com/oliverbestmann/webgpu v1.33.2 h1:uDs3Fx4uAiUs8E4QytblofDpLtqBRGX3pfnLZzlhWGY= +github.com/oliverbestmann/webgpu v1.33.2/go.mod h1:0UEcoJ8VnwnAqo3JfzdFptplxtjhaQasc3n/nYZOrPA= github.com/oliverbestmann/webgpu/libs-android v0.0.0-20260509160813-48db59792a15 h1:HPxVSV8C8JaxGfa9hjDhzNmryoqPF3EwESBTFWpxNBo= github.com/oliverbestmann/webgpu/libs-android v0.0.0-20260509160813-48db59792a15/go.mod h1:tczQXCdsoFy+FTJVsZSve/vF8cmWEkxhvjcyY2Rujp8= github.com/oliverbestmann/webgpu/libs-darwin v0.0.0-20260509160802-b09403b07cd3 h1:NbBG2+pwqKcNfKUKtjWOj+02RkXSUWVkxY3hqzgyjSA= @@ -177,8 +177,12 @@ golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= +google.golang.org/genproto v0.0.0-20260511170946-3700d4141b60 h1:rhBdfmsOlOZIvz3Y5/BdUzPg2CkO8L7QQPKj96B8554= +google.golang.org/genproto v0.0.0-20260511170946-3700d4141b60/go.mod h1:8xo2Pj1b20ZOCpzlU3B9qieMwVIAXx1QVZWLMlPL6sM= google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 h1:RmoJA1ujG+/lRGNfUnOMfhCy5EipVMyvUE+KNbPbTlw= google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260504160031-60b97b32f348 h1:pfIbyB44sWzHiCpRqIen67ZQnVXSfIxWrqUMk1qwODE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260504160031-60b97b32f348/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM= google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= From f3a74b30c682245c7f439e951d0c4c3562f1cd69 Mon Sep 17 00:00:00 2001 From: "Randall C. O'Reilly" Date: Thu, 14 May 2026 13:52:43 +0200 Subject: [PATCH 7/8] plotminmax: update to latest core --- go.mod | 9 ++------- go.sum | 20 ++++---------------- 2 files changed, 6 insertions(+), 23 deletions(-) diff --git a/go.mod b/go.mod index 48afdc45..99067ab8 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ go 1.25.6 // https://github.com/googleapis/go-genproto/issues/1015 require ( - cogentcore.org/core v0.3.26 + cogentcore.org/core v0.3.28 github.com/cogentcore/readline v0.1.3 github.com/cogentcore/yaegi v0.0.0-20260116172027-700fbf8949f3 github.com/mitchellh/go-homedir v1.1.0 @@ -32,6 +32,7 @@ require ( github.com/aymerick/douceur v0.2.0 // indirect github.com/bramvdbogaerde/go-scp v1.6.0 // indirect github.com/chewxy/math32 v1.11.1 // indirect + github.com/cogentcore/webgpu v0.23.1-0.20260410073005-a2ae7d757168 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dlclark/regexp2 v1.11.5 // indirect github.com/ericchiang/css v1.4.0 // indirect @@ -54,12 +55,6 @@ require ( github.com/mattn/go-runewidth v0.0.15 // indirect github.com/mattn/go-shellwords v1.0.12 // indirect github.com/muesli/termenv v0.16.0 // indirect - github.com/oliverbestmann/webgpu v1.33.2 // indirect - github.com/oliverbestmann/webgpu/libs-android v0.0.0-20260509160813-48db59792a15 // indirect - github.com/oliverbestmann/webgpu/libs-darwin v0.0.0-20260509160802-b09403b07cd3 // indirect - github.com/oliverbestmann/webgpu/libs-ios v0.0.0-20260509160803-765e39d2a48b // indirect - github.com/oliverbestmann/webgpu/libs-linux v0.0.0-20260509160809-2fefaf7c9ead // indirect - github.com/oliverbestmann/webgpu/libs-windows v0.0.0-20260509160807-0bc32b12c7bc // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/rivo/uniseg v0.4.7 // indirect diff --git a/go.sum b/go.sum index 680d18bb..585974f6 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ codeberg.org/go-pdf/fpdf v0.11.0 h1:n3I8WISQ1cr0S2rvx9DOlE/GypbcimMWqLpel3slHmY= codeberg.org/go-pdf/fpdf v0.11.0/go.mod h1:Y0DGRAdZ0OmnZPvjbMp/1bYxmIPxm0ws4tfoPOc4LjU= -cogentcore.org/core v0.3.26 h1:KaMYB39EAe5rrzmOUQcSVRg0GXPo20cVOL30OgYW5Ow= -cogentcore.org/core v0.3.26/go.mod h1:WSfT4hTHjRHHVkaht8Xix1JRbzvojBfU6kGu9eplZXw= +cogentcore.org/core v0.3.28 h1:4sE28se7PLtDrYESg9W1hirOYY9Pddkle0cLxCLPZyw= +cogentcore.org/core v0.3.28/go.mod h1:IuX9mO4iQAMACI3yJbRfPmCN+PM+Z+mbJrFXa9fc7sg= git.sr.ht/~sbinet/cmpimg v0.1.0 h1:E0zPRk2muWuCqSKSVZIWsgtU9pjsw3eKHi8VmQeScxo= git.sr.ht/~sbinet/cmpimg v0.1.0/go.mod h1:FU12psLbF4TfNXkKH2ZZQ29crIqoiqTZmeQ7dkp/pxE= github.com/Bios-Marcel/wastebasket/v2 v2.0.3 h1:TkoDPcSqluhLGE+EssHu7UGmLgUEkWg7kNyHyyJ3Q9g= @@ -30,6 +30,8 @@ github.com/chewxy/math32 v1.11.1 h1:b7PGHlp8KjylDoU8RrcEsRuGZhJuz8haxnKfuMMRqy8= github.com/chewxy/math32 v1.11.1/go.mod h1:dOB2rcuFrCn6UHrze36WSLVPKtzPMRAQvBvUwkSsLqs= github.com/cogentcore/readline v0.1.3 h1:tYmjP3XHvsGwhsDLkAp+vBhkERmLFENZfftyPOR/PBE= github.com/cogentcore/readline v0.1.3/go.mod h1:IHVtJHSKXspK7CMg3OC/bbPEXxO++dFlug/vsPktvas= +github.com/cogentcore/webgpu v0.23.1-0.20260410073005-a2ae7d757168 h1:K5en4IrBrolIAWvjrLuXRb9CvU1w+WMMi0Eu0KmcMfQ= +github.com/cogentcore/webgpu v0.23.1-0.20260410073005-a2ae7d757168/go.mod h1:DQLhF8pM/WkdaGpX6pKmZJPYsoR9x+hohhA1nnNuCa8= github.com/cogentcore/yaegi v0.0.0-20260116172027-700fbf8949f3 h1:y3Djpt/g3QTjFdj8cpvy/r8FsZsEa7PqHGjgsKXbta0= github.com/cogentcore/yaegi v0.0.0-20260116172027-700fbf8949f3/go.mod h1:XkOm++pRmWlk85p+hw71ZItfTeRdzqG23+2xjP9eb+M= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -101,18 +103,6 @@ github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= github.com/nsf/termbox-go v1.1.1 h1:nksUPLCb73Q++DwbYUBEglYBRPZyoXJdrj5L+TkjyZY= github.com/nsf/termbox-go v1.1.1/go.mod h1:T0cTdVuOwf7pHQNtfhnEbzHbcNyCEcVU4YPpouCbVxo= -github.com/oliverbestmann/webgpu v1.33.2 h1:uDs3Fx4uAiUs8E4QytblofDpLtqBRGX3pfnLZzlhWGY= -github.com/oliverbestmann/webgpu v1.33.2/go.mod h1:0UEcoJ8VnwnAqo3JfzdFptplxtjhaQasc3n/nYZOrPA= -github.com/oliverbestmann/webgpu/libs-android v0.0.0-20260509160813-48db59792a15 h1:HPxVSV8C8JaxGfa9hjDhzNmryoqPF3EwESBTFWpxNBo= -github.com/oliverbestmann/webgpu/libs-android v0.0.0-20260509160813-48db59792a15/go.mod h1:tczQXCdsoFy+FTJVsZSve/vF8cmWEkxhvjcyY2Rujp8= -github.com/oliverbestmann/webgpu/libs-darwin v0.0.0-20260509160802-b09403b07cd3 h1:NbBG2+pwqKcNfKUKtjWOj+02RkXSUWVkxY3hqzgyjSA= -github.com/oliverbestmann/webgpu/libs-darwin v0.0.0-20260509160802-b09403b07cd3/go.mod h1:XoHM/ZcjQqJQyEfQjU0ScDkxvQRWfZLxKP8IrEz4xyo= -github.com/oliverbestmann/webgpu/libs-ios v0.0.0-20260509160803-765e39d2a48b h1:j+uRWcmAl3Y4RPJ4rmxnc1DRHgZ6VNywZPsRHUEuD0M= -github.com/oliverbestmann/webgpu/libs-ios v0.0.0-20260509160803-765e39d2a48b/go.mod h1:IV+TkwmPA0yMzZZoz0Aj4X+22WLEQq2TOyN4/0k8lgs= -github.com/oliverbestmann/webgpu/libs-linux v0.0.0-20260509160809-2fefaf7c9ead h1:kkY04PFBq6I58BwK5cwJ3LRp+xy7Y5/jrkLHBdcBL68= -github.com/oliverbestmann/webgpu/libs-linux v0.0.0-20260509160809-2fefaf7c9ead/go.mod h1:SOeo2YWe2UxWxOeAHyZtwaSXkBbP78cGnm7I+6lIWV0= -github.com/oliverbestmann/webgpu/libs-windows v0.0.0-20260509160807-0bc32b12c7bc h1:YVCfgeByW1ibKniigozHCwF2wC26TDmAIJwQG40bCBM= -github.com/oliverbestmann/webgpu/libs-windows v0.0.0-20260509160807-0bc32b12c7bc/go.mod h1:58qRJHG2+mjEu/AKJFh026bz3xE1zEHYt41i4TBM8NE= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -179,8 +169,6 @@ gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= google.golang.org/genproto v0.0.0-20260511170946-3700d4141b60 h1:rhBdfmsOlOZIvz3Y5/BdUzPg2CkO8L7QQPKj96B8554= google.golang.org/genproto v0.0.0-20260511170946-3700d4141b60/go.mod h1:8xo2Pj1b20ZOCpzlU3B9qieMwVIAXx1QVZWLMlPL6sM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 h1:RmoJA1ujG+/lRGNfUnOMfhCy5EipVMyvUE+KNbPbTlw= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/genproto/googleapis/rpc v0.0.0-20260504160031-60b97b32f348 h1:pfIbyB44sWzHiCpRqIen67ZQnVXSfIxWrqUMk1qwODE= google.golang.org/genproto/googleapis/rpc v0.0.0-20260504160031-60b97b32f348/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM= From c2bd7d6fa07eb0d552a1cabf04b641fb4deb4b49 Mon Sep 17 00:00:00 2001 From: "Randall C. O'Reilly" Date: Thu, 14 May 2026 14:42:27 +0200 Subject: [PATCH 8/8] plotminmax: revert to Stretch as the default for OutOfRange, as it is more robust to approximate but slightly incorrect default range parameters, and people who want more control can exert it as needed. also use more logical ordering of rest of options. --- plot/enumgen.go | 6 +++--- plot/plot.go | 2 +- plot/style.go | 12 ++++++------ plot/typegen.go | 11 ++++++++--- 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/plot/enumgen.go b/plot/enumgen.go index 7bd1ebdf..c1a3b732 100644 --- a/plot/enumgen.go +++ b/plot/enumgen.go @@ -216,11 +216,11 @@ var _OutOfRangeValues = []OutOfRange{0, 1, 2, 3} // OutOfRangeN is the highest valid value for type OutOfRange, plus one. const OutOfRangeN OutOfRange = 4 -var _OutOfRangeValueMap = map[string]OutOfRange{`BreakMark`: 0, `Mark`: 1, `Break`: 2, `Stretch`: 3} +var _OutOfRangeValueMap = map[string]OutOfRange{`Stretch`: 0, `Mark`: 1, `Break`: 2, `BreakMark`: 3} -var _OutOfRangeDescMap = map[OutOfRange]string{0: `BreakMark breaks any continuous line elements and renders a marker for out-of-range values`, 1: `Mark renders a marker for out-of-range values, but does not break continuous line elements.`, 2: `Break breaks any continuous line elements, but does not render a marker, for out-of-range values.`, 3: `Stretch stretches the range to include all values, avoiding the problem of out-of-range values entirely.`} +var _OutOfRangeDescMap = map[OutOfRange]string{0: `Stretch stretches the range to include all values, avoiding the problem of out-of-range values entirely.`, 1: `Mark renders a marker for out-of-range values, but does not break continuous line elements.`, 2: `Break breaks any continuous line elements, but does not render a marker, for out-of-range values.`, 3: `BreakMark breaks any continuous line elements and renders a marker for out-of-range values`} -var _OutOfRangeMap = map[OutOfRange]string{0: `BreakMark`, 1: `Mark`, 2: `Break`, 3: `Stretch`} +var _OutOfRangeMap = map[OutOfRange]string{0: `Stretch`, 1: `Mark`, 2: `Break`, 3: `BreakMark`} // String returns the string representation of this OutOfRange value. func (i OutOfRange) String() string { return enums.String(i, _OutOfRangeMap) } diff --git a/plot/plot.go b/plot/plot.go index 7ae7d742..d1cd4b62 100644 --- a/plot/plot.go +++ b/plot/plot.go @@ -135,7 +135,7 @@ func (ps *PlotStyle) Defaults() { ps.TitleStyle.Size.Dp(24) ps.Background = colors.Scheme.Surface ps.Scale = 1 - ps.OutOfRange = BreakMark + ps.OutOfRange = Stretch ps.Legend.Defaults() ps.Axis.Defaults() ps.LineWidth.Pt(1) diff --git a/plot/style.go b/plot/style.go index 6ecb028f..751183aa 100644 --- a/plot/style.go +++ b/plot/style.go @@ -250,9 +250,9 @@ const ( type OutOfRange int32 //enums:enum const ( - // BreakMark breaks any continuous line elements and renders a marker - // for out-of-range values - BreakMark OutOfRange = iota + // Stretch stretches the range to include all values, + // avoiding the problem of out-of-range values entirely. + Stretch OutOfRange = iota // Mark renders a marker for out-of-range values, but does not break // continuous line elements. @@ -262,9 +262,9 @@ const ( // a marker, for out-of-range values. Break - // Stretch stretches the range to include all values, - // avoiding the problem of out-of-range values entirely. - Stretch + // BreakMark breaks any continuous line elements and renders a marker + // for out-of-range values + BreakMark ) func (or OutOfRange) HasMark() bool { diff --git a/plot/typegen.go b/plot/typegen.go index 9ddda05b..73f515e4 100644 --- a/plot/typegen.go +++ b/plot/typegen.go @@ -57,7 +57,7 @@ func (t *AxisStyle) SetTickLine(v LineStyle) *AxisStyle { t.TickLine = v; return // TickLength is the length of tick lines. func (t *AxisStyle) SetTickLength(v units.Value) *AxisStyle { t.TickLength = v; return t } -var _ = types.AddType(&types.Type{Name: "cogentcore.org/lab/plot.Axis", IDName: "axis", Doc: "Axis represents either a horizontal or vertical axis of a plot.\nThis is the \"internal\" data structure and should not be used for styling.", Fields: []types.Field{{Name: "Range", Doc: "Range has the Min, Max range of values for the axis (in raw data units.)"}, {Name: "Axis", Doc: "specifies which axis this is: X, Y or Z."}, {Name: "RightY", Doc: "For a Y axis, this puts the axis on the right (i.e., the second Y axis)."}, {Name: "Label", Doc: "Label for the axis."}, {Name: "Style", Doc: "Style has the style parameters for the Axis,\ncopied from [PlotStyle] source."}, {Name: "TickText", Doc: "TickText is used for rendering the tick text labels."}, {Name: "Ticker", Doc: "Ticker generates the tick marks. Any tick marks\nreturned by the Marker function that are not in\nrange of the axis are not drawn."}, {Name: "Scale", Doc: "Scale transforms a value given in the data coordinate system\nto the normalized coordinate system of the axis—its distance\nalong the axis as a fraction of the axis range."}, {Name: "AutoRescale", Doc: "AutoRescale enables an axis to automatically adapt its minimum\nand maximum boundaries, according to its underlying Ticker."}, {Name: "ticks", Doc: "cached list of ticks, set in size"}}}) +var _ = types.AddType(&types.Type{Name: "cogentcore.org/lab/plot.Axis", IDName: "axis", Doc: "Axis represents either a horizontal or vertical axis of a plot.\nThis is the \"internal\" data structure and should not be used for styling.", Fields: []types.Field{{Name: "Range", Doc: "Range has the full Min, Max range of values for the axis\n(in raw data units). This includes extra space needed for plotting."}, {Name: "DataRange", Doc: "DataRange has the Min, Max range for the actual data values\nfor the axis (in raw data units), *exclusive* of extra plotting space.\nThis is used for OutOfRange clipping."}, {Name: "Axis", Doc: "specifies which axis this is: X, Y or Z."}, {Name: "RightY", Doc: "For a Y axis, this puts the axis on the right (i.e., the second Y axis)."}, {Name: "Label", Doc: "Label for the axis."}, {Name: "Style", Doc: "Style has the style parameters for the Axis,\ncopied from [PlotStyle] source."}, {Name: "TickText", Doc: "TickText is used for rendering the tick text labels."}, {Name: "Ticker", Doc: "Ticker generates the tick marks. Any tick marks\nreturned by the Marker function that are not in\nrange of the axis are not drawn."}, {Name: "Scale", Doc: "Scale transforms a value given in the data coordinate system\nto the normalized coordinate system of the axis—its distance\nalong the axis as a fraction of the axis range."}, {Name: "AutoRescale", Doc: "AutoRescale enables an axis to automatically adapt its minimum\nand maximum boundaries, according to its underlying Ticker."}, {Name: "ticks", Doc: "cached list of ticks, set in size"}}}) var _ = types.AddType(&types.Type{Name: "cogentcore.org/lab/plot.Normalizer", IDName: "normalizer", Doc: "Normalizer rescales values from the data coordinate system to the\nnormalized coordinate system.", Methods: []types.Method{{Name: "Normalize", Doc: "Normalize transforms a value x in the data coordinate system to\nthe normalized coordinate system.", Args: []string{"min", "max", "x"}, Returns: []string{"float64"}}}}) @@ -275,7 +275,7 @@ var _ = types.AddType(&types.Type{Name: "cogentcore.org/lab/plot.PanZoom", IDNam var _ = types.AddType(&types.Type{Name: "cogentcore.org/lab/plot.Plot", IDName: "plot", Doc: "Plot is the basic type representing a plot.\nIt renders into its own image.RGBA Pixels image,\nand can also save a corresponding SVG version.", Fields: []types.Field{{Name: "Title", Doc: "Title of the plot"}, {Name: "Style", Doc: "Style has the styling properties for the plot.\nAll end-user configuration should be put in here,\nrather than modifying other fields directly on the plot."}, {Name: "StandardTextStyle", Doc: "standard text style with default options"}, {Name: "X", Doc: "X, Y, YR, and Z are the horizontal, vertical, right vertical, and depth axes\nof the plot respectively. These are the actual compiled\nstate data and should not be used for styling: use Style."}, {Name: "Y", Doc: "X, Y, YR, and Z are the horizontal, vertical, right vertical, and depth axes\nof the plot respectively. These are the actual compiled\nstate data and should not be used for styling: use Style."}, {Name: "YR", Doc: "X, Y, YR, and Z are the horizontal, vertical, right vertical, and depth axes\nof the plot respectively. These are the actual compiled\nstate data and should not be used for styling: use Style."}, {Name: "Z", Doc: "X, Y, YR, and Z are the horizontal, vertical, right vertical, and depth axes\nof the plot respectively. These are the actual compiled\nstate data and should not be used for styling: use Style."}, {Name: "SizeAxis", Doc: "SizeAxis is a virtual axis for the Size data role."}, {Name: "Legend", Doc: "Legend is the plot's legend."}, {Name: "Plotters", Doc: "Plotters are drawn by calling their Plot method after the axes are drawn."}, {Name: "PanZoom", Doc: "PanZoom provides post-styling pan and zoom range factors."}, {Name: "HighlightPlotter", Doc: "HighlightPlotter is the Plotter to highlight. Used for mouse hovering for example.\nIt is the responsibility of the Plotter Plot function to implement highlighting."}, {Name: "HighlightIndex", Doc: "HighlightIndex is the index of the data point to highlight, for HighlightPlotter."}, {Name: "TextShaper", Doc: "TextShaper for shaping text. Can set to a shared external one,\nor else the shared plotShaper is used under a mutex lock during Render."}, {Name: "PaintBox", Doc: "PaintBox is the bounding box for the plot within the Paint.\nFor standalone, it is the size of the image."}, {Name: "PlotBox", Doc: "Current local plot bounding box in image coordinates, for computing\nplotting coordinates."}, {Name: "Painter", Doc: "Painter is the current painter being used,\nwhich is only valid during rendering, and is set by Draw function.\nIt needs to be exported for different plot types in other packages."}, {Name: "unitContext", Doc: "unitContext is current unit context, only valid during rendering."}}}) -var _ = types.AddType(&types.Type{Name: "cogentcore.org/lab/plot.Plotter", IDName: "plotter", Doc: "Plotter is an interface that wraps the Plot method.\nStandard implementations of Plotter are in the [plots] package.", Methods: []types.Method{{Name: "Plot", Doc: "Plot draws the data to the Plot Paint.", Args: []string{"pt"}}, {Name: "UpdateRange", Doc: "UpdateRange updates the given ranges.", Args: []string{"plt", "x", "y", "yr", "z", "size"}}, {Name: "Data", Doc: "Data returns the data by roles for this plot, for both the original\ndata and the pixel-transformed X,Y coordinates for that data.\nThis allows a GUI interface to inspect data etc.", Returns: []string{"data", "pixX", "pixY"}}, {Name: "Stylers", Doc: "Stylers returns the styler functions for this element.", Returns: []string{"Stylers"}}, {Name: "ApplyStyle", Doc: "ApplyStyle applies any stylers to this element,\nfirst initializing from the given global plot style, which has\nalready been styled with defaults and all the plot element stylers.", Args: []string{"plotStyle", "idx"}}}}) +var _ = types.AddType(&types.Type{Name: "cogentcore.org/lab/plot.Plotter", IDName: "plotter", Doc: "Plotter is an interface that wraps the Plot method.\nStandard implementations of Plotter are in the [plots] package.", Methods: []types.Method{{Name: "Plot", Doc: "Plot draws the data to the Plot Paint.", Args: []string{"pt"}}, {Name: "UpdateRange", Doc: "UpdateRange updates the given ranges.", Args: []string{"plt"}}, {Name: "Data", Doc: "Data returns the data by roles for this plot, for both the original\ndata and the pixel-transformed X,Y coordinates for that data.\nThis allows a GUI interface to inspect data etc.", Returns: []string{"data", "pixX", "pixY"}}, {Name: "Stylers", Doc: "Stylers returns the styler functions for this element.", Returns: []string{"Stylers"}}, {Name: "ApplyStyle", Doc: "ApplyStyle applies any stylers to this element,\nfirst initializing from the given global plot style, which has\nalready been styled with defaults and all the plot element stylers.", Args: []string{"plotStyle", "idx"}}}}) var _ = types.AddType(&types.Type{Name: "cogentcore.org/lab/plot.PlotterType", IDName: "plotter-type", Doc: "PlotterType registers a Plotter so that it can be created with appropriate data.", Fields: []types.Field{{Name: "Name", Doc: "Name of the plot type."}, {Name: "Doc", Doc: "Doc is the documentation for this Plotter."}, {Name: "Required", Doc: "Required Data roles for this plot. Data for these Roles must be provided."}, {Name: "Optional", Doc: "Optional Data roles for this plot."}, {Name: "New", Doc: "New returns a new plotter of this type with given data in given roles."}}}) @@ -323,7 +323,7 @@ func (t *PointStyle) SetSize(v units.Value) *PointStyle { t.Size = v; return t } var _ = types.AddType(&types.Type{Name: "cogentcore.org/lab/plot.Shapes", IDName: "shapes", Doc: "Shapes has the options for how to draw points in the plot."}) -var _ = types.AddType(&types.Type{Name: "cogentcore.org/lab/plot.Style", IDName: "style", Doc: "Style contains the plot styling properties relevant across\nmost plot types. These properties apply to individual plot elements\nwhile the Plot properties applies to the overall plot itself.", Directives: []types.Directive{{Tool: "types", Directive: "add", Args: []string{"-setters"}}}, Fields: []types.Field{{Name: "Plot", Doc: "Plot has overall plot-level properties, which can be set by any\nplot element, and are updated first, before applying element-wise styles."}, {Name: "On", Doc: "On specifies whether to plot this item, for table-based plots."}, {Name: "Plotter", Doc: "Plotter is the type of plotter to use in plotting this data,\nfor [plot.NewTablePlot] [table.Table] driven plots.\nBlank means use default ([plots.XY] is overall default)."}, {Name: "Role", Doc: "Role specifies how a particular column of data should be used,\nfor [plot.NewTablePlot] [table.Table] driven plots."}, {Name: "Group", Doc: "Group specifies a group of related data items,\nfor [plot.NewTablePlot] [table.Table] driven plots,\nwhere different columns of data within the same Group play different Roles."}, {Name: "Range", Doc: "Range is the effective range of data to plot, where either end can be fixed."}, {Name: "Label", Doc: "Label provides an alternative label to use for axis, if set."}, {Name: "NoLegend", Doc: "NoLegend excludes this item from the legend when it otherwise would be included,\nfor [plot.NewTablePlot] [table.Table] driven plots.\nRole = Y values are included in the Legend by default."}, {Name: "RightY", Doc: "RightY specifies that this should use the right-side alternate Y axis."}, {Name: "NTicks", Doc: "NTicks sets the desired number of ticks for the axis, if > 0."}, {Name: "LabelSkip", Doc: "LabelSkip is the number of data points to skip between Labels.\n0 means plot the Label at every point."}, {Name: "Line", Doc: "Line has style properties for drawing lines."}, {Name: "Point", Doc: "Point has style properties for drawing points."}, {Name: "Text", Doc: "Text has style properties for rendering text."}, {Name: "Width", Doc: "Width has various plot width properties."}}}) +var _ = types.AddType(&types.Type{Name: "cogentcore.org/lab/plot.Style", IDName: "style", Doc: "Style contains the plot styling properties relevant across\nmost plot types. These properties apply to individual plot elements\nwhile the Plot properties applies to the overall plot itself.", Directives: []types.Directive{{Tool: "types", Directive: "add", Args: []string{"-setters"}}}, Fields: []types.Field{{Name: "Plot", Doc: "Plot has overall plot-level properties, which can be set by any\nplot element, and are updated first, before applying element-wise styles."}, {Name: "On", Doc: "On specifies whether to plot this item, for table-based plots."}, {Name: "Plotter", Doc: "Plotter is the type of plotter to use in plotting this data,\nfor [plot.NewTablePlot] [table.Table] driven plots.\nBlank means use default ([plots.XY] is overall default)."}, {Name: "Role", Doc: "Role specifies how a particular column of data should be used,\nfor [plot.NewTablePlot] [table.Table] driven plots."}, {Name: "Group", Doc: "Group specifies a group of related data items,\nfor [plot.NewTablePlot] [table.Table] driven plots,\nwhere different columns of data within the same Group play different Roles."}, {Name: "Range", Doc: "Range is the effective range of data to plot, where either end can be fixed.\nSee [OutofRange] for plotting behavior for data outside of fixed range."}, {Name: "Label", Doc: "Label provides an alternative label to use for axis, if set."}, {Name: "NoLegend", Doc: "NoLegend excludes this item from the legend when it otherwise would be included,\nfor [plot.NewTablePlot] [table.Table] driven plots.\nRole = Y values are included in the Legend by default."}, {Name: "RightY", Doc: "RightY specifies that this should use the right-side alternate Y axis."}, {Name: "NTicks", Doc: "NTicks sets the desired number of ticks for the axis, if > 0."}, {Name: "LabelSkip", Doc: "LabelSkip is the number of data points to skip between Labels.\n0 means plot the Label at every point."}, {Name: "Line", Doc: "Line has style properties for drawing lines."}, {Name: "Point", Doc: "Point has style properties for drawing points."}, {Name: "Text", Doc: "Text has style properties for rendering text."}, {Name: "Width", Doc: "Width has various plot width properties."}, {Name: "OutOfRangeMark", Doc: "OutOfRangeMark has style properties for drawing points when out of range."}}}) // SetPlot sets the [Style.Plot]: // Plot has overall plot-level properties, which can be set by any @@ -353,6 +353,7 @@ func (t *Style) SetGroup(v string) *Style { t.Group = v; return t } // SetRange sets the [Style.Range]: // Range is the effective range of data to plot, where either end can be fixed. +// See [OutofRange] for plotting behavior for data outside of fixed range. func (t *Style) SetRange(v minmax.Range64) *Style { t.Range = v; return t } // SetLabel sets the [Style.Label]: @@ -394,6 +395,10 @@ func (t *Style) SetText(v TextStyle) *Style { t.Text = v; return t } // Width has various plot width properties. func (t *Style) SetWidth(v WidthStyle) *Style { t.Width = v; return t } +// SetOutOfRangeMark sets the [Style.OutOfRangeMark]: +// OutOfRangeMark has style properties for drawing points when out of range. +func (t *Style) SetOutOfRangeMark(v PointStyle) *Style { t.OutOfRangeMark = v; return t } + var _ = types.AddType(&types.Type{Name: "cogentcore.org/lab/plot.WidthStyle", IDName: "width-style", Doc: "WidthStyle contains various plot width properties relevant across\ndifferent plot types.", Directives: []types.Directive{{Tool: "types", Directive: "add", Args: []string{"-setters"}}}, Fields: []types.Field{{Name: "Cap", Doc: "Cap is the width of the caps drawn at the top of error bars.\nThe default is 10dp"}, {Name: "Offset", Doc: "Offset for Bar plot is the offset added to each X axis value\nrelative to the Stride computed value (X = offset + index * Stride)\nDefaults to 0."}, {Name: "Stride", Doc: "Stride for Bar plot is distance between bars. Defaults to 1."}, {Name: "Width", Doc: "Width for Bar plot is the width of the bars, as a fraction of the Stride,\nto prevent bar overlap. Defaults to .8."}, {Name: "Pad", Doc: "Pad for Bar plot is additional space at start / end of data range,\nto keep bars from overflowing ends. This amount is subtracted from Offset\nand added to (len(Values)-1)*Stride -- no other accommodation for bar\nwidth is provided, so that should be built into this value as well.\nDefaults to 1."}}}) // SetCap sets the [WidthStyle.Cap]: