Changelog
Source:NEWS.md
VizModules 0.3.0
New Modules
- Turned the Figure Builder into a reusable, namespaced Shiny module (
figureBuilderUI()/figureBuilderServer()), so it can be embedded inside a larger app and instantiated more than once, just like the plot modules.figureBuilderApp()is now a thin wrapper around this module and keeps its existing behaviour. The canvas CSS/JS was made namespace-safe (class-based, per-instance) so multiple builders can coexist on one page.- Panel labels (a, b, c …) now render live on the canvas as soon as they are chosen from the “Panel labels” menu (and renumber as panels are added, removed, or dragged), instead of only appearing in the exported SVG.
- Moved the Figure Builder app into an exported
figureBuilderApp()function so it can be launched directly (figureBuilderApp()), seeded with custom datasets viadata_list, extended with custom modules viamodule_registry, and returned either as ashinyApp()object or as separateui/servercomponents (return_components = TRUE). The bundledinst/apps/figure-builderapp is now a thin wrapper around this function. - Added to Gallery App.
Improved/New Functionality
- Facet/split selectors across all modules now only offer valid faceting variables. Faceting (or splitting) is restricted to categorical columns (character or factor) with fewer than 50 unique values; numeric columns and high-cardinality categoricals are no longer selectable, preventing accidental creation of an unwieldy number of panels. This is powered by a new internal helper,
.facet_check(), whose output populates the facet/split input choices. - Simplified boxplot outlier hiding to rely on native plotly
boxpoints = FALSEbehaviour (via ggplot2’soutlier.shape = NAin theplotthis_BoxPlotmodule anddittoViz::yPlot’sboxplot.show.outliersargument indittoViz_yPlot), rather than post-hoc marker manipulation. Removed the now-unused internal helper.remove_boxplot_outliers(). This is more robust with plotly 4.12.0+. - Added a new reusable custom Shiny input,
multiDynamicInput()(withupdateMultiDynamicInput()), that lets users dynamically add and remove rows of heterogeneous inputs. Each row is described by a genericrow_spec(a named list of field specs using either atypealias —select,text,numeric,slider,checkbox,colour— or an arbitrary input constructor viafn), a+ Addbutton appends rows, each row has anXdelete button, and fields wrap to a new line aftermax_per_row(default 4). The value returned to the server is a named list of rows (model1,model2, …), each a named list keyed by the field names. Add/delete are handled client-side, and values are read back generically via each field’s registered Shiny input binding, so any input type is supported.- Added vignette
vignette("using-custom-shiny-inputs")documentingmultiDynamicInput()usage: row_spec definition, pre-filling withelements, reading values, and server-side updates.
- Added vignette
- Added generic modeling capabilities to
dittoViz_scatterPlot module. The module’s custom-model feature now supports multiple models at once viamultiDynamicInput(): add as many rows as you like, each with its own model type (lm/glm/loess/nls), formula, line colour, and line width, and every valid model is fitted against the active (filtered) data and overlaid as its own line (respecting faceting). Formulas are validated by the internal.safe_build_model()helper to ensure safety.- This includes the ability to add custom model backends via
register_model_backend(),get_model_backend(),list_model_backends(), andbuild_model_row_spec(). Backends declare afitfunction, apredictfunction, validated output classes, and optional extra UIfieldsthat appear/hide dynamically based on the selected model type. The four built-in backends (lm, glm, loess, nls) are registered automatically at package load. Extra UI fields from backends are forwarded tofit()via.... - Added vignette
vignette("custom-model-lines")documenting the model backend registry: how the pipeline works, setting model defaults, registering custom backends (with drc and mgcv examples), and how extra fields flow through to the fit function.
- This includes the ability to add custom model backends via
- Pass
defaults,hide.inputs, andhide.tabsarguments to the module app factory functions in all module app wrappers, so that users can pre-fill or hide controls when testing modules in isolation. - More intelligent input hiding logic so that when individual inputs are hidden (via
hide.inputsor dynamically in response to other inputs), the remaining controls reflow to fill the space and no empty gaps are left in the UI. Input grids are now laid out with a wrapping flexbox container viaorganize_inputs(). Optional elements are handled gracefully. - Added continuous color-scale trimming controls (“Lower Quantile”, “Upper Quantile”, “Lower Cutoff”, and “Upper Cutoff”) to the
plotthis_DotPlot,plotthis_BarPlot, andplotthis_SplitBarPlotmodules, exposing the newlower_quantile/upper_quantile/lower_cutoff/upper_cutoffarguments from plotthis 0.13.0. These controls appear only when the selected fill column is numeric. - Added dot border controls (“Border Color” and “Border Size”) to the
plotthis_DotPlotmodule, exposing the newborder_colorandborder_sizearguments from plotthis 0.13.0.border_coloris limited to a single constant color in the module UI. - Updated the
plotthis_DotPlot“Fill Cutoff” control to pair a numeric value with a new “Fill Cutoff Direction” selector (<,<=,>,>=), matching plotthis 0.13.0’s string-expressionfill_cutoff(e.g."< 18"). - Added annotation persistence, i.e. annotation positions persist when the plot is re-rendered. This extends to axis/facet titles and custom annotations, which means much less finagling during iterative editing.
Bug Fixes
- Fixed broken input hiding when using
hide.inputsandhide.tabsarguments in module app wrappers due to lazy UI injection viarenderUI, which effectively overwrote thehidecalls.renderUIalso re-renders the input UIs every time a dataset changes - now if the dataset changes, the inputs are re-rendered but thehidecalls are re-applied to maintain the hidden state. - Fixed an error in
plotthis_SplitBarPlotwhere the categorical text position input was not respected if the axes were flipped. Now the text position input is respected regardless of axis orientation. - Export numerous internal helper functions for use in custom modules, particularly those related to axes, faceting, and layouts. It became apparent these were necessary as initial work began on
sciVizModules. - Fixed a bug in
dittoViz_yPlotwhere plot selection and outlier hiding were not respected appropriately due to a typo in theboxplot.show.outliersinput name. - Fixed a bug in
dittoViz_scatterPlotwhere 2split.byinputs caused an error due to improper checks for empty strings on a vector of elements. - Fixed a bug in
dittoViz_scatterPlotwhere highlight aesthetics weren’t applied when a categorical x-axis was used.
VizModules 0.2.0
CRAN release: 2026-06-16
- Created the Figure Builder app so that users can dynamically construct multi-panel figures using different data sets and plot types on a single page. Allows for full page SVG export, source data dump organized per panel, and full customization of plot position and size.
- All
*OutputUI()functions gained aresizableargument (defaultTRUE). WhenFALSE, the plot output is no longer wrapped inshinyjqui::jqui_resizable(), which avoids a redundant resize handle when the output is embedded in a container that already provides resizing (such as the Figure Builder app cards). - Added a new
plotthis_DotPlotmodule (plotthis_DotPlotInputsUI(),plotthis_DotPlotOutputUI(),plotthis_DotPlotServer(), and theplotthis_DotPlotApp()convenience wrapper) that wrapsplotthis::DotPlot()for interactive dot plots, including a custom dot-size legend since plotly still lacks that capability. - Added the
example_markersdataset, a simulated single-cell marker-gene expression table (immune cell types × marker genes) used as the default example data for the DotPlot module. - Added “Source Data” download button at the bottom of every module’s control panel. The button creates and downloads a ZIP file containing a self-contained HTML of the plotly plot, a CSV of the plot data (retrieved via
plotly::plotly_data()), and for modules with statistics enabled (Box / Violin / yPlot), a table of the statistics info. Source downloads are now built from the exportedcollect_source_data()andcreate_source_download_handler()helpers, and each module server returns its source reactive so it can be reused (e.g. by the Figure Builder). Given source data is now required by many journals, this is important. - Removed old interactive plot download button and associated helper function.
- Removed old dynamically hidden stats download button and associated logic, since stats are now included in the source download when applicable.
- Statistic helper functions are now exported allowing users to annotate plotly graphs with custom statistics:
compute_pairwise_stats(),create_stat_annotations(),apply_stat_annotations(),generate_pair_strings(), andparse_pair_strings(). - Exposed
empty_plot()for use as a placeholder, e.g. if parameters aren’t valid for a given plot type, to pass that info to user without ugly error messages. - Faceting improvements - new internal helpers that control subplot spacing, subplot size, and facet_scale handling. This fixes much of the wonkiness for plots with many panels. Uniform inputs added for panel spacing across all modules.
- Axis titles now uniformly added as annotations to allow interactive repositioning.
- Condensed package wide workflows with simple helpers, e.g.
apply_title_layout(), resulting in significantly less jank. - Axis adjustments are now properly reflected in axis/legend titles for appropriate modules, e.g.
yPlot,scatterPlot,linePlot. - Removed a handful of spurious/non-functional inputs, particularly for the
dittoViz_scatterPlotmodule. - Custom
size.bylegends added forplotthis_DotPlotanddittoViz_scatterPlotmodules, since plotly does not yet support these. - Update docstrings to reflect new inputs and features and clarify which parameters of underlying plotting functions may not be implemented.
- Various border fixes for faceted plots.