Tables present numbers; charts reveal patterns. But what if a table could do both? Nanoplots (tiny, embedded visualizations) bridge this divide by placing miniature graphics directly within table cells. These small-scale data representations can show trends, distributions, and comparisons at a glance, augmenting numeric values with visual context that aids rapid comprehension.
The term “sparkline” (coined by Edward Tufte) describes “data-intense, design-simple, word-sized graphics” that can be embedded inline with text. Nanoplots in gt extend this concept to tabular contexts, allowing each row to carry its own miniature visualization derived from the row’s data. They are deliberately simple (there’s limited space, after all) but that simplicity becomes a virtue. A nanoplot doesn’t replace detailed analysis; it provides an immediate visual summary that guides the reader’s attention and facilitates comparison across rows.
This chapter explores the cols_nanoplot() function and its companion nanoplot_options() helper. We’ll examine the three available plot types (line plots, bar plots, and box plots) and discover how to customize their appearance, handle missing data, add reference elements, and supply data in various formats. By the chapter’s end, you’ll be equipped to enhance your tables with these compact but powerful visualizations.
10.1 The cols_nanoplot() function
The cols_nanoplot() function creates a new column containing nanoplots, using data from one or more existing columns. The function collects numeric values across specified columns for each row, generates a plot from those values, and places the resulting visualization in a new column.
Let’s start with a simple example using the illness dataset, which contains daily medical test measurements:
illness|>dplyr::slice_head(n =8)|>gt(rowname_col ="test")|>tab_header(title ="Daily Medical Test Results")|>cols_hide(columns =c(starts_with("norm"), units))|>cols_nanoplot( columns =starts_with("day"), new_col_name ="trend", new_col_label ="7-Day Trend")
Daily Medical Test Results
7-Day Trend
Viral load
WBC
Neutrophils
RBC
Hb
PLT
ALT
AST
This table shows medical test measurements with a line plot summarizing the seven daily values. The columns = starts_with("day") argument collects data from all columns beginning with “day”, concatenating them left-to-right to form each row’s data series. The source columns are automatically hidden (due to autohide = TRUE by default), keeping the table clean.
The nanoplot provides immediate visual context: readers can instantly see whether values trended upward, downward, or remained stable, without mentally parsing seven separate numbers.
Two arguments control how the new nanoplot column is identified and presented. The new_col_name = "trend" argument sets the internal column name and this is what you’ll use to reference this column in subsequent gt operations like cols_width(), cols_align(), cols_move(), or tab_style(). Think of it as the column’s programmatic identifier. Meanwhile, new_col_label = "7-Day Trend" sets what readers actually see in the column header. This label can include spaces, special characters, or even markdown formatting (via md()), making it reader-friendly while keeping the internal name concise and code-friendly.
Both arguments are optional. If you omit new_col_name, gt generates a default name (typically “nanoplots”). If you omit new_col_label, the column name itself becomes the label. However, providing explicit values is good practice: it makes your code clearer and ensures column headers communicate effectively with your audience. You’ll often want a short, simple internal name for coding convenience paired with a more descriptive, formatted label for presentation clarity.
10.1.1 Data input: columns vs. value streams
Nanoplots accept data in two flexible formats, allowing you to work with whatever structure your data already has.
The first format spreads values across multiple columns, as we just saw with the illness dataset. Each column contributes one value to the nanoplot, collected in left-to-right order:
The second format packs all values for a row into a single column as a delimited string. This is particularly useful when different rows have varying numbers of data points, or when your data arrives in this format from external sources:
Both formats produce identical nanoplots. The multi-column approach works well when your table already has the data structured that way and you want to show those columns alongside the nanoplot. The value stream approach is good for when you need flexibility in the number of data points per row or want to keep your table structure simple. Commas, spaces, or semicolons can all serve as delimiters in value streams.
10.2 Line plots
Line plots are the default nanoplot type and is best for showing trends over ordered sequences. They consist of three visual layers that can be independently controlled: data points (the actual values), a connecting line, and a filled area beneath the line.
10.2.1 Basic line plots
Line plots are the natural choice when your data represents a continuous progression or ordered sequence. Time series, sequential measurements, cumulative values, and any data where the order matters and you want to emphasize change from one value to the next: all of these benefit from line plot representation. The connecting line creates a visual path that guides the eye through the progression, making it easy to spot upward trends, downward trends, plateaus, or sudden changes.
In the context of nanoplots, line plots serve as compact trend indicators that answer questions like “Is this going up or down?” and “How volatile is this pattern?” at a glance. Because they’re the default plot type, you don’t need to specify plot_type = "line". Simply calling cols_nanoplot() produces a line plot. This makes them the quickest option when you need a basic visual summary without customization.
The towny dataset contains population data for municipalities across multiple census years. By selecting columns that start with “population”, we collect a time series for each municipality that spans several decades. The resulting line plots provide an immediate visual history of population growth:
Each municipality’s population history spanning decades condenses into a compact visualization. The line plot reveals growth trajectories that would require careful numeric comparison to discern from the raw numbers alone. You can immediately see which municipalities experienced steady growth (smooth upward slopes), which grew explosively in recent decades (sharp upward curves), and which remained relatively stable (nearly flat lines).
The visual comparison across rows is particularly valuable here. Without the nanoplots, determining which municipality grew fastest would require mentally calculating growth rates from the numeric columns. The line plots make this comparison instant as steeper slopes indicate faster growth. Similarly, you can spot patterns like early rapid growth followed by stabilization, or slow initial growth accelerating in later years, patterns that might be missed when scanning columns of numbers.
By hiding the intermediate year columns with cols_hide(columns = matches("199|200|201")), we keep the table clean while still showing the most recent population figure (2021) alongside the visual trend. This combination of current value and historical trend provides both the “what is it now?” and “how did we get here?” perspectives in a single glance.
10.2.2 Customizing line plot appearance
The nanoplot_options() helper function provides extensive control over visual properties. Let’s create line plots with customized styling:
The blue color scheme creates visual cohesion. Larger data points with contrasting stroke and fill colors improve visibility, while the wider line and lighter area fill create depth.
10.2.3 Showing only specific layers
Sometimes you want to emphasize particular aspects of the data. Here’s a line-only plot without points or area:
With many data points, hiding individual markers reduces visual clutter. The data_line_type = "straight" option uses straight line segments instead of curves, which can be clearer for volatile data.
Alternatively, show only points for a scatter-like appearance:
With only two data points per row, a connecting line adds little value. Points alone clearly show the two values and their relative magnitudes.
10.2.4 Line plots with x-axis values
By default, nanoplots space data points evenly along the x-axis. For line plots, you can supply explicit x values using columns_x_vals:
# Create sample data with irregular time intervalsdplyr::tibble( category =c("Product A", "Product B", "Product C"), times =c("1,3,4,8,12", "2,5,6,9,15", "1,2,7,10,14"), values =c("10,15,13,20,25", "8,12,15,11,18", "5,8,12,15,20"))|>gt(rowname_col ="category")|>tab_header(title ="Sales at Irregular Intervals")|>cols_nanoplot( columns =values, columns_x_vals =times, new_col_name ="trend", new_col_label ="Sales Trend", expand_x =c(0, 16))|>cols_width(trend~px(150))
Sales at Irregular Intervals
Sales Trend
Product A
Product B
Product C
The x values position points according to their actual timing rather than equally spacing them. The expand_x argument ensures all plots share the same x-axis range for valid comparison.
10.3 Bar plots
Bar plots are good when showing categorical comparisons and clearly distinguishing positive from negative values. Unlike line plots, bar plots always use equal spacing and ignore any x-axis values.
10.3.1 Basic bar plots
Bar plots work best when you need to compare discrete categories or sequential values where the magnitude of each individual item matters. Each bar represents a single data point, and its height encodes the value. When multiple values appear in a single nanoplot, the bars stand side by side, making it easy to compare magnitudes both within a row (across bars) and between rows (comparing corresponding bars).
In the context of tables, bar nanoplots are particularly effective for showing compositions, breakdowns, or multi-part measurements. For instance, if each row represents a different entity and the columns contain related metrics, a bar nanoplot can show all those metrics together in a compact visual form. This allows readers to quickly grasp not just which values are largest or smallest, but how the pattern of relative magnitudes differs from row to row.
Each bar represents one pizza type’s sales for that day. The relative heights reveal the sales mix, showing which types dominated each day’s orders. By comparing across rows, you can see whether certain days had notably different sales patterns. For example, a day where the classic pizza bar is much taller than the others indicates strong preference for that type, while more uniform bar heights suggest balanced sales across types.
The bars are positioned in the same order as the columns specified in the columns argument, creating a consistent visual structure. This consistency allows your eye to track a specific category across multiple rows. If the veggie pizza is always the fourth bar, you can quickly scan down the column to assess veggie pizza sales across all days without having to reorient yourself for each row.
Bar plots also make zero values and missing values visually obvious. A missing bar (or a bar with zero height) stands out immediately, drawing attention to gaps in the data. This is different from line plots, where missing values might create subtle gaps that could be overlooked.
10.3.2 Customizing bar colors
When bar plots display multiple categories, assigning distinct colors to each bar position creates immediate visual differentiation. Instead of relying on position alone, color allows readers to identify specific categories at a glance. This technique is particularly effective when the categories have inherent associations (like product types, regions, or departments) that benefit from consistent color coding.
The data_bar_fill_color option in nanoplot_options() accepts a vector of colors, with each color corresponding to a bar position in the order specified by the columns argument. The first color applies to the first column’s bar, the second color to the second column’s bar, and so on. This positional consistency means that across all rows, the same category always appears in the same color, creating a visual legend that persists throughout the table.
When using multiple colors, providing a legend is essential. Without one, readers must deduce the color-to-category mapping by examining the source columns (if visible) or through trial and error. A clear legend, whether in a footnote, source note, or table caption, eliminates ambiguity and ensures readers can interpret the colored bars correctly from the first glance.
With autohide = FALSE, the source columns remain visible, allowing readers to see both exact numbers and the visual comparison. The colored bars create an instant visual signature for each pizza type. The source note uses HTML to create colored squares (■ is the Unicode character for a square) that match the bar colors, providing an unambiguous legend without requiring readers to cross-reference column positions.
The even column widths (achieved with cols_width(everything() ~ px(100))) and centered alignment create a balanced, symmetric layout. This uniformity emphasizes the visual comparison by removing layout-based distractions. When all elements are equally spaced and aligned, differences in bar heights become the dominant visual feature.
Color choice matters. The colors used here have strong contrast and distinct hues (orange, yellow, purple, green), making them easy to distinguish even for readers with some forms of color vision deficiency. Avoid using colors that differ only in saturation or lightness, as these can be difficult to differentiate. Test your color palette to ensure sufficient contrast between adjacent bars.
10.3.3 Bar plots with positive and negative values
When data contains both positive and negative values, bar plots automatically apply different visual styling to distinguish them. This is particularly useful for displaying changes, differences, or variance metrics where direction matters as much as magnitude. Positive values might represent growth, gains, or increases, while negative values indicate declines, losses, or decreases.
By default, gt renders positive and negative bars with distinct fill colors, making the directional information immediately visible without requiring readers to examine numeric values or axis labels. You can customize these colors using the data_bar_fill_color and data_bar_negative_fill_color options in nanoplot_options(), allowing you to align the color scheme with your data’s semantics. For instance, green for positive changes and red for negative changes, or any other color pairing that suits your context:
Positive changes appear in green while negative changes display in red, making it immediately apparent which quarters saw gains versus losses for each metric.
10.3.4 Horizontal reference lines in bar plots
Reference lines add analytical context to bar plots by marking specific values of interest. They can highlight thresholds, targets, or statistical measures like means and medians. When comparing bars across different positions or rows, a reference line provides a common benchmark that makes it easier to assess whether individual values exceed, fall short of, or align with a particular standard.
You can specify reference lines using keywords (like "mean" or "median") to compute values from the data itself, or supply fixed numeric values when you have predetermined thresholds or targets in mind. The reference line appears as a horizontal line across the plot, typically in a contrasting color to ensure visibility against the bars:
The reference line shows each country’s mean population across the years, helping identify whether recent years are above or below the historical average. This horizontal line provides a quick visual benchmark: bars extending above the line represent years with above-average population, while those falling below indicate below-average years. The reference line is interactive. Positioning your mouse pointer to the right of the reference line reveals the computed mean value in a tooltip, formatted in the same way as the individual bar values. This allows you to see both the visual pattern and the precise threshold value that defines the comparison.
10.4 Box plots
Box plots summarize distributions by showing median, quartiles, and outliers. They’re ideal when each row contains many values and you want to convey distributional characteristics rather than individual data points.
10.4.1 Basic box plots
pizzaplace|>dplyr::filter(date<="2015-01-14")|>dplyr::mutate(time_numeric =as.numeric(hms::as_hms(time)))|>dplyr::summarize( times =paste(time_numeric, collapse =","), n_orders =dplyr::n(), .by =date)|>gt()|>tab_header(title ="Pizza Order Timing", subtitle ="First Two Weeks of 2015")|>fmt_date(columns =date, date_style ="yMMMEd")|>cols_nanoplot( columns =times, plot_type ="boxplot", new_col_name ="timing", new_col_label ="Order Time Distribution")|>cols_width(timing~px(150))|>cols_align(columns =timing, align ="center")
Pizza Order Timing
First Two Weeks of 2015
date
n_orders
Order Time Distribution
Thu, Jan 1, 2015
162
Fri, Jan 2, 2015
165
Sat, Jan 3, 2015
158
Sun, Jan 4, 2015
106
Mon, Jan 5, 2015
125
Tue, Jan 6, 2015
147
Wed, Jan 7, 2015
138
Thu, Jan 8, 2015
173
Fri, Jan 9, 2015
127
Sat, Jan 10, 2015
146
Sun, Jan 11, 2015
116
Mon, Jan 12, 2015
119
Tue, Jan 13, 2015
120
Wed, Jan 14, 2015
150
Each box plot summarizes that day’s order timing distribution. The box spans the interquartile range (Q1 to Q3), the line inside marks the median, and whiskers extend to data within 1.5× IQR. Points beyond the whiskers are outliers.
10.4.2 Customizing box plot appearance
# Generate sample distribution dataset.seed(23)dplyr::tibble( group =LETTERS[1:5], values =purrr::map_chr(1:5, ~paste(round(rnorm(30, mean =.x*10, sd =5), 1), collapse =",")))|>gt(rowname_col ="group")|>tab_header(title ="Distribution Comparison")|>cols_nanoplot( columns =values, plot_type ="boxplot", autoscale =TRUE, new_col_name ="dist", new_col_label ="Distribution")|>cols_width(dist~px(180))
Distribution Comparison
Distribution
A
B
C
D
E
The autoscale = TRUE option ensures all box plots share the same scale, making cross-row comparisons valid. Without this, each box plot would scale independently to its own data range.
10.4.3 Formatting box plot hover values
Box plots can display custom-formatted values on hover:
pizzaplace|>dplyr::filter(date<="2015-01-07")|>dplyr::mutate(time_numeric =as.numeric(hms::as_hms(time)))|>dplyr::summarize( times =paste(time_numeric, collapse =","), .by =date)|>gt()|>tab_header(title ="Order Time Distributions")|>fmt_date(columns =date, date_style ="yMd")|>cols_nanoplot( columns =times, plot_type ="boxplot", new_col_name ="timing", new_col_label ="When Orders Came In", options =nanoplot_options( y_val_fmt_fn =function(x)format(hms::as_hms(x), "%H:%M")))|>cols_width(timing~px(160))
Order Time Distributions
date
When Orders Came In
1/1/2015
1/2/2015
1/3/2015
1/4/2015
1/5/2015
1/6/2015
1/7/2015
The y_val_fmt_fn argument accepts a function that transforms numeric values for display. Here, seconds-since-midnight values convert back to readable times when users hover over the plot.
10.5 Reference lines and reference areas
Reference elements provide context by marking specific values or ranges within nanoplots.
10.5.1 Reference lines
A reference line is a horizontal line marking a particular value. It can be a fixed number or computed from the data:
Gaps appear where data is missing. Lines discontinue and resume, clearly indicating where observations are absent.
10.6.2 Marker strategy
The marker strategy works like the gap strategy but adds special visual markers at the locations of missing values. This draws even more attention to the fact that data is absent:
Like gaps, but with prominent markers at missing data locations. This makes missingness even more visible.
10.6.3 Zero strategy
The zero strategy treats missing values as zeros. This approach is appropriate when absence of data genuinely means zero (for instance, missing order counts likely mean no orders occurred):
Missing values are replaced with zeros. Use this when zeros are meaningful substitutes (e.g., missing sales might truly mean zero sales).
10.6.4 Remove strategy
The remove strategy excludes missing values entirely from the plot, connecting the remaining points directly. This can be useful when you want to focus only on observed values without calling attention to gaps:
Values are collected left-to-right in the order columns are specified.
10.7.2 Value stream format
While spreading values across multiple columns works well when your data is already structured that way, there are situations where packing values into a single delimited string offers significant advantages. This “value stream” format is useful when different rows contain varying numbers of data points, when data arrives from external sources in this format, or when you want to keep your table structure simple without creating many intermediate columns that serve only as nanoplot inputs.
Value streams are particularly useful when working with time series data of irregular length, aggregated measurements, or any scenario where the number of observations varies by row. Instead of dealing with missing values in unused columns or complex data reshaping, you can store each row’s complete data series as a comma-separated (or space-separated, or semicolon-separated) string. gt parses these strings automatically, making it seamless to work with data in this format.
Value streams pack multiple values into a single column as delimited strings:
Commas, spaces, or semicolons can separate values. Value streams are useful when different rows have varying numbers of observations, since each row’s string can contain however many values exist for that row.
10.7.3 Datetime value streams
Value streams can also contain ISO 8601 datetimes, which are automatically converted to numeric values:
The datetime strings become x-axis positions, accurately representing the timing of observations.
10.8 Autoscaling and axis control
By default, nanoplots scale independently: each plot adjusts its axis range to fit its own data. While this maximizes detail within each plot, it can mislead when comparing across rows. The autoscale option addresses this by forcing all nanoplots to share a common scale, and the expand_x and expand_y arguments allow you to set explicit axis ranges for even greater control.
10.8.1 Autoscaling across rows
By default, each nanoplot scales independently to its own data range. This maximizes visual variation within each plot but makes cross-row comparison difficult:
Now the visual heights accurately represent population magnitudes relative to other rows. Toronto’s massive population dominates while smaller cities appear proportionally smaller.
10.8.2 Expanding axis ranges
The expand_x and expand_y arguments extend plot boundaries beyond the data range:
The fixed y-axis range (70–140) and reference line at 100 provide consistent context across all scenarios, making it easy to see which projections exceed or fall below the baseline.
10.9 Column positioning and labeling
When cols_nanoplot() creates a new column, you control where it appears and what it’s called. The before and after arguments position the column relative to existing columns, while new_col_name and new_col_label set its internal name and display label.
10.9.1 Positioning the nanoplot column
The before and after arguments control where the new nanoplot column appears:
The nanoplot column appears immediately after char, placing related information together.
10.9.2 Custom column names and labels
The new_col_name and new_col_label arguments work together to give your nanoplot column both a practical internal identifier and a polished display label:
The new_col_name sets the internal column name (useful for subsequent operations), while new_col_label sets the display label. Labels can include markdown formatting via md().
10.10 The nanoplot_options() helper
The nanoplot_options() function provides granular control over every visual aspect of nanoplots. Let’s explore the major option categories:
Function Signature
nanoplot_options(# Data point options data_point_radius =NULL, data_point_stroke_color =NULL, data_point_stroke_width =NULL, data_point_fill_color =NULL,# Data line options data_line_type =NULL, data_line_stroke_color =NULL, data_line_stroke_width =NULL,# Data area options data_area_fill_color =NULL,# Bar options (positive values) data_bar_stroke_color =NULL, data_bar_stroke_width =NULL, data_bar_fill_color =NULL,# Bar options (negative values) data_bar_negative_stroke_color =NULL, data_bar_negative_stroke_width =NULL, data_bar_negative_fill_color =NULL,# Reference elements reference_line_color =NULL, reference_area_fill_color =NULL,# Interactive guides vertical_guide_stroke_color =NULL, vertical_guide_stroke_width =NULL,# Layer visibility show_data_points =NULL, show_data_line =NULL, show_data_area =NULL, show_reference_line =NULL, show_reference_area =NULL, show_vertical_guides =NULL, show_y_axis_guide =NULL,# Value formatting interactive_data_values =NULL, y_val_fmt_fn =NULL, y_axis_fmt_fn =NULL, y_ref_line_fmt_fn =NULL, currency =NULL)
10.10.1 Per-point styling
Some options accept vectors to style individual data points differently:
The final point (Q4) is highlighted with a larger golden marker (look at the final values in the data_point_fill_color and data_point_radius arguments), drawing attention to the most recent value.
10.10.2 Reusable option sets
When creating tables with multiple nanoplot columns, you often want them to share a consistent visual style. Rather than duplicating the same nanoplot_options() specification for each column, you can define an option set once and reuse it. This approach offers several benefits: it reduces code repetition, ensures perfect visual consistency across columns, and makes style updates trivial (change the definition once rather than hunting through multiple cols_nanoplot() calls).
Reusable option sets are particularly valuable when building themed tables or when working with organizational style guidelines. You might define several standard option sets ("minimal", "detailed", "dashboard", etc.) and apply them consistently across different tables and reports. This creates visual coherence across your work while keeping the implementation clean and maintainable.
Create option sets once and apply them across multiple nanoplot columns:
Both nanoplot columns share the same minimal styling, creating visual consistency across the table.
10.10.3 Currency formatting
When nanoplots display financial data, proper currency formatting in tooltips and hover displays makes the values immediately understandable. Rather than seeing raw numbers like “1350” or “12000”, users see properly formatted currency values like "$1,350" or "$12,000". This formatting applies to the interactive elements of the nanoplot: when users hover over data points, reference lines, or other interactive features, the displayed values respect the currency specification.
The currency option in nanoplot_options() accepts standard three-letter currency codes ("USD", "EUR", "GBP", "JPY", etc.) and automatically applies appropriate formatting rules for that currency, including the correct symbol, decimal places, and thousands separators. This ensures that financial nanoplots maintain the same level of polish and professionalism as the rest of your formatted table columns.
Hovering over data points displays values formatted as currency (e.g., "$1,350" instead of "1350").
10.11 Practical examples
Nanoplots shine when they combine multiple techniques like autoscaling for valid comparisons, reference elements for context, custom styling for clarity, and meticulous positioning for narrative flow. These examples demonstrate complete workflows that bring together the concepts covered in this chapter.
10.11.1 Sparkline summary table
This example combines monthly summary statistics with daily price trend sparklines, providing both high-level metrics and visual context:
This financial summary table combines key statistics with a visual representation of daily price movements. The sparkline provides trend context that complements the summary figures.
10.11.2 Distribution comparison table
Box plot nanoplots are great at comparing distributions across groups, revealing differences in central tendency, spread, and outliers:
Box plots reveal distributional differences between treatments (not just central tendency but spread and outliers). The shared scale (via autoscale) enables valid visual comparison.
10.11.3 Multi-metric dashboard row
This dashboard-style table demonstrates how multiple nanoplot columns with different plot types and color schemes can work together to tell a comprehensive story:
This dashboard-style table uses color-coded nanoplots to show multiple metrics per server. Line plots suit the percentage metrics while bar plots work well for discrete request counts.
Nanoplots transform tables from static data presentations into dynamic visual summaries. By embedding trend lines, distributions, and comparisons directly within table rows, they enable readers to grasp patterns at a glance while retaining access to precise numeric values. The extensive customization options ensure that nanoplots can be tailored to match any design aesthetic or analytical purpose.
10.12 Summary
This chapter has explored nanoplots: compact visualizations that embed directly within table cells, bridging the gap between tabular precision and visual pattern recognition.
The key capabilities we’ve covered:
plot types: line plots show trends over time or sequence, bar plots display discrete comparisons, and box plots summarize distributions. Each type serves different analytical purposes.
the cols_nanoplot() function creates a new column of visualizations from numeric data in existing columns. It handles data collection, plot generation, and column placement automatically.
data formats: nanoplots accept data as separate columns, comma-separated strings within cells, or explicit x-y value pairs. This flexibility accommodates various data structures.
reference elements: reference lines and reference areas add context to plots, showing targets, thresholds, or acceptable ranges that help readers interpret the visualizations.
customization: the nanoplot_options() helper provides extensive control over colors, sizes, strokes, and display elements. You can match nanoplots to your table’s overall design aesthetic.
missing data handling: the missing_vals argument controls how gaps appear in plots (as breaks, markers, zeros, or removed points).
autoscaling: when comparing across rows, autoscale = TRUE ensures all plots share the same axis ranges, making visual comparisons meaningful.
Nanoplots work best when they complement rather than replace numeric values. A trend line next to quarterly figures helps readers see the trajectory. A distribution box plot alongside summary statistics reveals shape. The combination of numbers and graphics creates tables that inform at multiple levels of detail.
The next chapter introduces table groups, which let you work with multiple related tables as a cohesive unit. You’ll learn to bundle tables together, apply common styling, and output them as coordinated sets.