Conversation
…mits goldfish 1.9.21 returns `diagnose_outliers`, `diagnose_changepoints` and `margin_table` -- classed tibbles carrying a metadata contract -- in place of the shared `diagnostic.goldfish` these methods were written against. The old bindings never had a released goldfish to dispatch on. `plot.changepoints.goldfish` is rewritten rather than adjusted: it consumed a LIST of a data frame and a vector of changepoint positions, where the object is now one tibble with a logical `cpt` column. `plot.outliers.goldfish` loses its `"YES" %in% x$outlier` string check, the column being logical. Both now plot the `.series` column -- the series the diagnostic actually analysed -- and read their labels off `params`, so a diagnostic called with `effect =` is drawn as that term's own series with the term in the subtitle, rather than as a log-likelihood trace beside flags computed from something else. Nothing here sniffs which columns are present, and nothing calls back into goldfish: dispatch is on class alone. The axis is labelled with the break times themselves only where they are numbers. The old method passed them to `scale_x_continuous()` unconditionally while its own fixture carried POSIXct times. New `plot.margin_table()` compares each actor's observed activity with what the model expected of them, choosing the comparison from the scales the object records rather than from which columns are NA: the per-actor martingale residual where the model class defines a compensator, the calibration ratio where it does not. It draws the `top` actors furthest from the reference -- 154 states one per row is unreadable, and the fisheries fixture is the ordinary case, not an extreme one -- and says in the subtitle how many it left out. Fixtures regenerated from public goldfish data, and `goldfish_margins` added. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`plot.test_gof()` draws each effect's standardized cumulative score process against the Brownian-bridge bands its p-value was read from, faceted by term and, on a flavoured fit, by the process columns the object appends. The x axis is the object's own `u` column, labelled by the `clock` it records, and that is load-bearing rather than presentational: the bands are valid on whichever clock produced the process, so re-deriving an event index here would draw the path on one clock and the reference on another. On the information clock the spacing of the steps is itself the diagnostic. The band inverts the same Kolmogorov distribution the event-clock p-value comes from, solved to machine precision so the two cannot disagree in the digits. `plot.test_time()` draws the scaled Schoenfeld residuals of each tested effect against the model's own clock, with a smooth and the fitted estimate as the reference line. Under `method = "periods"` the scatter is coloured by period so the compared regimes are visible; under `"trend"` the period column is all-NA and no colour aesthetic is set, since a one-level legend on every trend plot is noise. Both objects are classed lists rather than single tibbles -- one rectangle does not hold a per-effect table and a per-interval series -- so each method reads its series from a named component while taking labels and references from the same metadata contract the existing methods use. Two precooked fixtures added (`goldfish_gof`, `goldfish_time`). The three existing ones are regenerated at the same time: they carry a `version` attribute precisely so a stale fixture can be spotted, and they were minted before the diagnostic objects moved. Suite: 130 PASS, 0 FAIL.
Two panels composed with patchwork: each coefficient's
leave-the-first-m-events-out path, and the share of information those events
delivered. `view = c("both", "path", "accrual")` selects one panel alone, the
escape hatch when a model has more coefficients than a composed figure can
hold.
The geometry is the substance, so it is what the tests pin.
Both panels are windowed on the excursion rather than the sequence. The path
returns to the estimate by construction, so drawing the full range squashes the
part being read into a few percent of the axis. Each coefficient gets its own
window -- `1.15 * stabilized_at`, floored at 10 -- and its own scales: a window
shared across facets re-creates exactly the squashing the windowing prevents,
since coefficients settle at very different points. A path that never left its
band takes the full range, there being no excursion to window on.
The accrual panel is full-range with the onset window shaded rather than cut
to, and carries the proportional diagonal `y = x/n`. Without the diagonal a
monotone curve from 0 to 1 says nothing: the departure from proportional is the
finding, which is what makes a slow-starting sequence visible.
Coefficients held fixed through `offset()` are not drawn -- an offset's path is
a flat line at its imposed value -- and a fit with nothing estimated says so
rather than drawing an empty panel.
One precooked fixture added (`goldfish_onset`), from the cold-start choice fit:
while the history is empty every alternative looks alike and the score
contributions are zero, so the information arrives late and the accrual curve
has something to show.
Suite: 150 PASS, 0 FAIL.
The three plot methods added for the goldfish test and onset classes, plus the
precooked fixtures. Filed under the unreleased 1.0.4, which is where the
phase-1 rebinding already sits.
Two checks the task asked for, both clean. autograph gains no goldfish
dependency: goldfish appears nowhere in DESCRIPTION and no `goldfish::` call
exists in R/, dispatch being on class alone in the stocnet pattern. And the
pkgdown reference needs no edit -- the three methods are aliases on the
`plot_adequacy` topic, which the index already selects.
That second point corrects the premise this task carried. The note said
`starts_with("plot.")` "matches no topic whose name uses an underscore", so
`plot_adequacy`, `plot_gof`, `plot_convergence` and `plot_interp` were all
supposedly absent from the reference index. They are not. pkgdown's
`starts_with()` interpolates its argument into a regex --
`any_alias(~grepl(paste0("^", x), .))`, with no `fixed = TRUE` and no escaping
-- so the `.` is a wildcard and matches the underscore. Checked against the
package's own man/ directory: all seven `plot_*` topics are selected. There is
nothing here to raise with the maintainer.
The other item stands and remains the maintainer's: RSiena 1.6.6 already
publishes `test_gof`, `test_parameter` and `test_time` as S3 generics with
`.sienaFit` methods, which is a cross-package question about where the stocnet
diagnostic generics should live rather than anything autograph can settle.
Suite: 150 PASS, 0 FAIL.
`plot.result.goldfish()` composes four panels: the deviance trace with outlying intervals marked, scaled Schoenfeld smooths, the cumulative score processes, and the waiting times against the unit exponential. Everything comes from what the fit already stores -- no evaluation pass, no preprocessed statistics -- so the figure costs a plot and not a re-fit. The consequence is the design's most useful property: a panel needing a primitive the fit did not store is **left out** rather than erroring, so which panels appear is itself a readout of what was asked for at estimation. Availability is decided by attempting each panel and dropping it on failure, rather than by a primitive list kept here: goldfish already raises a named error when a primitive is missing, and a second copy of its availability rules is how the two would drift apart. The waiting-time panel is exact-time only for the same reason -- an ordinal likelihood conditions the timing away, and goldfish's own error is what says so. The Schoenfeld panel is capped and ranked by the cumulative-score statistic, so a model with a dozen terms shows the effects worth looking at rather than whichever the formula named first. goldfish joins ergm and RSiena under `Enhances` -- packages whose objects autograph plots and which it does not require. This is the one place a goldfish call is unavoidable: the method receives a fit rather than a plot-ready diagnostic object, and reimplementing four residual definitions here (the Grambsch-Therneau scaling, the exact-time exposure term, the tie rule) would guarantee drift from the package that owns them. It stays out of Imports and Depends, and the calls are gated as the other optional-package methods are. Note this refines the previous commit's claim that goldfish appears nowhere in DESCRIPTION: it now appears under Enhances, which creates no install or check dependency. Suite: 161 PASS, 0 FAIL.
goldfish now returns `diagnose_outliers()` and `diagnose_changepoints()` on a multi-process fit as one row-bound table with `flavor` and `family` naming the process each row came from. Both plots draw their series with `geom_line()`, so without a panel split the line ran straight from one process's last event to the next process's first -- a segment joining two unrelated series. `plot.diagnose_changepoints()` had a second one: `geom_vline(xintercept = )` took a vector pooled over the whole table, which would put every process's breaks onto every panel. The breaks now travel as the rows they were found in. Same `facet_wrap` pattern `plot.margin_table()` already used. A single-process table carries neither column and is unfaceted, as before. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LcCL1nqr8RrHLUpABt28B2
A model with many terms breaks a one-panel-per-term figure, and the obvious remedy assumes a human between the fit and the plot. Fits go to a cluster, so that assumption fails exactly where the problem is worst. `plot()` on `test_gof`, `test_time` and `diagnose_onset` takes `page`, and `ag_pages()` reports the count WITHOUT rendering, so a loop can size itself and write every page. A page past the last is an error naming the count rather than an empty panel, which is what an off-by-one would otherwise produce silently. Omitting `page` leaves the figure exactly as it was. `plot.margin_table()` draws level against shape when goldfish supplies the `dispersion` column: the difference on one axis, the dispersion on the other, sized by event count, so the quadrants separate an actor that acted too often from one whose events were merely bunched. Both kinds of omission are named -- actors below two completed spans, and actors beyond `top`. The overview's Schoenfeld panel says how many terms it dropped. Drawing four of fifty-six without a word is the same failure as a diagnostic reporting nothing because it could not see anything: the output looks like an answer about the whole model. Fixing that surfaced a real defect in the ranking it does. It matched the test's coefficient labels (`ideg_cal`) against the residual matrix's effect names (`indeg`), which intersect only on the intercept -- so asking for four terms drew one. Worse, those names repeat when an effect appears over two networks, so `rows[, "indeg"]` would have drawn the first of them under an ambiguous label. Selection is now by column position and the panels are labelled with the test's own compact term strings. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LcCL1nqr8RrHLUpABt28B2
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LcCL1nqr8RrHLUpABt28B2
…tograph)` faster to attach
…be remembered across sessions
…spreads rather than at a fixed diameter of one coordinate unit
…ere the network records them instead of default "One" and "Two"
…ode and two-mode layers (identified by `manynet::is_multilevel()`) with the "multilevel" layout by default
… how many nodes there are at each level rather than in the whole network
# Conflicts: # DESCRIPTION # NEWS.md
Contributor
There was a problem hiding this comment.
Pull request overview
This PR bumps {autograph} to v1.2.0 with faster attach-time behavior, expanded multilevel layout controls/defaults, improved multilevel/multiplex graph rendering, persisted theming across sessions, and a substantial new set of goldfish diagnostic plot methods (plus fixtures and tests).
Changes:
- Removed the interactive CRAN update check on attach and added persisted theme support via
stocnet_theme(persist=TRUE). - Enhanced multilevel layout inference/options and improved
graphr()defaults and aesthetics for multilevel/multiplex networks (sizes, opacity, labels, legends, loops). - Added/expanded goldfish diagnostic plotting (
plot.*) including pagination support and new precooked fixtures with corresponding tests and docs.
Reviewed changes
Copilot reviewed 21 out of 35 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/testthat/test-plot_goldfish.R | Adds comprehensive tests for new goldfish diagnostic plot methods and pagination behavior. |
| tests/testthat/test-layout_partition.R | Adds regression tests around multilevel defaults/inference, sizing, opacity, labels, and self-loop scaling. |
| tests/testthat/test-graphr.R | Adds tests for two-mode mode-name legends and multiplex edge colouring/linetype legend behavior. |
| tests/testthat/test-functional_layouts.R | Updates functional layout argument coverage note for multilevel. |
| R/zzz.R | Removes CRAN version check and applies persisted theme preference on attach. |
| R/theme_set.R | Adds persist support plus read/write/forget helpers for theme preference storage. |
| R/plot_diagnostics.R | Reworks and expands goldfish diagnostic plotting, adds pagination helpers, and adds plot.result.goldfish(). |
| R/layout_partition.R | Extends layout_multilevel() API and improves level inference/validation for multilevel layouts. |
| R/grapht.R | Updates docs clarifying grapht() default layout behavior for animations. |
| R/graphr.R | Updates default layout selection logic and passes layout context into edge/node sizing/alpha inference. |
| R/graph_nodes.R | Adjusts node mapping/legend behavior and makes default node size handling layout-aware. |
| R/graph_legends.R | Aligns edge colour legend title with the same logic used to infer edge colour semantics. |
| R/graph_labels.R | Adjusts multilevel labeling to use nudged plain text (no white label boxes) with tuned repel parameters. |
| R/graph_edges.R | Adds layout-aware edge alpha inference, fixes sign legend behavior when colours show layers, and scales self-loop size by layout spread. |
| R/graph_aes.R | Makes default node sizing layout-aware for multilevel, improves two-mode mode labels, and defaults multiplex edge colours to layer with matching legend titling. |
| R/data_precooked.R | Adds new precooked goldfish fixtures to the package datasets. |
| NEWS.md | Adds v1.2.0 release notes aligned with the PR description. |
| NAMESPACE | Registers new plot.* S3 methods and exports ag_pages(). |
| man/theme_set.Rd | Documents new persist argument for stocnet_theme(). |
| man/plot_grapht.Rd | Documents grapht() default layout behavior clarification. |
| man/plot_graphr.Rd | Updates graphr() default layout documentation to include multilevel defaulting. |
| man/plot_goldfish_fit.Rd | Adds generated docs for plot.result.goldfish(). |
| man/plot_adequacy.Rd | Updates generated docs for new diagnostic plot methods and pagination arguments. |
| man/made_earlier.Rd | Updates dataset documentation to new goldfish fixture classes and adds new fixtures. |
| man/layout_partition.Rd | Documents expanded layout_multilevel() arguments and new default level inference behavior. |
| man/ag_pages.Rd | Adds generated docs for new ag_pages() helper. |
| DESCRIPTION | Bumps version to 1.2.0 and updates dependency constraints. |
| cran-comments.md | Adds note about optional user filespace usage for persisted theme setting. |
Files not reviewed (7)
- man/ag_pages.Rd: Generated file
- man/layout_partition.Rd: Generated file
- man/made_earlier.Rd: Generated file
- man/plot_adequacy.Rd: Generated file
- man/plot_goldfish_fit.Rd: Generated file
- man/plot_graphr.Rd: Generated file
- man/plot_grapht.Rd: Generated file
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+189
to
+191
| .as_level <- function(level) { | ||
| if (is.numeric(level)) as.integer(level) else as.integer(as.factor(level)) | ||
| } |
Comment on lines
+335
to
+342
| p <- ggplot2::ggplot( | ||
| residuals, | ||
| ggplot2::aes(x = .data$clock, y = .data$residual) | ||
| ) + | ||
| ggplot2::geom_hline( | ||
| ggplot2::aes(yintercept = .data$reference), | ||
| colour = ag_base() | ||
| ) |
Comment on lines
+5
to
+7
| S3method(plot,diagnose_changepoints) | ||
| S3method(plot,diagnose_onset) | ||
| S3method(plot,diagnose_outliers) |
Labelling every node of a dense network hid the network behind its own labels, and the only alternative was `labels = FALSE`. `labels` now also accepts a depth of ranks (`labels = 5`), a measure to rank by (`labels = "betweenness"`, or `c(betweenness = 5)` for both), the name of a logical node attribute, or a logical/name/position vector of the nodes to label. Selection reuses `netrics::node_is_max(measure, ranks = n)`, so nodes tied at the cut are labelled together and two-mode networks are ranked within each mode; multilevel networks carrying `lvl` are handled alongside. Networks of more than 30 nodes now label only their most central nodes by default, reporting how many. `fict_marvel` on the multilevel layout goes from 194 overlapping labels to 10, five per plane. The selected rows are handed to each of the six label geoms as their `data`, rather than blanking the others' labels, so no space is reserved for labels that are not drawn. `grapht()` resolves the selection once across all waves and `graphs()` once for all its panels. Also updates the Labels section of the visualisation tutorial, which had recommended the `mutate(name = ifelse(...))` workaround this replaces, and regenerates its article and pre-rendered HTML. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…anges or categories (closes #15)
… "fr", "drl", "kk" networks
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.
Description
Package
.onAttach(), makinglibrary(autograph)faster to attach.onAttach()not applying the ink of a persisted theme{goldfish}toEnhances{systemfonts}toSuggestswebsite-buildsjob toprchecks.yml, reporting whether the site buildscount_pages()was missing from the reference index, which stopped itNEWS.mdbullets,the website reference index, and keeping tutorials and articles in step
stocnet_completion()to offer values an argument accepts as RStudio completionsgraphr(fict_lotr, node_color =Tab lists the node variablesfict_lotrholdsisolatesstocnet_completion(FALSE)restores itpersistargument remembers the choice, asstocnet_theme()doesLayouts
alignment = "rungs"check_span()) and nodal offset (check_offset())ranks=to choose the layers:igraph::layout_with_sugiyama()rankforalignment=to choose how a layer is spread out:layout_layered()centring on a second mode node yet reading first mode labelsranks=label_repellayout_levels()to identify modes without having to name alevelmethod,alpha,beta,FUN1andFUN2argumentslayout_dyad()tolayout_hexad()functions themselves are unchangedlayout_matching()alias so every layout has a short namegetNNvec()Graphing
graphr()to draw multilevel networks of interlocking one-mode and two-mode layers by defaultnode_groupto draw overlapping hulls (closes node_group cannot handle overlapping group membership #51)graphr(ison_adolescents, node_group = netrics::node_x_clique())graphr()to note when a colour/shape legend grows past about 7 keysgraphs()to collect guides even where panels held different ranges or categories (closesgraphs()collecting guides doesn't work for different range in the visual variables #15)Theming
persist=tostocnet_theme()persist = TRUEwrites it totools::R_user_dir("autograph", "config")stocnet_theme()via{systemfonts}list_fonts()for listing the font families R can seestocnet_medium()for standardising output to the expected medium:ag_size()scales text, not node size or anything elseag_theme_*()wrappersag_ink()and the groundsimulate_colorblind(),check_separation()andcheck_contrast()for checking palettesseverity=to view anomalous trichromacy (deuteranomaly, protanomaly)check_span()for scoring how far each tie travels down the pagecheck_offset()for scoring how far each tie is from its ideal straight lineag_ink()for the colour a theme writes withag_base()to be light where that sets it off from the highlightag_missing()for the neutral that data recedes into:ag_qualitative()to note when a palette is asked for more colours than it holdsag_qualitative()uses most distinct, own colors first not mixturesPlotting
plot.goldfishFit()for the four diagnostic panels a fit can supplyrepeat where an effect appears over two networks
alone, so it drew one term where four were asked for
plot.goldfishGOF()for each effect's cumulative score processplot.goldfishTimeTest()for the scaled Schoenfeld residualsmethod = "periods"plot.goldfishOnset()for the parameter path and information accrualview = c("both", "path", "accrual")to select a single panelplot.goldfishMargins()for observed against expected activitytopactors furthest from the reference, and counts the restdispersiontoppageargument toplot()on the per-term diagnosticsgoldfishGOF,goldfishTimeTest, andgoldfishOnsetcount_pages(), reporting the count without renderingag_pages(), sinceag_is for the theme accessorspageis past the lastpageis omittedgoldfishOutliers,goldfishChangepoints,goldfishOnset,goldfishMargins,goldfishGOF,goldfishTimeTest,goldfishScoreTest,and
goldfishFittest_gofis what a sibling package would pick too, andtwo packages emitting one class string cannot be told apart by dispatch
plot.goldfishOutliers()andplot.goldfishChangepoints()plot.outliers.goldfish()andplot.changepoints.goldfish().seriescolumn, so a diagnostic called witheffect =isdrawn as that term's series rather than as a log-likelihood trace
plot.goldfishChangepoints()to draw each process's own breaksplot.goldfishOutliers()to read the now-logicaloutliercolumnplot.goldfishChangepoints()for the tibble with acptcolumnso a dated event stream keeps its date scale
goldfish_margins,goldfish_gof,goldfish_time,and
goldfish_onset, and refreshed the two older fixturesgoldfish_outlierscomes from a receiver-choice model of the callsfisheries_treatieslayercli::cli_abort()ingf_facet_paged()withsnet_abort()R/plot_diagnostics.Rsince only ASCII is portableplot.matrix()hard-coding its polesTutorials