Follow figure's main branch: the charts it grew, and a fallback font - #6
Merged
Merged
Conversation
figure gained geom.Horizon, which folds a series into bands of equal height and names them with a colourbar rather than with an axis. The demo is where a new chart type has to appear or nobody sees it. One entry under Groups & stacking: six hours of feeder load, folded into 30 kW bands about the idle draw. The band height is pinned rather than cut from the data, which is the discipline the mark exists for — 30 kW means 30 kW in the next chart drawn this way. The strip is 220 pixels because that is where the form starts paying for itself against the line chart of the same series. Its id goes to the front of Newest, so the tree opens on it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HdSCXbhBhWBgUiCns9Abhf
geom.Horizon and Plot.Theme both landed in figure v0.11.0. With the require at v0.10.0 this repository builds only through go.work, which is why CI could not compile chart/chart.go: Plot.Theme did not exist in the core it resolved. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HdSCXbhBhWBgUiCns9Abhf
Interactive lets a reader hover, drag, zoom and click; it no longer floats a box over the marks as well. A chart that hands its hover to the application — a readout, a crosshair, a linked table — wants the pointer without one. Tooltip is now off by default and shows only on a chart that is both interactive and asked for one. Chart.SetTooltip and Chart.Tooltip switch and report it on a chart already on screen; the hover handlers are registered either way so it can be turned on later. The demo gets a Tooltips switch beside Interactive, on by default. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
figure's main branch has grown a raster mark, survival curves, trees, probability scales, an oblique coord with extruded marks, and the statistical instruments that are drawn with the marks that already exist. The demo is where a new chart type has to appear or nobody sees it, so each gets an entry: - bars-extruded: bars given a top and a side by coord.Oblique - weibull: failure times on Weibull paper, a complementary log-log axis - survival: Kaplan-Meier curves with their band, censor ticks and a numbers-at-risk track - roc: two classifiers and the area under each - correlogram: stat.ACF against the white-noise bound - spectrogram: a short-time Fourier transform drawn as one raster, resampled by Max so a one-millisecond click survives the downscale - dendrogram-heatmap: clustered samples, the tree in a track over the cells - radial-tree: a tidy tree bent round a polar coord - spc: an individuals chart with frozen limits and Nelson's run rules The ports follow figure's own examples. Their ids go to the front of Newest. These APIs are not in figure v0.11.0, which cmd/demo/go.mod requires, so the demo builds only through go.work until figure is released again. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
figure's PR #26 gave the three package a spherical scene and a scatter. The spherical scene is a coordinate system rather than a chart type, so the demo shows it three ways, each a port of figure's examples/sphere: - smith-sphere: the Smith chart on the Riemann sphere, where a negative resistance runs into the southern hemisphere instead of off the page - antenna-pattern: a broadside array's power pattern as a surface - bloch: a detuned Rabi oscillation as one closed curve and scatter3 is two batches that overlap on the floor and part only in the third column, with the droplines that make a floating point's height readable. The Bloch sphere's kets are written with ASCII brackets, as figure's example writes them: the chart's typeface has no ⟩. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
figure's backend/gg grew WithFallbackFont: fonts consulted, in order, for a rune the chart's own font has no glyph for, with a `?` written for a rune no face can draw at all. That closes the gap chart.ThemeFont has carried a warning about since it was written — Fyne's NotoSans-Regular has no ≤, ≥ or ∞, and a rasterizer handed one font drew nothing where the shaper Fyne draws its own text with would have fallen back. - fynefigure.FallbackFont is the new option, and Target.SetFont takes the fallbacks with the typeface so a chart that follows the application to a new font keeps them. The config holds the faces rather than the rasterizer's options, because SetFont used to rebuild that list and would now drop the fallback while replacing the font. - The chart widget passes look.Fallback() — the Go regular face, which is what every other figure raster is drawn in — whenever it follows the theme's typeface, and the tooltip beside it gets the same list. The test draws the same title as "????" and requires the two to differ: a question mark is ink, so counting ink no longer tells a drawn symbol from a lost one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
figure's main branch has grown a barycentric coord and the prism over it, a ribbon, a spherical histogram, an arc between two rows on a ball, an orientation for a mark, and an outline an extruded mark keeps. The demo is where a new chart type has to appear or nobody sees it, so each gets an entry or takes over one that was already there: - soil-texture: three parts of a mixture in a triangle, with the derived component named at its own corner because the third grid family has no labels yet. It opens the new Ternary group, beside Polar and Smith. - alloy-prism: the same triangle as a scene's floor with the melting point up the fourth axis, sampled over the whole simplex so the liquidus is a surface rather than the corner a real alloy catalogue would crowd into - ribbon: a descending approach as a band, which occludes and says which of two passes is in front - joint-orientations: two fracture sets over a scattered background, binned into cells of equal area — the chart a stereonet's contoured density is the flat form of - bloch: two dozen states rather than two hundred and forty, which is where the arc shows: a coarse sweep joined by chords would cut through the ball - dendrogram-heatmap: the gene tree in a left track, geom.Horizontal with geom.Baseline(1), so the record's headline chart is drawn whole - bars-extruded: a fill and a colour, which outlines all three faces data.go's clustering is now a function of the items and a distance, because the genes are clustered by the same code read the other way round, and its uniform deviate takes three rounds: two read side by side off one affine round walk in step, which put the histogram's background on a curve instead of over the ball. These APIs are not in figure v0.11.0, which cmd/demo/go.mod requires, so the demo still builds only through go.work until figure is released again. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The require directives name published tags, and the option the chart widget now passes is not in one yet. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
CI builds each module from its own go.mod, with no go.work, so a require that names a tag without the API the code calls is a red build rather than a note in a comment. Three modules were in that state: the widget calls gg.WithFallbackFont, the demo draws the chart types figure grew after v0.11.0, and the GPU tier calls Available, Disable and Enable, which backend/gg/gpu has never released because it is held out of releases while its replace is needed. So the requires name a commit of figure's main branch. A pseudo-version is what keeps a module buildable by anyone who fetches it before the next release, and each go.mod says why it is not a tag and when it goes back to being one. Verified with GOWORK=off in all three modules: build, vet, test and govulncheck, plus the no-cgo build of the library alone. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The tier's import moved behind !linux in "Give the demo the GPU tier where a
binary can hold it", because on linux/amd64 with cgo on — which Fyne's desktop
driver requires — its foreign-function layer does not link. Three files went on
importing it anyway, for Enabled, Available, Enable, Disable and Close, so the
Linux binary still carried it and still failed to link:
dlopen_stub: unhandled relocation for goffi_dlopen (SDYNIMPORT) (R_CALL)
CI never said so, because module resolution failed before the link did.
So the tier is reached through six functions, and the import lives in the one
file that is not built on Linux. tier_linux.go answers instead, with the
answers a machine with no usable device would give, and imports nothing — the
point is the import, not the return value. The panel says which of the two it
is: a build with no tier reads differently from a machine where no device
answered.
go mod tidy sees every platform, so the requirement on the tier stays.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…outine The race detector fails the demo's tests, and the CI job that would have said so never got past the build. The kitchen refreshes the panel's numbers from a ticker four times a second through fyne.Do. Under the desktop driver that puts the refresh on the goroutine the driver draws from; the test driver documents that it "ignores the wait flag as our threading is simple" and runs the function on whichever goroutine called it. So the ticker was a second goroutine in the widgets the test was driving, and the two met in the panel's labels. newKitchen takes the interval, and the test passes zero, which leaves the goroutine unstarted. The app passes panelRefresh and behaves as it did. The test refreshes what it reads, which it already did. Verified with `go test -race ./...` in all three modules. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… its new size (#7) * Ring a picked row only in the panel it was picked in figure numbers layers per panel, and a band beside the panel is a panel of its own holding its own layers. A selection made by a click names a layer and a row, and marks.locate asked every panel for that pair — so a row picked in a gantt strip under a curve was also ringed at layer 0, row n of the curve's panel and of every other band, which are different rows of different tables. With bands present, a ref this chart made is now located only in the panel it was picked in, and the key lookup reads the plot's layers for panel 0 alone: a band's layers are not reachable from here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Let a chart limit what a click can pick chart.SelectWhere takes a predicate over the hit. A click on a mark it turns down is a click on nothing and clears the selection. A caller could already clear an unwanted pick from its OnSelect handler, but only outside the chart's lock, which is a frame later — and for that frame the ring is drawn round a row the reader was never meant to pick. Deciding before the selection is installed leaves nothing to flash. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Forget what the painter asked of a size the chart no longer has The painter rounds a raster's pixels and the chart truncates its size, so at any fractional width the painter asks for a pixel or so more than was drawn, and painterGeometry records it. Nothing reads that until the next checkScale, and the next one is often the resize — which divided the old size's pixels by the new width. After a jump as large as a maximize that read as a fraction of the real device pixel ratio, and the chart was rasterized at about the pixel count it had before and stretched. A drag moves a few pixels at a time, which is why it never showed there. A resize now drops the recorded geometry, in chart and in orbit alike. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Let a chart hold its view against the pointer chart.PanZoom(false) keeps drag, wheel and double click from moving the axes, and leaves the rest of the pointer alone: hover, the tooltip, a click that picks a row and a drag that selects all still work. SetPanZoom changes it on a chart already on screen. Interactive(false) was the only way to stop a pan, and it takes the tooltip and the click with it. A list of charts that the program holds on one time range wants those and must not let a reader drag one of them out of line. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Leave the wheel to the list when a chart may not zoom The wheel moves from the pointer layer to a layer of its own, shown only on an interactive chart with PanZoom on. Fyne looks for a Scrollable apart from a Mouseable, so hiding the wheel layer keeps hover and clicks on the chart and lets the wheel reach the scroll container around it. Before, a chart with PanZoom(false) took the wheel and ignored it, and a list of such charts could not be scrolled with the pointer over any of them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Give the wheel test the time a race-detected runner needs TestOnGestureEndsAWheelOnceItIsStill sends two notches and expects one gesture, which holds only while the gap between them is shorter than wheelSettles. Under the race detector on CI the first notch took longer than 120ms to draw, the wheel settled in between, and OnGesture said [true false true]. wheelSettles is now a variable a test can widen through export_test.go, and this test widens it to a second; the wait for the gesture to end grows to match. What the chart does outside tests is unchanged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The branch started as one horizon chart and has followed figure's main branch
since. It is now the demo's catalogue caught up with what figure can draw,
plus the one widget change that catching up asked for.
The widget change
figure's
backend/gggrewWithFallbackFont: fonts consulted, in order, fora rune the chart's own font has no glyph for, with a
?written for a rune noface can draw at all. That closes the gap
chart.ThemeFonthas carried awarning about since it was written — Fyne's NotoSans-Regular has no
≤,≥or
∞, and a rasterizer handed one font drew nothing where the shaper Fynedraws its own text with would have fallen back.
fynefigure.FallbackFontis the new option, andTarget.SetFonttakes thefallbacks with the typeface, so a chart that follows the application to a new
font keeps them. The config holds the faces rather than the rasterizer's
options:
SetFontused to rebuild that list, and would now have dropped thefallback while replacing the font.
look.Fallback()— the Go regular face, which iswhat every other figure raster is drawn in — whenever it follows the theme's
typeface, and the tooltip beside it gets the same list.
"????"and requires the two to differ. Aquestion mark is ink, so counting ink no longer tells a drawn symbol from a
lost one.
The charts
Each entry is a chart type figure grew, because the demo is where one has to
appear or nobody sees it.
colourbar instead of an axis, with the band height pinned rather than cut
from the data
dendrogram-heatmap, radial-tree, spc — the raster mark, the probability
scales, the statistical instruments and the tidy tree
three charts plus the 3D scatter
over it, in a new Ternary group beside Polar and Smith. The prism is
sampled over the whole simplex, so the liquidus is a surface rather than the
corner a real alloy catalogue would crowd into.
of two passes is in front
binned into cells of equal area: the chart a stereonet's contoured density is
the flat form of
Three existing entries moved rather than being added to:
where
Frame.Arcshows: a coarse sweep joined by chords would cut throughthe ball.
geom.Orient(geom.Horizontal)withgeom.Baseline(1)— so ADR 0053'sheadline chart is drawn whole.
of an extruded mark.
cmd/demo/plots/data.go's clustering is now a function of the items and adistance, because the genes are clustered by the same code read the other way
round, and its uniform deviate takes three rounds: two read side by side off
one affine round walk in step, which put the histogram's background on a curve
instead of over the ball.
Base branch
Targets
shared-selection, notmain:cmd/demo/plots/does not exist onmain, so this work sits on top of that branch rather than beside it.CI
Green, and it took three fixes that had nothing to do with the charts.
module from its own
go.mod, with nogo.work, so the comment saying "buildsthrough go.work until figure is released" was a red build. All three modules
now name a commit of figure's main branch — the widget calls
gg.WithFallbackFont, the demo draws the chart types after v0.11.0, and theGPU tier calls
Available,DisableandEnable, whichbackend/gg/gpuhasnever released. Each
go.modsays why it is not a tag and when it goes backto being one.
!linuxa while ago, but three files went on importing it forEnabled,Available,Enable,DisableandClose, so the link still ended indlopen_stub: unhandled relocation for goffi_dlopen. CI never said so becausemodule resolution failed first. The tier is now reached through six functions,
the import lives in the one file Linux does not build, and
tier_linux.goanswers instead.
GOOS=linux go list -depswent from eight matches on thetier and its foreign-function layer to none.
through
fyne.Do; the test driver documents that it runs the function onwhichever goroutine called it, so the ticker was a second goroutine in the
widgets the test was driving.
newKitchentakes the interval and the testpasses zero.
Test plan
GOWORK=off, which is how CI builds itgo build ./... && go vet ./... && go test ./...— passes,including the new font test and its negative control (with the fallback list
emptied, the symbol titles render identically to
"????"and the test fails)cmd/demo:go build ./... && go vet ./... && go test ./...— passes;TestEveryEntryBuildsAndPaintspaints every new entry in a Fyne test window,and
TestCatalogueShapechecks the new group's order and idsgpumodule:go build ./... && go vet ./...gofmt -l .— clean in both modules🤖 Generated with Claude Code