# News

_If you are viewing this file on CRAN, please check the
[latest NEWS](https://grantmcdermott.com/tinyplot/NEWS.html) on our website
where the formatting is also better._

## Development version

### New features

#### New plot types

- `type_hexbin()` (equivalently, `type = "hexbin"`) for hexagonal bin plots, a
  2D analogue of a histogram. (#667 @grantmcdermott)

#### Other new features

- Custom plot types have more control over the surrounding plot machinery, via a
  new `type_hints` mechanism. A type can declare properties about itself---that
  it draws its own axes, needs a secondary right-hand axis, uses proportional
  limits, fills its legend key from `col`, and so on---and **tinyplot** adjusts
  margins, axis limits and legend keys accordingly. Previously this behaviour was
  hard-coded against the names of built-in types, so it was unavailable to custom
  types. See
  [Advanced customization](https://grantmcdermott.com/tinyplot/vignettes/types.html#type-hints)
  in the `Types` vignette for the list of supported hints. (#543 @grantmcdermott)
- New `axes` argument for `facet.args`, giving explicit control over which facets
  draw their own axes: `"all"`, `"outer"` (drop redundant interior axes), or
  `"none"`. Previously this was only achievable as a side effect of
  `frame.plot = FALSE`, so `facet.args = list(axes = "outer")` now allows
  redundant axes to be dropped while *keeping* the facet frames. (#661, #673
  @grantmcdermott)
  - The same behaviour can be set globally via the new `facet.axes` parameter
    (note the reverse order), e.g. `tpar(facet.axes = "outer")`, which also
    makes it available to themes. A per-call `facet.args = list(axes = ...)`
    takes precedence over the global setting, which in turn takes precedence
    over the old frame-based inference.
  - Accordingly, themes with L-shaped axes (`"classic"`, `"socviz"`, `"tufte"`,
    and `"float"`) now default to `facet.axes = "outer"` so that they drop the
    redundant interior axes of faceted plots.
- `type_density()` gains an `echo.bw` argument for reporting the smoothing
  bandwidth and the number of observations behind it, neither of which is
  visible from the curve itself. Destinations are `"sub"`, `"cap"`, and
  `"cat"` (console), in any combination; a destination the user has already
  labelled is left alone. Shared bandwidths are reported once and named as
  joint, individual bandwidths per group. (#287 @haomeng797-ship-it)

### Bug fixes

- `flip = TRUE` now flips the drawn geometry of the single-letter line types,
  not just the axes: `type = "h"` draws horizontal segments to the baseline,
  and the step types `"s"` and `"S"` swap which coordinate moves first.
  (#675 @haomeng797-ship-it)
- Fixed several bugs specific to plots with free facets (i.e.,
  `facet.args = list(free = TRUE)`):
  - Single-valued discrete axes no longer trigger invalid `par(usr)` values.
    (#668 @grantmcdermott)
  - User-provided `x/ylim` overrides now work correctly with flipped plots.
    (#670 @grantmcdermott)
  - Axes now inherit the same themed `cex`, `lwd` and `lty` as their fixed-scale
    counterparts. Previously the free-facet code path built its axis calls by
    hand and so silently ignored `cex.axis`, `lwd.axis` and `lty.axis` (plus
    their per-side variants), which was most visible under themes that set them,
    e.g. `tinytheme("bw")`. (#673 @grantmcdermott)
- Grouped and faceted plots no longer redraw axes once per empty group. This was
  most visible for `"spineplot"` types (e.g. `facet = "by"`), where the
  self-drawn axis labels were overplotted several times and rendered too heavy.
  (#637 @grantmcdermott)
- Fixed several bugs in how faceted plots draw their axes. These were most
  visible for `"spineplot"` and `"ridge"` types, which draw their own axes and so
  bypassed the shared outer-axis logic, but some affected other types too.
  (#660, #661 @grantmcdermott)
  - Redundant interior axes are no longer drawn when the plot is frameless (e.g.
    `tinytheme("clean2")`), where the category labels previously spilled into the
    neighbouring facet.
  - Category labels no longer overlap the neighbouring facet under framed themes
    (e.g. `tinytheme("clean")`). The tick-label width was only reserved once, in
    the outer margin, which is correct only when a single facet draws that axis.
  - Flipped plots (e.g. `type = "boxplot", flip = TRUE`) no longer duplicate the
    category axis while omitting the interior x-axes, which had left facets
    labelled against a neighbour's scale.
  - `axes = "t"` (and other tick-style axes) no longer drop the interior facet
    labels.
- Univariate `y ~ 1` formulas no longer silently drop explicitly-typed layers,
  e.g. `tinyplot(body_mass ~ 1, data = penguins)` followed by
  `tinyplot_add(type = type_vline(4500))`. The x-axis swap these formulas
  require was only applied when the type had to be inferred, so an explicit type
  was mistaken for an empty plot and never drawn. (#647 @grantmcdermott
  @zeileis)

## v0.7.0

**tinyplot** v0.7.0 is a big release with many new features, including major
updates to our theming logic and aesthetic stylings. Related updates are grouped
below for easier navigation.

### Aesthetic changes

A major focus of v0.7.0 is bringing various aesthetic improvements to 
**tinyplot**. These aesthetic improvements should carry over to all of your
(tiny)plots automatically and do not require any changes to user-facing inputs 
or the core API. From that perspective they are not a breaking change, even
though some of your plots may look slightly different from before. Still, we
hope that you agree the following changes result in better looking
visualizations:

#### Legend aesthetics

- Legend titles and labels are now left-justified by default for the (vertical)
  side-positioned legends like `"right!"` and `"left!"`. This is a minor visual
  change from the previous default of centered legends, which we inherited from
  base R. However, users can still override this behaviour with the new `ljust`
  parameter, which accepts values of `"l(eft)"` (new default) or `"c(enter)"`
  (old default). (#500 @grantmcdermott)
  - Example: Override globally by setting `tpar(ljust = "c")`, or revert for a
    single plot by passing the parameter as part of the legend list arguments,
    i.e. `plt(..., legend = list(ljust = "c"))`.
- Direct legend labels are now supported via the new `legend = "direct"`
  keyword. This places the legend labels at the last observation of each data
  group and is thus best suited to line or ribbon plots, where the data is
  sorted along the x-axis. (#587 @grantmcdermott)
  - Note: The plot (facet) RHS margin is automatically expanded to prevent text
    clipping of these direct legend labels. However, the labels themselves may
    still overlap. Users can prevent this by passing helper arguments to the
    legend constructor: either `repel` (for automatic vertical separation) or
    `nudge_x`/`nudge_y` (for manual per-group offsets). For example,
    `plt(..., legend = list("direct", repel = TRUE))`.

#### Theme aesthetics

We have significantly refactored our _dynamic_ themes logic. Recall, these are
themes like `"dynamic"`, `"clean"`, `"bw"`, etc. that automatically adjust
margin spacing and related plot elements to reduce whitespace and improve the
overall plot aesthetic. The `?tinytheme` help file and online
[Themes](https://grantmcdermott.com/tinyplot/vignettes/themes.html) vignette
cover the new features in detail. But see below for the highlights.
(#549, #591, #595, #606, #614 @grantmcdermott, @vincentarelbundock, @zeileis)

New theme features:

- `tinytheme()` now accepts additional `gap.axis` and `gap.lab` "primitives",
  providing finer control for spacing between ticks-to-labels and
  labels-to-titles, respectively, in dynamic themes. (#590 @grantmcdermott)
- Similarly, `tinytheme()` also accepts `gap.main` and `gap.sub` primitives
  for controlling the spacing between titles and the plot region.
  (#595 @grantmcdermott)
- Existing theme refinements and improvements. (#595, #603 @grantmcdermott).
  - `"tufte"` and `"void"` are now dynamic (responsive margins).
  - All of the `ggplot2`-inspired themes (`"bw"`, `"classic"`, etc.) now use
    smaller axis text and tighter spacing to better match their upstream
    `ggplot2` counterparts.
  - `"ipsum"` has been similarly overhauled to match the upstream theme (bold
    title, no ticks, fine grid, custom palette). Our original `tinyplot` variant
    is preserved as `"ipsum2"` for those who still want to use it.
  - `"dark"` now uses a better default `ribbon.alpha` for better contrast
    against the black background.
- Added several new themes. (#595, #606 @grantmcdermott)
  - `"dynamic"` (new foundation for all other dynamic themes)
  - `"broadsheet"` (data journalism style _à la_ _The Economist_ or _NY Times_)
  - `"float"` (floating axes; a variant of `"tufte"`)
  - `"linedraw"` (based on the `ggplot2` theme)
  - `"nber"` (NBER working paper style)
  - `"socviz"` (based on Kieran Healy's [book](https://socviz.co/))
  - `"web"` (web publication, e.g. FiveThirtyEight)
- New `tinytheme_register()` function for registering custom user themes.
  Registered themes inherit from any built-in (or previously registered) theme,
  apply user-specified overrides, and can then be used by name with
  `tinytheme(<theme>)` or `tinyplot(..., theme = <theme>)`. Companion functions
  `tinytheme_list()` and `tinytheme_unregister()` further support this
  functionality. (#608 @grantmcdermott)
- We adopt a new logic for selecting the default colour for single-group
  (i.e. plots without a `by` grouping) versus multi-group displays. The upshot
  is that, for many themes, single-group displays will simply default to
  "black", whereas multi-group displays will drop "black" and only present
  colour palettes. This behaviour is operationalized through the new
  `col.default` parameter, settable via `tpar()` or within a theme.
  (#614 @grantmcdermott @zeileis)
  - Themes whose palette already leads with a non-black colour (e.g.
    `"clean(2)"`, `"dark"`, `"nber"`, `"web"`) consistently use that colour for
    single-group displays too.
  - The ggplot2-inspired themes (`"bw"`, `"classic"`, `"linedraw"`, and
    `"minimal"`) continue to use black for single-group display. But they now
    drop the leading black from their _grouped_ palettes. (Note that these
    themes also use the default `"ggplot2"` palette now, so grouped plots start
    at the familiar salmon hue.)
  - Similarly, the `"ipsum2"` and `"broadsheet"` themes use the
    Okabe-Ito palette less its leading black, so grouped plots start at orange.
    The `"float"` and `"void"` themes also default to black for single-group
    displays.
- Relatedly, the _fill_ of single-group `"boxplot"`, `"violin"`, `"barplot"`,
  and `"histogram"` displays is now unified across these four types, so that a
  single-group plot looks the same regardless of which one you reach for.
  (#614 @grantmcdermott @zeileis)
  - When the resolved default colour is _chromatic_ (e.g. the blue of `"clean"`
    or the teal of `"dark"`), the fill is a lighter-but-opaque tint of it;
    following the same sequential HCL ramp that `"ridge"` type plots have been
    using for a while.
  - When the default is _achromatic_ (black, as in the plain default and the
    `"bw"`/`"classic"`/`"ipsum"` themes), all four types share a neutral
    `"lightgray"` fill, matching base R's `hist()` and `boxplot()` defaults.
    Note that this does imply a change for `"barplot"` types, which previously
    used a slightly darker `"grey"` (to match base R's `barplot()`), but we
    decided internal consistency was the more important feature to prioritize.
- Building on the above, _multi-group_ `"boxplot"`, `"violin"`, and `"barplot"`
  displays now also use the lighter-but-opaque fill, so that grouped plots match
  their single-group counterparts (previously grouped barplots used dark
  saturated fills and grouped boxplots/violins used semi-transparent fills). Each
  type gains a `lighten` argument (default `TRUE`); set
  `type_barplot(lighten = FALSE)` (etc.) to recover the fully-saturated palette
  colours. `"histogram"` is deliberately excluded, since semi-transparency
  remains preferable for overlapping grouped distributions. `"spineplot"` also
  gains a `lighten` argument (only relevant for the `y == by` case), but defaults
  to `FALSE` (saturated fills): its tiles abut one another with no gap, so the
  darker fills read better against their matching border colours.
  (#646 @grantmcdermott @zeileis)
  - Relatedly, transparency requested via `fill` or `alpha` is now layered _on
    top of_ the (lightened) fill rather than the saturated base colour. This
    fixes a counterintuitive case where adding an alpha fill (e.g. `fill = 0.7`)
    could _darken_ the interior of an area-based plot.

Theme fixes:

- Plot margins now correctly respond to missing and/or multi-line `main`,
  `sub`, and `x`/`y` axis titles. For example, a plot without a `main` (or
  `sub`) title will expand to the top of the device region to reduce excess
  whitespace. (#303)
- Left-justified `main` and `sub` titles now correctly anchor to the y-axis
  line, even when long horizontal tick labels widen the left margin. (#479)
- Similarly, center-justified axis titles are now anchored on the relevant
  axis alone, rather than the full plot region. (#573)
- `cex.xlab` and `cex.ylab` now correctly control axis title size. The
  more general `cex.lab` is still respected as a fallback. (#574)
- Margin spacing now correctly adjusts for math expressions, including
  fractions and exponents in titles. (#575)
- Dynamic margins and `mgp` now scale correctly with `cex.axis` and
  `cex.lab`, maintaining constant visual gaps between axis elements
  regardless of text size. From the user perspective, this is
  operationalized through the new `gap.axis` and `gap.lab` theme
  primitives, which let you control the spacing between margin elements
  directly (tick-to-label gap and label-to-title gap, respectively),
  replacing the guesswork of manually combining `mar`, `mgp`, and `tcl`
  values. (#590)
- The gap between y-axis tick labels and the y-axis title is now
  constant regardless of label width (1-digit, 2-digit, decimals, etc.).
  Previously the gap varied at the narrow/wide label boundary. (#596)
- New `gap.main` and `gap.sub` theme primitives control the spacing
  between titles and the plot box. `gap.main` sets the gap from the main
  title to whatever is below it (plot box or subtitle top); `gap.sub`
  sets the gap from the subtitle to the plot box. Both default to `0.7`.
  (#597)
- Dynamic themes now play nicely with `legend = "top!"`. The title,
  subtitle, and legend stack correctly above the plot region with proper
  spacing. (#605)

### New features

#### New plot types

- `type_chull()` (equivalently, `type = "chull"`) for drawing convex hulls
  around grouped points. Uses `grDevices::chull()` under the hood and delegates
  drawing to `draw_polygon()`. Works well as a layer on top of points, e.g.
  `plt_add(type = "chull", fill = 0.2)`. (#600 @grantmcdermott)
- `type_ellipse()` (equivalently, `type = "ellipse"`) for drawing confidence
  ellipses around grouped points. Like `type_chull`, works well as a filled
  layer, e.g. `plt_add(type = "ellipse", fill = 0.2)`. (#610 @grantmcdermott)

#### New `tinyplot.*` methods

- `tinyplot.data.frame()`: Supports direct plotting of data frames, alongside
  the new top-level function `tinypairs()`. Can be called with or without a
  formula. One benefit of the former is that it facilitates piping, e.g.
  
  ```r
  iris |> plt(Sepal.Length ~ Petal.Width | Species)
  ```
  
  If no formula is provided, then the behaviour depends on the number of
  variables (columns) in the data frame. For example, a dataset with 3 or more
  variables will yield a `pairs()`-style grid of all variable combinations. 
  Thanks to @mthulin for the suggestion and original implementation idea.
  (#613, #640 @zeileis @grantmcdermott)
- `tinyplot.matrix()`: for `matrix` objects, e.g.
  
  ```r
  plt(VADeaths, type = "b")
  ```

  The output largely mimics the base `matplot`/`matlines` equivalents, but with
  additional **tinyplot** functionality related to automatic legends, options
  for faceting, etc. (#649 @grantmcdermott)
- `tinyplot.ts()`: for `ts` time series, e.g.
  
  ```r
  plt(EuStockMarkets)
  ```
  
  Produces a line plot by default, although users can override by passing an
  explicit `type` argument. Similarly, multivariate series are faceted by
  default, but users can also override to obtain, say, a single frame with
  direct labels. (#558 @zeileis @grantmcdermott)

#### Other new features

- New and updated top-level `tinyplot()`/`plt()` arguments:
  - `cap = <string>` for adding a caption to your plots. Captions are drawn at
    the bottom of the plot and are best paired with dynamic themes (since
    separation from `sub` is guaranteed). Appearance is customizable via
    `tpar()` parameters: `adj.cap`, `cex.cap`, `col.cap`, `font.cap`, and
    `line.cap`. (#592 @grantmcdermott)
  - `weights = <varname>` for adding weights to statistical transformations.
    Supported types are models (`type_lm()`, `type_glm()`, `type_loess()`) and
    distributions (`type_density()`, `type_histogram()`, `type_spineplot()`). A
    warning is emitted if `weights` is passed to an unsupported type and the
    argument is also ignored. The top-level `weights` argument supports
    non-standard evaluation (NSE) in the formula method, so that bare column
    names can be passed for convenience. Users can also pass a weights argument
    directly at the type-specific function level, but this must be a vector
    of correct length (no NSE). For example:
    
    ```r
    plt(y ~ x, data = dat, type = "lm", weights = w)        # top-level, NSE
    plt(y ~ x, data = dat, type = type_lm(weights = dat$w)) # type-level, vector
    ```
    
    In addition to NSE convenience, the top-level variant is preferred since it
    is correctly matched to the model frame construction with the formula method
    (e.g., so missing values are handled automatically). Thanks to @eleuven for
    the original suggestion, as well as various discussion participants for
    helping to frame the scope. (#639 @grantmcdermott)
  - `labels = <varname>` for passing labels to `type = "text"`. Like the new
    `weights` argument (above), the main benefit is the convenience of NSE, as
    well as the automatic handling of missing values and subsets as part of the
    model frame construction. For example, compare:
    
    ```r
    plt(y ~ x, data = dat, type = "text", labels = labs, subset = x < 10)
    plt(y ~ x, data = subset(dat, x < 10), type = type_text(labels = subset(dat, x < 10)$labs))
    ```
    The `labels` arg is silently ignored for non-text types.
    (#639 @grantmcdermott)
  - The `grid` argument (and `tpar("grid")`) now accepts character strings to
    control axis-specific grids at different resolutions. Uppercase letters
    (`"X"`, `"Y"`, `"XY"`) draw grid lines at the standard tick positions, while
    lowercase letters (`"x"`, `"y"`, `"xy"`) draw a finer grid with additional
    lines at the midpoints between ticks. Thanks to @zeileis for the suggestion.
    (#578 @grantmcdermott)
  - Facet formulas now support `1` as a convenience syntax for single row or
    column arrangements. (#562 @zeileis)
    - `plt(..., facet = z ~ 1)` <-> `plt(..., facet = ~z, facet.args = list(ncol = 1))`
    - `plt(..., facet = 1 ~ z)` <-> `plt(..., facet = ~z, facet.args = list(nrow = 1))`.
  - `x/ylim` gain several "smart" override forms. (#644 @grantmcdermott)
    - A single scalar (e.g. `ylim = 0`) ensures that value is covered by the
      axis range, e.g. for forcing zero onto a coefficient plot.
    - A length-2 vector with one `NA` (e.g. `ylim = c(0, NA)`) pins the non-`NA`
      limit and lets the data determine the other.
    - The string `"rev"` (or `"reverse"`) reverses the auto-computed axis range,
      without needing to know the data extent in advance.
- Type-specific updates:
  - `type_barplot()` gains an `offset` argument for shifting bar baselines away
    from zero. (#611, #615 @grantmcdermott @zeileis)
    - If the offset is an unnamed scalar or numeric vector, it shifts the bars
      positionally by the given values. Useful for creating waterfall plots and
      floating bars.
    - If the offset is a character or named numeric vector, it instead "sets
      aside" the named level(s) of the `by` group, pulling them out of the stack
      and drawing them as standalone bars. This is useful for Likert plots,
      where you want to show a neutral category (e.g., "Unsure") apart from
      the diverging stack. Thanks to @strengejacke for the suggestion.
  - `type_text()` gains two new arguments:
    - a `labeller` argument that is passed to `tinylabel()` for formatting the
      text labels. (#620 @grantmcdermott)
    - a `repel` argument that automatically nudges overlapping text labels
      apart. One limitation is that the repulsion logic operates within groups.
      So there may still be some overlapping text for grouped data.
      (#621 @grantmcdermott)
  - Model-fit and various distribution types gain a `weights` argument; although
    this is best provided from the top-level `tinyplot()`/`plt()` call. See
    above.
- `legend = list(title = FALSE)` now suppresses the legend title, matching the
  existing `title = NULL` behaviour. (#653 @grantmcdermott)

### Bug fixes

- Fixed `grid = grid()` not drawing grid lines on all facets. That said, logical
  or character inputs (e.g., `grid = TRUE`, `grid = "xy"`) remain the more
  idiomatic way to generate a background grid in `tinyplot`.
  (#193 @grantmcdermott)
- Fixed margin spacing for free facets with different axis scales. The dynamic
  margin adjustment now computes tick labels per-facet and sizes the margin to
  accommodate the widest labels. (#579 @grantmcdermott)
- Fixed several minor issues related to facet title strips and spacing: Strips
  and spacing now scale correctly with `facet.cex`; inter-panel gaps for
  multiline facet titles remain fixed regardless of strip height; and strip
  text is now vertically centered within the background rect.
  (#586 @grantmcdermott)
- Fixed Issue #593 where `palette.qualitative` in themes could not be a
  function. Thanks to @katrinabrock for the report. (#594 @zeileis)
- Polygon density hatching lines now correctly use the group colour instead of
  black. Affects `type_polygon`, `type_chull`, and `type_ellipse` when
  `density` is set. (#610 @grantmcdermott)
- Fixed inconsistent decimal places in the `tinylabel()` currency and comma
  formatters (e.g., `"$"`, `"€"`, `"£"`, `","`). These now use a consistent
  number of decimal places across the whole vector, matching the existing
  behaviour of the percent formatter. The currency formatters additionally show
  at least two decimal places whenever a fractional component is present (e.g.
  `"$0.50"` rather than `"$0.5"`), while still keeping clean integers
  integer-valued (e.g. `"$1,000"`), and place the negative sign in front of the
  currency symbol (e.g. `"-$1.50"` rather than `"$-1.50"`).
  (#618, #623 @grantmcdermott)
- Fixed `xlab = NA` / `ylab = NA` gotchas for `"barplot"`, `"spineplot"`, and
  `"ridge"` types. (#635, #650 @grantmcdermott)
- `tinyplot_add()` (`plt_add()`) now captures its arguments unevaluated, so
  arguments that rely on non-standard evaluation against `data` (e.g.,
  `plt_add(..., subset = <>)`) resolve correctly instead of erroring with 
  "object not found". (#638 @grantmcdermott)
- `plt(..., ann = FALSE)` correctly turns off title annotations now, fixing a
  regression that we missed from at least v0.6.0. Thanks to @bastistician for
  the report. (#641 @zeileis)
- Fixed `bquote()` (and other unevaluated language) annotations such as `main`,
  `sub`, `cap`, `xlab`, and `ylab` being evaluated instead of coerced to
  plotmath expressions, e.g. `plt(0, 0, main = bquote(foo == .(pi)))`. Thanks 
  (again) to @bastistician for the report. (#642 @grantmcdermott)
- Line plots (`type = "l"`, and relatives like `"b"`/`"o"`) with a factor or
  character `x` variable now draw the category labels on the x-axis, matching
  the behaviour of point plots. Previously these tick labels were only shown
  when dodging was active. (#648 @grantmcdermott)
- The "Continuous legends not supported for this plot type" warning no longer
  fires when the legend is suppressed, e.g. `legend = FALSE`.
  (#656 @grantmcdermott)

## v0.6.1

### Aesthetic changes

- The legend plot characters for the `"pointrange"` and `"errorbar"` types now
  include a line, to better resemble the actual plot elements (#533 @grantmcdermott)

### New features

- Support for univariate formulas, e.g., `y ~ 1`, `~ x`, and `~ 0`. These are
  translated to `x = NULL` or `y = NULL` in the default method call, with
  automatic type inference: `y ~ 1` (numeric) produces a histogram, `y ~ 1`
  (factor) produces a barplot, `~ x` (factor) produces a barplot, and `~ x`
  (numeric) produces a scatterplot against the index. The `~ 0` form is useful
  for types that don't require x/y, such as `segments` and `rect`. Thanks to
  @katrinabrock for the suggestion. (#534 @zeileis @grantmcdermott)

### Bug fixes

- Fixed Issue #545 where xaxs/yaxs were not restored when set by an internal
  function. (#545 @zeileis)
- Fixed Issue #553 where `facet.args = list(free = TRUE)` lead to an error
  when used without facets. Thanks to @katrinabrock for the report.
  (#554 @zeileis)
- Fixed `type_ridge()` fill errors for themes that set a qualitative palette,
  e.g. `"clean2"`. (#564 @grantmcdermott)
- Fixed plot clipping when using ephemeral `theme = "default"` with a legend
  and `tinyplot_add()`. Thanks to @katrinabrock for the report in #557.
  (#565 @grantmcdermott)
- Several improvements/fixes to jittered plots and layering:
  - Jittered plots now support Date/POSIXt axes. Thanks to @wachtermh for the
     bug report and @vincentarelbundock for the code contribution. (#327)
  - `tinyplot_add(type = "jitter")` no longer errors when layered on top of
    boxplot, violin, or similar categorical plot types. (#560 @grantmcdermott)
  - Jitter layers added via `tinyplot_add()` now align correctly with grouped
    (offset) boxplot, violin, and ridge base layers. (#561 @grantmcdermott)

### Documentation

- Improved guidance for
  [custom types](https://grantmcdermott.com/tinyplot/vignettes/types.html#custom-types)
  in the `Types` vignette. (#531 @grantmcdermott)

### Internals

- We now encourage type-specific legend customizations within the individual
  `type_<type>` constructors. (#531 @grantmcdermott)
- Change maintainer email address.
- Add `.CLAUDE.md` context file for AI-assisted development. (#563 @grantmcdermott)
- Quality of life website improvements. (#566 @grantmcdermott)
  - Fix Makefile website target (remove circular dep, fix comment)
  - Enable parallel + freeze for faster local builds
  - Replace iconify extension with native Bootstrap icon for Bluesky
- Add GitHub Actions workflow for reverse dependency checks. Triggered by
  pushing a `revdep*` branch. (#567 @grantmcdermott)

## v0.6.0

### Breaking changes

- "Breaking" change for internal development and custom types only:
  The plot settings and parameters from individual `tinyplot` calls are now
  stored in a dedicated (temporary) internal environment called `settings`,
  which can be accessed and modified by type-specific functions. This change
  will enable various internal enhancements, from improving the modularity and
  maintainability of the `tinyplot` codebase, to reducing memory overhead and
  performance (since we require fewer object copies). Looking ahead, we also
  expect that it will make it easier to support new features and integration 
  with downstream packages. Most `tinyplot` users should be unaffected by these
  internal changes. However, users who have defined their own custom types will
  need to make some adjustments to match the new `settings` logic; details are
  provided in the updated `Types` vignette. (#473 @vincentarelbundock and @grantmcdermott)
- The ancillary `fixed.pos` argument for dodged plots has been renamed to
  `fixed.dodge` to avoid ambiguity, especially when passed down from a top-level
  `tinyplot(...)` call. (#528 @grantmcdermott) 

### New features

- `type_text()` gains a `family` argument for controlling the font family,
  separate to the main plot text elements. (#494 @grantmcdermott)
- Expanded `dodge` argument capabilities and consistency for dealing with
  overlapping groups:
  - `dodge` argument now also supported by `type_lines()`, `type_points()`, and
    `type_ribbon()`. (#522, #528 @grantmcdermott)
  - We now enforce that numeric `dodge` values must be in the range `[0,1)`.
    (#526 @grantmcdermott)
  - Alongside numeric values, we now support a logical `dodge = TRUE` argument,
    which gives automatic width spacing based on the number of groups. (#525 @grantmcdermott)
  - Renamed ancillary argument `fixed.pos` -> `fixed.dodge`, per the breaking
    change above. (#528 @grantmcdermott)

### Bug fixes

- For bubble plots, we now drop the minimum legend category (label) if it is
  equal to 0. The previous behaviour was just an artifact of the `pretty` breaks
  algorithm that we use to create discrete legend categories. The interior plot
  elements, e.g. bubble points, are unaffected. (#498 @grantmcdermott)
- `type_text()` now defaults to displaying `y` values if an explicit `labels`
  arg is not provided, mirroring the behaviour of the base `text()` function.
  (#501 @grantmcdermott)
- Determining the last call of the `tinyplot()` generic in preparation for
  `tinyplot_add()` is now more robust so that it is compatible with `do.call()`
  again (reported by @FlorianSchwendinger). This is achieved by inspecting
  the functions called rather than just their names. (#504 @zeileis)
- Legend labels are now correct if `by` is logical. Thanks to @TCornulier for
  the report. (#512 @grantmcdermott)
- Axis limits are now correctly calculated for factor (and character) variables,
  by coercing to numeric first. We also avoid the redundancy of re-calculating
  axis limits for secondary plot layers. (#513 @grantmcdermott)
- Fixed lazy evaluation bug where `legend` passed as a symbol through S3 methods
  (e.g., `tinyplot.foo`) would fail. (#515 @grantmcdermott)
- Added layers, particularly from `tinyplot_add()`, should now respect the
  x-axis order of the original plot layer. This should ensure that we don't end
  up with misaligned layers. For example, when ribbon is added on top of an
  errorbar plot. (#517, #520, #523, #526 @grantmcdermott)
- Custom axis titles work properly for one-sided (formula) bar plots. Thanks to
  @lbelzile for the report in #423. (#527 @grantmcdermott)


### Documentation

- Add a "recession bars" section to the `Tips & tricks` vignette.
  (#503 @grantmcdermott)

- Point out more explicitly how the `draw` argument is evaluated within
  `tinyplot()` and that it thus has access to the local definition to all
  variables such as `x` and `y` etc. (#507 @zeileis)

## v0.5.0

### New features

- Added support for "bubble" scatter plots, allowing for point size scaling via
  an appropriate `cex` argument (e.g., a continuous variable from your dataset).
  Simultaneously enables dual-legend support for combined size + color mappings.
  The updated `?type_points` documentation contains several examples.
  (#433 @grantmcdermott)
- Improved horizontal legend spacing, as well as multicolumn legend support. A
  new example in the "Tips & tricks" vignette demonstrates the latter.
  (#446 @grantmcdermott)
- Univariate boxplots (without grouping variable) are now handled in
  `tinyplot.default()`, so that `tinyplot(x, type = "boxplot")` and
  `tinyplot(~ x, type = "boxplot")` essentially produce the same output as
  `boxplot(x)`. (#454 @zeileis)
- `type_errorbar()` and `type_point_range()` get a `dodge` argument.
  (#461 @vincentarelbundock)
- The new `tinyplot(..., theme = <theme>)` argument enables users to invoke
  ephemeral themes as an alternative to the persistent themes that follow
  `tinytheme(<theme>)`. (#484 @grantmcdermott)
- Similarly to how the `x/yaxl` arguments allow for axes label adjustment, users
  can now adjust the legend labels too with
  `tinyplot(..., legend = list(labeller = <labeller>))`. The `labeller` argument
  is passed to `tinylabel`; see the latter's help documentation for examples.
  (#488 @grantmcdermott)

### Bug fixes

- `tinyplot_add()` now evaluates the additional call in the environment from
  which `tinyplot_add()` is called so that it also works in non-base environments
  such as in function definitions. Additionally, the call matching is now more
  precise, matching only `tinyplot()` or `plt()` or their fully-qualified
  counterparts (with `tinyplot::` prefix). Finally, the internals where these
  calls are stored are streamlined, avoiding modifying the user-visible
  `options()`. (#460 @zeileis)
- Fixed several minor `tinylabel` bugs. (#468 @grantmcdermott)
  - `tinylabel(x, "%")` is more precise, preserving unique levels of `x` through
     automatic decimal level determination. Thanks to @etiennebacher for the
     bug report in #449.
  - Numeric labellers now work on appropriate `x`/`y` variables, even if the
    plot type internally coerces it to factor (e.g., `"boxplot"`)
- `type_text()` can now also deal with factor `x`/`y` variables by converting
  them to numeric which helps to add text to barplots etc. (#470 @zeileis)
- Fixed some `tinytheme()` bugs.
  - Sourced (non-interactive) scripts with `tinytheme()` calls now inherit the
    correct parameters and spacing. (#475, #481 @grantmcdermott)
  - Custom `cex` theme settings are now reset correctly. (#482 @grantmcdermott)

### Documentation

- @grantmcdermott's _useR! 2025_ **tinyplot** presentation has been added to the
  website as a standalone
  [vignette](https://grantmcdermott.com/tinyplot/vignettes/useR2025/useR2025.html).

### Internals

- Move `altdoc` from `Suggests` to `Config/Needs/website`.
  Thanks to @etiennebacher for the suggestion and to @eddelbuettel for help
  with the CI implementation.
- Add a `devcontainer.json` file for remote testing. (#480 @grantmcdermott) 

## v0.4.2

### New features

- `type_text()` gains `xpd` and `srt` arguments for controlling text clipping
  and rotation, respectively. (#428 @grantmcdermott)
- Add `xlevels` (in addition to `ylevels`) in `type_spineplot()` for spine plots
  with categorical `x` variable. (#431 @zeileis)

### Bug fixes

- Fixed a long-standing issue whereby resizing the plot window would cause
  secondary plot layers, e.g. from `plt_add()`, to become misaligned in 
  faceted plots (#313). This also resolves a related alignment + layering issue
  specific to the Positron IDE
  ([positron#7316](https://github.com/posit-dev/positron/issues/7316)).
  As an aside, `tinyplot` should now be fully compatible with Positron. (#438 @grantmcdermott)
- Fixed a bug that resulted in y-axis labels being coerced to numeric for
  `"p"`-alike plot types (including `"jitter"`) if `y` is a factor or character.
- Safer handling of pre-plot hooks. Resolves an issue affecting how `tinyplot`
  behaves inside loops, particularly for themed plots where only the final plot
  was being drawn in Quarto/RMarkdown contexts. Special thanks to @hadley and @cderv
  for helping us debug. (#425 @vincentarelbundock)
- The `xlevels` argument of `type_barplot()` could not handle numeric indexes correctly.
  (#431 @zeileis)
- Addressed several shortcomings of the straight line family of types (`type_hline`,
  `type_vline`, `type_abline`) through better recycling logic. For example,
  these types now work correctly across non-`by` facets. Simultaneously, users
  can also call them in a base plot layer, relaxing the requirement that they
  must be called as part of a subsequent plot layer via `tinyplot_add()`. (#422 @grantmcdermott)

## v0.4.1

### Bug fixes

- Fix a narrow `tinytheme("ridge")` regression that was accidentally introduced in
  v0.4.0, which was causing a palette mismatch for gradient legends. (#415 @grantmcdermott)

### Misc

- Revert minimum compatible R version to 4.0.0 (#416 @grantmcdermott)

## v0.4.0

### New features:

#### New plot types

- `"barplot"` / `type_barplot()` for bar plots. This closes out
  one of the last remaining canonical base plot types that we wanted to provide
  a native `tinyplot` equivalent for. (#305 and #360 @zeileis and @grantmcdermott) 
- `"violin"` / `type_violin()` for violin plots. (#354 @grantmcdermott)

#### Other new features

- `tinyplot(..., file = "*.pdf")` will now default to using `cairo_pdf()` if
  cairo graphics are supported on the user's machine. This should help to ensure
  better fidelity of (non-standard) fonts in PDFs. (#311 @grantmcdermott)
- The `palette` argument now accepts a vector or list of manual colours, e.g.
  `tinyplot(..., palette = c("cyan4", "hotpink", "purple4"))`, or
  `tinytheme("clean", palette = c("cyan4", "hotpink", "purple4"))` (#325 @grantmcdermott)
- Two new sets of top-level arguments allow for greater axis customization:
  - `xaxb`/`yaxb` control the manual break points of the axis tick marks. (#400 @grantmcdermott)
  - `xaxl`/`yaxl` apply a formatting function to change the appearance of the
    axis tick labels. (#363, #391 @grantmcdermott)
    
  These `x/yaxb` and `x/yaxl` arguments can be used in complementary fashion;
  see the new (lower-level) `tinylabel` function documentation. For example:
  ```r
  tinyplot((0:10)/10, yaxb = c(.17, .33, .5, .67, .83), yaxl = "%")
  ```
- The `x/ymin` and `x/ymax` arguments can now be specified directly via the
  `tinyplot.formula()` method thanks to better NSE processing. For example,
  instead of having to write
  ```r
  with(dat, tinyplot(x = x, y = y, by = by ymin = lwr, ymax = upr))
  ```
  users can now do
  ```r
  tinyplot(y ~ x | by, dat, ymin = lwr, ymax = upr)
  ```
  
  Underneath the hood, this works by processing these NSE arguments as part of
  formula `model.frame()` and reference against the provided dataset. We plan to
  extend the same logic to other top-level formula arguments such as `weights`
  and `subset` in a future version of tinyplot.
  
### Bug fixes:

- The `tinyplot(..., cex = <cex>)` argument should be respected when using
  `type = "b"`. Thanks to @rjknell for report #307 and @vincentarelbundock for
  the fix.
- The `tinyplot(..., lwd = <lwd>)` argument is now correctly passed down to
  `pt.lwd` for type `"p"`, which sets proper line weight for the border of `pch`
  symbols in legend. Report in #319 and fix in #320 by @kscott-1.
- Passing `x` and/or `y` as character variables now triggers the same default
  plot type behaviour as factors, e.g. boxplots. (#323 @grantmcdermott)
- Scatter plots (`type_points()`/`"p"`) now work even if `x` or `y` is a factor
  or character variable. (#323 @grantmcdermott)
- The `tinyplot(..., col = <col>)` argument now accepts a numeric index.
  (#330 @grantmcdermott)
- `type_text()` now accepts non-character labels. (#336 @grantmcdermott)
- The `tinyplot(..., pch = <pch>)` argument now accepts character literals, e.g.
  `pch = "."`. (#338 @grantmcdermott)
- Line plots (`type_lines()`/`"l"`) now pass on the `bg` argument to the
  drawing function. Thanks to @wviechtb for report in #355 (@zeileis).
- Fixed dynamic y-axis margin spacing for flipped `"boxplot"` and `"jitter"`
  types. Thanks to @eddelbuettel for the report in #357 (@grantmcdermott).
- Fixed dynamic x-axis margin spacing for perpendicular (vertical) label text,
  i.e. cases where `las = 2` or `las = 3`. (#369 @grantmcdermott)
- Better integration with the Positron IDE graphics pane. Thanks to @thomasp85
  for the report and helpful suggestions. (#377, #394 @grantmcdermott)
  - The one remaining Positron issue at present is calling `plt_add()` on a
    faceted plot, but this appears to be an upstream limitation/bug
    [positron#7316](https://github.com/posit-dev/positron/issues/7316).
- Fixed a bug that resulted in y-axis labels being coerced to numeric for
  `"p"`-alike plot types (including `"jitter"`) if `y` is a factor or character.
  (#387 @grantmcdermott)
- Fix a colour recycling regression introduced in v0.3.0. Coincidentally, we
  have improved the consistency across `palette` and `col` arguments,
  particularly with respect to recycling behaviour. Thanks to @eddelbuettel for
  the report (#352) and @grantmcdermott for the fix (#410).

### Website:

- Improved column spacing of Arguments in the References section of the website.
  (#328 thanks to @etiennebacher's upstream `altdoc` fix)
- Added a new "Ticks & tips" vignette for non-standard workarounds.
  (#381 @vincentarelbundock)
- Improved website theme and navigation layout, especially on mobile.
  (#395, #411, #413 @zeileis and @retostauffer)

### Internals:

- The order of the nested loop for drawing interior plot elements has been
  switched. We now loop over facets first (outer loop) before looping over
  groups second (inner loop), rather than vice versa. The old/inverted nesting
  logic was mostly an artifact of development inertia and this new nesting logic
  should simplify the creation of certain plot types. (#331 @grantmcdermott)

## v0.3.0

### New features

**tinyplot** v0.3.0 is a big release with many new features, both internal and
user-facing. Related updates are grouped below for easier navigation.

#### Revamped `type` logic and functional equivalents

_(Primary PR and author: #222 @vincentarelbundock)_

- In addition to the standard character labels (`"p"`, `"density"`, etc.), the
  `type` argument now supports _functional_ equivalents (`type_points()`,
  `type_density()`, etc.). These new functional types all take the form
  `type_*()`.
- The character and functional types are interchangeable. For example,
  ```r
  tinyplot(Nile, type = "hist")
  ```
  and
  ```r
  tinyplot(Nile, type = type_hist())
  ```
  produce exactly the same result.
- The main advantage of the functional `type_*()` variants is that they offer
  much more flexibility and control beyond the default case(s). Users can pass
  appropriate arguments to existing types for customization and can even define
  their own `type_<typename>()` functions. More information is available in the
  dedicated help page for each type (e.g., `?type_hist`, `?type_lm`, etc.)
- On the development side, overhauling the `type` system has also allowed us to
  introduce a number of new plot types and features (see list below). We have
  also simplified our internal codebase, since explicit argument passing
  requires less guesswork on our end. Speaking of which, we now recommended that
  users explicitly pass ancillary type-specific arguments as part of the
  relevant `type_*()` call. For example,
  ```r
  tinyplot(Nile, type = type_hist(breaks = 30))
  ```
  is preferable to
  ```r
  tinyplot(Nile, type = "hist", breaks = 30)
  ```
  While the latter option will still work, we cannot guarantee that argument
  passing will work in every situation. (Reason: Passing ancillary type-specific
  arguments at the top level of the plot call only works if these do not
  conflict with the main arguments of the `tinyplot()` function itself; see
  #267.)
- Some minor breaking changes were unavoidable; see further below.
- For more details on the new `type` system, please see the dedicated
  [Plot types vignette](https://grantmcdermott.com/tinyplot/vignettes/types.html)
  on the website.

#### Support for additional plot types

  - Visualizations:
  
    - `type_spineplot()` (shortcut: `"spineplot"`) spine plots and
    spinograms. These are modified versions of a histogram or mosaic plot,
    and are particularly useful for visualizing factor variables. (#233
    @zeileis with contributions from @grantmcdermott)
    - `type_qq()` (shortcut: "qq") for quantile-quantile plots. (#251
    @vincentarelbundock)
    - `type_ridge()` (shortcut: `"ridge"`) for ridge plots aka Joy plots.
    (#252 @vincentarelbundock, @zeileis, and @grantmcdermott)
    - `type_rug()` (shortcut: `"rug"`) adds a rug to an existing plot. (#276
    @grantmcdermott)
    - `type_text()` (shortcut: `"text"`) adds text annotations. (@vincentarelbundock)
    
  - Models:
    - `type_glm()` (shortcut: `"glm"`) (@vincentarelbundock)
    - `type_lm()` (shortcut: `"lm"`) (@vincentarelbundock)
    - `type_loess()` (shortcut: `"loess"`) (@vincentarelbundock)
    - `type_spline()` (shortcut: `"spline"`) (#241 @grantmcdermott)
    
  - Functions:
    - `type_abline()`: line(s) with intercept and slope (#249 @vincentarelbundock)
    - `type_hline()`: horizontal line(s) (#249 @vincentarelbundock)
    - `type_vline()`: vertical line(s) (#249 @vincentarelbundock)
    - `type_function()`: arbitrary function. (#250 @vincentarelbundock)
    - `type_summary()`: summarize values of `y` along unique values of `x` (#274
    @grantmcdermott)

#### Themes

_(Primary PR and authors: #258 @vincentarelbundock and @grantmcdermott)_

- The new `tinytheme()` function provides a convenient mechanism for styling
  plots according to a variety of pre-defined themes, e.g. `tinytheme("clean")`.
- Users can also add their own custom themes or tweak an existing theme.
- Themes are persistent and will affect all subsequent plots until they are
  explicitly reset, e.g. by calling `tinytheme()` (with no argument) to restore
  the default plot aesthetic.
- Behind the scenes, `tinytheme()` sets a hook for a group graphical parameters
  by passing them through `tpar()`. Users can still use `tpar()` to style their
  plots manually by setting individual graphical parameters. But going forward
  we expect that most **tinyplot** users will prefer the convenience of going
  through `tinytheme()`.
- More details are provided in the dedicated
  [Themes vignette](https://grantmcdermott.com/tinyplot/vignettes/themes.html)
  on the website.

#### Other new features

- New `tinyplot()` arguments:
  -  `flip <logical>` allows for easily flipping (swapping) the orientation
  of the x and y axes. This should work regardless of plot type, e.g.
  `tinyplot(~Sepal.Length | Species, data = iris, type = "density", flip = TRUE)`.
  (#216 @grantmcdermott)
  - `draw = <draw_funcs>` allows users to pass arbitrary drawing functions that
  are evaluated as-is, before the main plotting elements. A core use case is
  drawing common annotations across every facet of a faceted plot, e.g. text or
  threshold lines. (#245 @grantmcdermott)
  - `facet.args` gains a `free = <logical>` sub-argument for independently
  scaling the axes limits of individual facets. (#253 @grantmcdermott)
  
- `tpar()` gains additional `grid.col`, `grid.lty`, and `grid.lwd` arguments for
  fine-grained control over the appearance of the default panel grid when
  `tinyplot(..., grid = TRUE)` is called. (#237 @grantmcdermott)
  
- The new `tinyplot_add()` (alias: `plt_add()`) convenience function allows
easy layering of plots without having to specify repeat arguments. (#246
@vincentarelbundock)

### Breaking changes

- There are a few breaking changes to grouped density plots.
  - The joint smoothing bandwidth is now computed using an observation-weighted
    mean (as opposed to a simple mean). Users can customize this joint bandwidth 
    by invoking the new `type_density(joint.bw = <option>)` argument. See the
    function documentation for details.  (#291 @grantmcdermott and @zeileis)
  - Grouped and/or faceted plots are no longer possible on density objects
    (i.e., via the `tinyplot.density()` method). Instead, please rather call
    `tinyplot(..., type = "density")` or `tinyplot(..., type = type_density())`
    on the raw data and pass grouping or facet arguments as needed.
    (#284 @grantmcdermott)
- The `ribbon.alpha` argument in `tinyplot()` has been deprecated. Use the
  `alpha` argument in `type_ribbon()` (and equivalents) instead: e.g.,
  `tinyplot(..., type = type_ribbon(alpha = 0.5))`.
  - Aside: Please note that this is _not_ equivalent to using
  `tinyplot(..., type = "ribbon", alpha = 0.5)` because the latter matches the
  top-level `alpha` argument of `tinyplot()` itself (and thus modifies the
  entire `palette`, rather than just the ribbon). See our warning about passing
  ancillary type-specific arguments above.

### Bug fixes

- Better preserve facet attributes, thus avoiding misarrangement of facet grids
for density and histogram types. (#209 @zeileis)
- Plots of the form `plt(numeric ~ character)` now work correctly, with the
character variable automatically being coerced to a factor. (#219 @zeileis)
- Respect `xlim` and `ylim` when explicitly supplied by the user. (Thanks to
@mclements for code submission #221)
- Axis titles for flipped (horizontal) boxplots are appropriately swapped too.
(#223 @grantmcdermott)
- Ribbon plots without `ymin` or `ymax` args, now inherit these values from `y`
(#224 @grantmcdermott)
- Plots where `y` is a factor now work automatically, dispatching to the new
`type_spineplot()` type. Thanks to @zeileis for the original suggestion all the
way back in #2 and the eventual solution in #233.
- Free axis scaling now works properly for faceted histograms. The new
`type_histogram(free.breaks = <logical>, drop.zeros = <logical>)` arguments
enable fine-grained control over this behaviour. (#228 @eleuven and
@grantmcdermott)

### Misc

- Continued modularization/abstraction of the code logic. (#214
@vincentarelbundock)
- Major internal refactor of the type drawing and data processing. (#222
@vincentarelbundock)
- Documentation improvements, e.g. explicit guidance on how to specify multiple
grouping variables (thanks to @strengejacke for reporting #213).
  - The new functional type processing system also means that each type now
    has its own help page (e.g. `?type_hist`, `type_ridge`, etc.)

## v0.2.1

New Features:

- The `axes` argument of `tinyplot()`/`plt()` gains extra options for
fine-grained control of the plot axes. In addition to the existing logical
(`TRUE`/`FALSE`) option, users can now specify one of the following character
keywords (or, just their first letters as a convenient shorthand):
  - `"standard"` (with axis, ticks, and labels; equivalent to `TRUE`),
  - `"none"` (no axes; equivalent to `FALSE`),
  - `"ticks"` (only ticks and labels without axis line),
  - `"labels"` (only labels without ticks and axis line),
  - `"axis"` (only axis line and labels but no ticks).

  Simultaneously, the main plotting functions also gain the `xaxt` and `yaxt`
for _separately_ controlling the two axes using the same keyword options. For
example, `plt(0:10, xaxt = "l", yaxt = "t")` will yield a plot where the x-axis
only contains labels and the y-axis contains both labels and ticks, but no axis
line. (#190 @zeileis)
- Support additional boxplot arguments like `varwidth`, `notch`, etc. Note
that `tinyplot(..., type = "boxplot", boxwidth = <num>)` is equivalent to the
`boxplot(..., width = <num>)`; we just use the "box(width)" prefix to avoid 
conflicting with the existing `tinyplot(..., width)` argument.
(#196 @grantmcdermott)

Bug fixes:

- Fix duplicate plots produced with `type = "density"`, which was a regression
accidentally introduced in v0.2.0 (#187 @grantmcdermott)
- Ensure correct boxplot positioning if `x` == `by`, or these two are
functionally identical. (#196 @grantmcdermott)
- `xlab` and `ylab` arguments not respected in some plots. Thanks to @lbelzile
for reporting Issue #203.
- Avoid triggering an inadvertent legend when a function transformation of x is
plotted against x itself, `tinyplot(log(x) ~ x)`. (#197 @zeileis)
- Facets with interactions and/or multivariate formulas (e.g., complex grid
arrangements like `tinyplot(mpg ~ wt, data = mtcars, facet = am + vs ~ gear)`)
now plot all panels correctly, even if some combinations are missing. (#197
@grantmcdermott)
- Fix alignment of facet titles when axes are logged. (#207 @grantmcdermott)
- Consistent decimals for gradient legends (#277 @grantmcdermott) 

Internals:

- Continued modularization of the main code logic. (#192 & #198
@vincentarelbundock)
- Revamped formula processing that allows for better sanity checking and
edge-case logic. (#197 @zeileis)

## v0.2.0

New features:

- Support for additional plot types:
  - `type = "n"`, i.e. empty plot. Since `type = "n"` implicitly assumes points,
  which limits the type of legend that can be drawn alongside the empty plot, we
  have also added a companion `empty` argument that can be used alongside any
  plot type. (#157, #167 @grantmcdermott)
  - `type = "boxplot"`. Simultaneously enables `plt(numeric ~ factor)`
  support, first raised in #2, so that a boxplot is automatically plotted if a
  numeric is plotted against a factor. (#154 @grantmcdermott)
  - `type = "polypath"`. (#159 @grantmcdermott)
  - `type = "rect"`. (#161 @grantmcdermott)
  - `type = "segments"`. (#163 @grantmcdermott)
  - `type = "histogram"` (alias `type = "hist"`). (#164 @grantmcdermott)
  - `type = "jitter"` (alias `type = "j"`). (#170 @grantmcdermott)

Internals:

- The main codebase has been significantly refactored (modularized), which
should simplify future maintenance and enable better user-level error messages
(#171, #173 @vincentarelbundock)

Misc:

- Various documentation improvements.

## v0.1.0

Our first CRAN submission! This v0.1.0 release includes the following new
features and updates:

License:

- Formally switch to Apache 2.0 license. (#141 @grantmcdermott)

Breaking changes:

- To ensure consistent "dot.case" style for all `tinyplot()` function arguments,
the following two arguments have been renamed (`old` => `new`):
  - `par_restore` => `restore.par` (note the change in word order too!)
  - `ribbon_alpha` => `ribbon.alpha`
  
  We don't believe that these two arguments are much used in practice. So
  hopefully it will only have a negligible effect on existing `tinyplot` code in
  the wild, even though it is a breaking change. (#149 @grantmcdermott)

New features:

- Gradient legends are now supported if a continuous variable is passed to
`by`. Thanks to @zeileis for detailed feedback and advice around the default
palette choice (a restricted version of the "viridis" palette), as well as
StackOverflow user mnel, whose answer
[here](https://stackoverflow.com/a/13355440) provided the inspiration for the
final implementation. (#122 @grantmcdermott)
- Ordered factors now inherit a discrete sequential color palette ("viridis") by
default. Thanks to @zeileis for the suggestion. (#130 @grantmcdermott)
- Support user-supplied polygons. (#127 @grantmcdermott)
- Support for the `lwd` argument for adjusting line widths. Similar to `pch`,
`lty`, etc. this arguments also accepts a "by" convenience keyword to
automatically vary line widths by group. (#134 @grantmcdermott)
- `tpar()` now accepts standard `par()` arguments in addition to the
`tinyplot`-specific ones. This allows users to set or query graphical parameters
via a single convenience function, instead having to invoke `tpar` and `par`
separately. (#140 @grantmcdermott)
  - As an aside, `tpar()` has gained some additional parameters for fine-grained
  control of global plot defaults, including `grid`, `ribbon.alpha`, and various
  `file.*` parameters (see next bullet point).
- Users can write plots directly to disk using the new `file` argument,
alongside corresponding `width` and `height` arguments for output customization
(both of which are defined in inches). For example,
`tinyplot(..., file = "~/myplot.png", width = 8, height = 5)`. This
implementation relies on a simple internal wrapper around the traditional R
external graphics devices like `png()`, `pdf()`, etc. But it may prove more
convenient, since the current global graphics parameters held in `(t)par()` are
carried over to the external device too and don't need to be reset. Note that
the appropriate device type is determined automatically by the file extension,
which must be one of ".png", ".jpg" (".jpeg"), ".pdf", or ".svg".
(#143 @grantmcdermott)
- We have a shiny new `tinyplot` logo. (#148 @grantmcdermott)
- The new `get_saved_par()` function can be used to retrieve the `par` settings
from immediately before or immediately after the preceding `tinyplot` call.
This function replaces some older (non-exported) internal functions that
`tinyplot` was using to restore and control `par` environments. But it could
also prove help to end users who are looking for additional ways to restore
`par` settings after the fact. See `?get_saved_par` for some examples. (#152
@grantmcdermott)
- `tinyplot`/`plt` gains a new `alpha = <numeric[0,1]>` convenience argument for
adding transparency to plot elements and colours. Example use:
`plt(rnorm(1e3), pch = 19, alpha = 0.3)`. (#129 @grantmcdermott)
- Similar to the preceding news item, transparency can be added to (grouped)
background fill by passing `bg` (or its alias, `fill`) a numeric in the range
`[0,1]`. This feature has the same effect as `bg = "by"` except for the added
transparency. Example use:
`tinyplot(lat ~ long | depth, data = quakes, pch = 21, cex = 2, bg = 0.2)`. (#129
@grantmcdermott)


Bug fixes:

- Fixed bug that prevented `tpar(facet.x = ...)` args from being passed forward
and set correctly. (#137 @grantmcdermott)
- Fixed bug where custom legends weren't working with `type = "density"`. (#147
@grantmcdermott)

Internals:

- We no longer ship the vignette(s) with the built package. This helps to reduce
the size of the installation tarball and also avoids some redundancy with the
actual help documentation (since many of the examples are the same). Note that
the vignettes are all still rendered and available online at the `tinyplot`
[website](https://grantmcdermott.com/tinyplot/).
(#135 @grantmcdermott)
- Similarly, we anticipate skipping tests on CRAN since the large suite of test
snapshots (images) held in `inst/tinytest` is pushing the install tarball over
CRAN's recommended 5 MB limit. Please note that local testing of the package
requires adding the `NOT_CRAN=TRUE` environment variable to your .Renviron file
(or, exporting it in your .bashrc/.zshrc/etc. dotfile if you prefer that
approach). (#145 @vincentarelbundock & @grantmcdermott)
- Update some test snapshots to match slight changes in the way that R 4.4.0
calculates `density` grid coords. (#150 @grantmcdermott)


## v0.0.5

**IMPORTANT BREAKING CHANGE:**

The package has been renamed to **tinyplot**. (#22 @grantmcdermott)

This package renaming also incorporates the following function changes:

- `plot2()` is replaced by `tinyplot()` (or its shorthand alias `plt()`).
- `par2()` is replaced by `tpar()`.

So, where you used to write...

```r
library(plot2)
plot2(Sepal.Length ~ Petal.Length | Species, iris)
```

... you should now write:

```r
library(tinyplot)
tinyplot(Sepal.Length ~ Petal.Length | Species, iris)

# Or, use the equivalent shorthand `plt` alias
plt(Sepal.Length ~ Petal.Length | Species, iris)
```

The package URLs have been updated accordingly:

- GitHub: https://github.com/grantmcdermott/tinyplot
- Website: https://grantmcdermott.com/tinyplot
- R-universe: https://grantmcdermott.r-universe.dev/tinyplot

Many thanks to everyone who provided thoughtful feedback about this prospective
name change, especially @zeileis and @vincentarelbundock for kicking off the
discussion, as well as the 100+ participants who voted in the social media
poll.

For more details about the rational underlying this renaming decision, please
see the following GitHub comment, as well as the discussion that preceded it:
https://github.com/grantmcdermott/plot2/issues/22#issuecomment-1928472754


##  v0.0.4

Website:

We now have a dedicated website! (#80 @vincentarelbundock)

New features:

- Support for `cex` and `bg` (alias `fill`) arguments. The latter also permit
the "by" convenience keyword similar to `lty` and `pch`. This is useful for
plotting filled point characters (e.g., pch = 21), where you want a different
colour for the fill and border. (#50, #75 @grantmcdermott)
- Support for filled density plots. (#58 @grantmcdermott)
- The new `add` argument allows new plot2 objects to be added to / on top of the
existing plot window. (#60 @grantmcdermott)
- Support for one-sided formulas, e.g. `plot2(~ Temp | Month, airquality)`. (#62
@grantmcdermott and @zeileis)
- Support for `plot2(x, type = "density")` as an alternative to
`plot2(density(x))`. Works for both the atomic and one-sided formula methods.
(#66 @grantmcdermott)
- Support for "area" type plots as a special case of ribbon plots. (#68
@grantmcdermott)
- Partial matching for palette keywords. (#74 @grantmcdermott)
- `plot2` gains a new `facet` argument for drawing faceted plots. Users can
override the default square arrangement by passing the desired number of facet
rows or columns to the companion `facet.args` helper function. Facets can be
combined with `by` grouping, or used on their own.
(#83, #91, #94, #96, #101, #103 @grantmcdermott)
- Users can now control `plot2`-specific graphical parameters globally via
the new `par2()` function (which is modeled on the base `par()` function). At
the moment only a subset of global parameters, mostly related to legend and
facet behaviour, are exposed in `par2`. But users can expect that more will be
added in future releases. (#33, #94 @grantmcdermott)

Bug fixes:

- Y-label correctly prints if a function was used for the atomic plot method,
e.g. `plot2(rnorm(100))`. (#52 etiennebacher)
- Ribbon plot types are now automatically ordered by the x variable. (#54
@grantmcdermott)
- Interval plots like ribbons, errorbars, and pointranges are now correctly
plotted even if a y variable isn't specified. (#54 @grantmcdermott)
- Correctly label date-time axes. (#77 @grantmcdermott and @zeileis)
- Improved consistency of legend and facet margins across different plot types
and placement, via the new `lmar` and `fmar` arguments of `par2()`. The default
legend margin is `par2(lmar = c(1,0, 0.1)`, which means that there is 1.0 line
of padding between the legend and the plot region (inside margin) and 0.1 line 
of padding between the legend and edge of the graphics device (outer margin).
Similarly, the default facet padding is `par2(fmar = c(1,1,1,1)`, which means
that there is a single line of padding around each side of the individual
facets. Users can override these defaults by passing numeric vectors of the
appropriate length to `par2()`. For example, `par2(lmar = c(0,0.1)` would shrink
the inner gap between the legend and plot region to zero, but leave the small
outer gap to outside of the graphics device unchanged. (#94 @grantmcdermott)
- Fix bug where grid wasn't auto-expanding correctly for area plots. (#92
@grantmcdermott)

##  v0.0.3

Breaking changes:

- Colour palettes are now controlled via a single `palette` argument that
unifies the old `palette` and (deprecated) `palette.args` arguments. In
addition, the default palette for small groups has been changed from "Okabe-Ito"
to "R4". (#31 and #32 @grantmcdermott)
- Legends are now controlled via a single `legend` argument that unifies the
previous (deprecated) `legend.position` and `legend.args` arguments.  This
change also enables several enhancements over the old legend behaviour; see
below. (#34 @grantmcdermott)

New features:

- Add support for the argument `log`. (#15 @etiennebacher)
- Add support for grouped density plots. (#18 @grantmcdermott)
- Add support for (both grouped and non-grouped) "c", "h", "s", and "S" types.
(#26 @grantmcdermott)
- Both the `pch` and `lty` arguments now accept a "by" convenience keyword for
automatically adjusting plot characters and line types by groups. (#28
@grantmcdermott)
- Add outside ("!") placement support for remaining legend keywords, e.g.
"top!", "left!", "topright!", etc. Users also gain finer control over many other
aspects of the legend via the new unified `legend` argument, including changing
labels, turning of the legend title, and so on. (#34 @grantmcdermott) 
- Add support for `"pointrange"`, `"errobar"`, and `"ribbon"` plot types. (#35
@vincentarelbundock, #40 and #46 @grantmcdermott)
- Support `grid = TRUE` as an alternative to `grid = grid()`. (#43
@grantmcdermott)

Bug fixes:

- Setting `par(pch=X)` globally is now respected. (#20 @grantmcdermott)
- Fix x-axis scale/index when y is NULL. (#24 @grantmcdermott)
- Setting a global palette, e.g. `palette("ggplot2")` is now respected. (#44
@grantmcdermott)

##  v0.0.2

Breaking changes:

- Legend defaults have been changed. The default position is now "right!" and
drawn without a border, i.e. bty = "n" (#14 by @grantmcdermott).

New features:

- Allow users to specify different `pch`, `lty`, and `col` types per group (#5
and #11 by @vincentarelbundock).

Bug fixes:

- Adding further elements to `plot2` now works (#13 by @grantmcdermott, thanks
@karoliskoncevicius for reporting).

Internals:

- Better formula parsing for `plot2.formula` (#8 by @zeileis).
- Unit testing scaffolding based on **tinysnapshot** (#11 by @vincent).

Project:

- @vincentarelbundock and @zeileis have joined the project as core contributors.
🎉

##  v0.0.1

* Initial release on GitHub.
