diff --git a/NAMESPACE b/NAMESPACE
index ffa51202..147117db 100644
--- a/NAMESPACE
+++ b/NAMESPACE
@@ -25,17 +25,23 @@ export(type_polypath)
 export(type_rect)
 export(type_ribbon)
 export(type_segments)
+export(type_spineplot)
 export(type_spline)
 importFrom(grDevices,adjustcolor)
 importFrom(grDevices,as.raster)
+importFrom(grDevices,col2rgb)
 importFrom(grDevices,colorRampPalette)
+importFrom(grDevices,convertColor)
 importFrom(grDevices,dev.list)
 importFrom(grDevices,dev.new)
 importFrom(grDevices,dev.off)
 importFrom(grDevices,extendrange)
+importFrom(grDevices,gray.colors)
+importFrom(grDevices,hcl)
 importFrom(grDevices,hcl.colors)
 importFrom(grDevices,hcl.pals)
 importFrom(grDevices,jpeg)
+importFrom(grDevices,nclass.Sturges)
 importFrom(grDevices,palette)
 importFrom(grDevices,palette.colors)
 importFrom(grDevices,palette.pals)
diff --git a/NEWS.md b/NEWS.md
index cf59900a..7c13cf0f 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -33,13 +33,17 @@ types enable a variety of additional features. (#222 @vincentarelbundock)
     - `type_lm()` (shortcut: `"lm"`)
     - `type_loess()` (shortcut: `"loess"`)
     - `type_spline()` (shortcut: `"spline"`)
+  - New `type_spineplot()` (shortcut: `"spineplot"`) type for producing 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)
   - Explicit argument passing for modified behaviour type
   (e.g., `type_lm(se = FALSE)`).
   - Users can define their own custom types by creating `type_<typename>()`
   functions.
   - More details are provided in the dedicated
   [Plot types vignette](https://grantmcdermott.com/tinyplot/vignettes/types.html)
-  on the website.
+  on the website.)
 - The new `flip` argument allows for easily flipping (swapping) the orientation
   of the x and y axes. This should work regardless of plot type, e.g.
   `plt(~Sepal.Length | Species, data = iris, type = "density", flip = TRUE)`.
@@ -60,6 +64,9 @@ character variable automatically being coerced to a factor. (#219 @zeileis)
 (#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. 
 
 Internals:
 
diff --git a/R/draw_legend.R b/R/draw_legend.R
index 5570e6aa..0b60edf9 100644
--- a/R/draw_legend.R
+++ b/R/draw_legend.R
@@ -158,7 +158,9 @@ draw_legend = function(
   if (is.null(legend_args[["bty"]])) legend_args[["bty"]] = "n"
   if (is.null(legend_args[["horiz"]])) legend_args[["horiz"]] = FALSE
   if (is.null(legend_args[["xpd"]])) legend_args[["xpd"]] = NA
-  if (is.null(legend_args[["pt.bg"]])) legend_args[["pt.bg"]] = bg
+  if (is.null(legend_args[["pt.bg"]])) {
+    legend_args[["pt.bg"]] = if (identical(type, "spineplot")) legend_args[["col"]] else bg
+  }
   if (
     type %in% c("p", "pointrange", "errorbar") &&
     (length(col) == 1 || length(cex) == 1) &&
@@ -166,7 +168,7 @@ draw_legend = function(
   ) {
     legend_args[["pt.cex"]] = cex
   }
-  if (type %in% c("rect", "ribbon", "polygon", "polypath", "boxplot", "hist", "histogram") || isTRUE(gradient)) {
+  if (type %in% c("rect", "ribbon", "polygon", "polypath", "boxplot", "hist", "histogram", "spineplot") || isTRUE(gradient)) {
     legend_args[["pch"]] = 22
     if (is.null(legend_args[["pt.cex"]])) legend_args[["pt.cex"]] = 3.5
     if (is.null(legend_args[["pt.lwd"]]) && (!is.null(type) && !(type %in% c("rect", "polygon", "polypath", "boxplot")))) {
@@ -219,6 +221,9 @@ draw_legend = function(
     
     outer_right = grepl("right!$", legend_args[["x"]])
     
+    # extra bump for spineplot if outer_right legend (to accommodate secondary y-axis)
+    if (identical(type, "spineplot")) lmar[1] = lmar[1] + 1.1
+    
     ## Switch position anchor (we'll adjust relative to the _opposite_ side below)
     if (outer_right) legend_args[["x"]] = gsub("right!$", "left", legend_args[["x"]])
     if (!outer_right) legend_args[["x"]] = gsub("left!$", "right", legend_args[["x"]])
diff --git a/R/facet.R b/R/facet.R
index 4797c490..5617a3c1 100644
--- a/R/facet.R
+++ b/R/facet.R
@@ -123,6 +123,11 @@ draw_facet_window = function(grid, ...) {
   list2env(list(...), environment())
 
   if (isFALSE(add)) {
+
+    ## optionally allow to modify the style of axis interval calculation
+    if (!is.null(xaxs)) par(xaxs = xaxs)
+    if (!is.null(yaxs)) par(yaxs = yaxs)
+
     if (nfacets > 1) {
       # Set facet margins (i.e., gaps between facets)
       if (is.null(facet.args[["fmar"]])) {
@@ -453,3 +458,17 @@ draw_facet_window = function(grid, ...) {
 
   return(as.list(environment()))
 }
+
+## internal convenience function to determine whether the current facet panel
+## has the position "left", "right", "top", or "bottom" in the facet grid
+is_facet_position = function(position, ifacet, facet_window_args) {
+  id = facet_window_args$ifacet
+  nc = facet_window_args$nfacet_cols
+  ni = tail(id, 1L)
+  switch(position,
+    "left"   = ifacet %in% seq(1L, ni, by = nc),
+    "right"  = ifacet %in% pmin(ni, seq(1L, ni, by = nc) + nc - 1L),
+    "top"    = ifacet %in% head(id, nc),
+    "bottom" = ifacet %in% tail(id, nc),
+    NA)
+}
diff --git a/R/sanitize.R b/R/sanitize.R
index 4b5b23b0..a118895c 100644
--- a/R/sanitize.R
+++ b/R/sanitize.R
@@ -11,15 +11,20 @@ sanitize_type = function(type, x, y) {
         return(type)
     }
 
-    types = c("area", "boxplot", "density", "jitter", "ribbon", "pointrange", "hist", 
-        "histogram", "errorbar", "polygon", "polypath", "rect", "segments", "points", 
-        "p", "l", "o", "b", "c", "h", "j", "s", "S", "n", "loess", "spline", "lm", "glm")
+    types = c("area", "boxplot", "density", "jitter", "ribbon", "pointrange", "hist",
+        "histogram", "errorbar", "polygon", "polypath", "rect", "segments", "points",
+        "p", "l", "o", "b", "c", "h", "j", "s", "S", "n", "loess", "spline", "lm", "glm",
+        "spineplot"
+        )
     assert_choice(type, types, null.ok = TRUE)
 
     if (is.null(type)) {
-        # enforce boxplot type for y ~ factor(x)
         if (!is.null(x) && is.factor(x) && !is.factor(y)) {
+            # enforce boxplot type for y ~ factor(x)
             return(type_boxplot())
+        } else if (is.factor(y)) {
+            # enforce spineplot type for factor(y) ~ x
+            return(type_spineplot())
         } else {
             type = "p"
         }
@@ -41,6 +46,7 @@ sanitize_type = function(type, x, y) {
         "boxplot" = type_boxplot(),
         "ribbon" = type_ribbon(),
         "histogram" = type_histogram(),
+        "spineplot" = type_spineplot(),
         "j" = type_jitter(),
         "jitter" = type_jitter(),
         "loess" = type_loess(),
diff --git a/R/tinyplot.R b/R/tinyplot.R
index 4535a790..d96f813e 100644
--- a/R/tinyplot.R
+++ b/R/tinyplot.R
@@ -291,7 +291,7 @@
 #'  specified.
 #' @param xaxt,yaxt character specifying the type of x-axis and y-axis, respectively.
 #'   See `axes` for the possible values.
-#' @param ... other graphical parameters (see \code{\link[graphics]{par}}). 
+#' @param xaxs,yaxs,... other graphical parameters (see \code{\link[graphics]{par}}).
 #'
 #' @returns No return value, called for side effect of producing a plot.
 #'   
@@ -533,6 +533,8 @@ tinyplot.default = function(
     xaxt = NULL,
     yaxt = NULL,
     flip = FALSE,
+    xaxs = NULL,
+    yaxs = NULL,
     ...
     ) {
 
@@ -675,6 +677,10 @@ tinyplot.default = function(
   datapoints[["facet"]] = if (!is.null(facet)) facet else ""
   datapoints[["by"]] = if (!is.null(by)) by else ""
 
+  ## initialize empty list with information that type_data
+  ## can overwrite in order to pass on to type_draw
+  type_info = list()
+
   if (!is.null(type_data)) {
     fargs = list(
       datapoints = datapoints,
@@ -682,6 +688,7 @@ tinyplot.default = function(
       by = by,
       col = col,
       facet = facet,
+      facet.args = facet.args,
       palette = palette,
       ribbon.alpha = ribbon.alpha,
       xaxt = xaxt,
@@ -990,7 +997,7 @@ tinyplot.default = function(
     ymax = datapoints$ymax, ymin = datapoints$ymin,
     xaxt = xaxt, xlabs = xlabs, xlim = xlim,
     yaxt = yaxt, ylabs = ylabs, ylim = ylim,
-    flip = flip
+    flip = flip, xaxs = xaxs, yaxs = yaxs
   )
   list2env(facet_window_args, environment())
 
@@ -1064,7 +1071,7 @@ tinyplot.default = function(
 
       # empty plot flag
       empty_plot = FALSE
-      if (isTRUE(empty) || isTRUE(type == "n") || ((length(ix) == 0) && !(type %in% c("histogram", "hist", "rect", "segments")))) {
+      if (isTRUE(empty) || isTRUE(type == "n") || ((length(ix) == 0) && !(type %in% c("histogram", "hist", "rect", "segments", "spineplot")))) {
         empty_plot = TRUE
       }
 
@@ -1107,7 +1114,9 @@ tinyplot.default = function(
             facet_by = facet_by,
             data_facet = idata,
             data_by = split_data,
-            flip = flip)
+            flip = flip,
+            type_info = type_info,
+            facet_window_args = facet_window_args)
       }
     }
   }
diff --git a/R/type_spineplot.R b/R/type_spineplot.R
new file mode 100644
index 00000000..ab8f003b
--- /dev/null
+++ b/R/type_spineplot.R
@@ -0,0 +1,384 @@
+#' Spineplot and spinogram type
+#'
+#' @inheritParams graphics::spineplot
+#' @examples
+#' # "spineplot" type convenience string
+#' tinyplot(Species ~ Sepal.Width, data = iris, type = "spineplot")
+#' 
+#' # Aside: specifying the type is redundant for this example, since tinyplot
+#' # default's to "spineplot" if y is a factor (just like base plot).
+#' tinyplot(Species ~ Sepal.Width, data = iris)
+#' 
+#' # Use `type_spineplot()` to pass extra arguments for customization
+#' tinyplot(Species ~ Sepal.Width, data = iris, type = type_spineplot(breaks = 4))
+#' 
+#' p = palette.colors(3, "Pastel 1")
+#' tinyplot(Species ~ Sepal.Width, data = iris, type = type_spineplot(breaks = 4, col = p))
+#' rm(p)
+#' 
+#' # More idiomatic tinyplot way of drawing the previous plot: use y == by
+#' tinyplot(
+#'   Species ~ Sepal.Width | Species, data = iris, type = type_spineplot(breaks = 4),
+#'   palette = "Pastel 1", legend = FALSE
+#' )
+#' 
+#' # Grouped and faceted spineplots
+#' 
+#' ttnc = as.data.frame(Titanic)
+#' 
+#' tinyplot(
+#'   Survived ~ Sex, facet = ~ Class, data = ttnc,
+#'   type = type_spineplot(weights = ttnc$Freq)
+#' )
+#' 
+#' # For grouped "by" spineplots, it's better visually to facet as well
+#' tinyplot(
+#'   Survived ~ Sex | Class, facet = "by", data = ttnc,
+#'   type = type_spineplot(weights = ttnc$Freq)
+#' )
+#' 
+#' # Fancier version. Note the smart inheritance of spacing etc.
+#' tinyplot(
+#'   Survived ~ Sex | Class, facet = "by", data = ttnc,
+#'   type = type_spineplot(weights = ttnc$Freq),
+#'   palette = "Dark 2", facet.args = list(nrow = 1), axes = "t"
+#' )
+#' 
+#' # Note: It's possible to use "by" on its own (without faceting), but the
+#' # overlaid result isn't great. We will likely overhaul this behaviour in a
+#' # future version of tinyplot...
+#' tinyplot(Survived ~ Sex | Class, data = ttnc,
+#'   type = type_spineplot(weights = ttnc$Freq), alpha = 0.3
+#' )
+#' 
+#' @export
+type_spineplot = function(breaks = NULL, tol.ylab = 0.05, off = NULL, ylevels = NULL, col = NULL, xaxlabels = NULL, yaxlabels = NULL, weights = NULL) {
+  col = col
+  out = list(
+    data = data_spineplot(off = off, breaks = breaks, ylevels = ylevels, xaxlabels = xaxlabels, yaxlabels = yaxlabels, weights = weights),
+    draw = draw_spineplot(tol.ylab = tol.ylab, off = off, col = col, xaxlabels = xaxlabels, yaxlabels = yaxlabels),
+    name = "spineplot"
+  )
+  class(out) = "tinyplot_type"
+  return(out)
+}
+
+#' @importFrom grDevices nclass.Sturges
+data_spineplot = function(off = NULL, breaks = NULL, ylevels = ylevels, xaxlabels = NULL, yaxlabels = NULL, weights = NULL) {
+    fun = function(
+      datapoints,
+      by = NULL, col = NULL, bg = NULL, palette = NULL,
+      facet = NULL, facet.args = NULL, xlim = NULL, ylim = NULL, axes = TRUE, xaxt = NULL, yaxt = NULL,
+      ...
+    ) {
+      
+        ## process weights
+        if (!is.null(weights)) {
+            ny = length(datapoints$y)
+            if (length(weights) != ny && length(weights) != 1L) {
+                stop(sprintf("'weights' must have either length 1 or %s", ny))
+            }
+        }
+        datapoints$weights = weights
+        
+        ## process x variable
+        if(is.factor(datapoints$x)) {
+            breaks = NULL
+            off = if(is.null(off)) 0.02 else off/100
+            if (is.null(xlim)) xlim = c(0, 1 + (nlevels(datapoints$x) - 1L) * off)
+        } else {
+            off = 0
+            if (is.null(xlim)) xlim = c(0, 1)
+    	    x = as.numeric(datapoints$x)
+            if (is.null(breaks)) {
+                breaks = if(is.null(weights)) nclass.Sturges(x) else ceiling(log2(sum(weights)) + 1)
+	    }
+            breaks = as.numeric(breaks)
+            if (length(breaks) == 1L) {
+                if (!is.numeric(breaks) || !is.finite(breaks) || breaks < 1L) stop("invalid number of 'breaks'")
+                if (breaks > 1e6) {
+                    warning(gettextf("'breaks = %g' is too large and set to 1e6", breaks))
+                    breaks = 1000000L
+                }
+                rg = if (is.null(weights)) range(x, na.rm = TRUE) else range(x[weights > 0], na.rm = TRUE)
+                breaks = pretty(rg, n = breaks, min.n = 1L)        
+            }
+        }
+
+        ## process y variable
+        if (!is.factor(datapoints$y)) datapoints$y = factor(datapoints$y)
+        if (!is.null(ylevels)) datapoints$y = factor(y, levels = if(is.numeric(ylevels)) levels(y)[ylevels] else ylevels)
+        if (is.null(ylim)) ylim = c(0, 1)
+
+        ## adjust facet margins
+        if (!is.null(facet) && is.null(facet.args[["fmar"]])) {
+          facet.args[["fmar"]] = c(2, 2, 2, 2)
+        }
+        
+        x.categorical = is.factor(datapoints$x)
+        x = datapoints$x
+        y = datapoints$y
+        
+        x_by = identical(datapoints$x, datapoints$by)
+        y_by = identical(datapoints$y, datapoints$by)
+        # if either x_by or y_by are TRUE, we'll only split by facets and then
+        # use some simpl logic to assign colouring on the backend
+        if (isTRUE(x_by) || isTRUE(y_by)) {
+          datapoints = split(datapoints, list(datapoints$facet))
+          datapoints = Filter(function(k) nrow(k) > 0, datapoints)
+        } else {
+          datapoints = split(datapoints, list(datapoints$by, datapoints$facet))
+          datapoints = Filter(function(k) nrow(k) > 0, datapoints)
+        }
+        
+        # construct spineplot rectangles and breaks points for each by-facet combo
+        datapoints = Map(function(dat, x.categorical, off) {
+          ## set up frequency table
+          x = dat$x
+          if(!x.categorical) {
+            x = cut(as.numeric(x), breaks = breaks, include.lowest = TRUE)
+          }
+          ## TODO: process by grouping via: interaction + spacing + labeling
+          ## (for now just do interaction)
+          ## FIXME: data_facet only contains the first by group?
+          ## if (any(dat$by != "")) x = interaction(dat$by, x)
+          if(is.null(dat$weights)) {
+            tab = table(x, dat$y)
+          } else {
+            tab = as.table(tapply(dat$weights, list(x, dat$y), FUN = sum, na.rm = TRUE))
+            tab[is.na(tab)] = 0
+          }
+          nx = nrow(tab)
+          ny = ncol(tab)
+          
+          ## compute coordinates
+          ## cumulative proportions of x (plus off) vs. conditional cumulative proportions of y
+          yat = rbind(0, apply(proportions(tab[, ny:1L, drop = FALSE], 1L), 1L, cumsum))
+          yat[is.na(yat)] = 1
+          xat = c(0, cumsum(proportions(marginSums(tab, 1L)) + off))
+          
+          ybottom = as.vector(yat[-(ny + 1L),])
+          ytop = as.vector(yat[-1L,])
+          xleft = rep(xat[1L:nx], rep(ny, nx))
+          xright = rep(xat[2L:(nx+1L)] - off, rep(ny, nx))
+          
+          out = data.frame(
+            by = dat$by[1], # already split
+            facet = dat$facet[1], # already split
+            ymin = ybottom,
+            ymax = ytop,
+            xmin = xleft,
+            xmax = xright
+          )
+          
+          attr(out, "nx") = nx
+          attr(out, "ny") = ny
+          attr(out, "xat") = xat
+          attr(out, "yat") = yat
+          return(out)
+        }, 
+        dat = datapoints,
+        x.categorical = x.categorical,
+        off = off
+        )
+        
+        nx = attr(datapoints[[1]], "nx") ## should be the same for all by/facet groups
+        ny = attr(datapoints[[1]], "ny") ## ditto
+        xat = lapply(datapoints, attr, "xat")
+        yat = lapply(datapoints, attr, "yat")
+        datapoints = do.call(rbind, datapoints)
+         
+        if (is.null(yaxlabels)) yaxlabels = rev(levels(y))
+      
+        ## axis labels
+        yaxlabels = if(is.null(yaxlabels)) levels(y) else rep_len(yaxlabels, ny)
+        if(x.categorical) {
+          xaxlabels = if(is.null(xaxlabels)) {
+            levels(x)
+          } else {
+            rep_len(xaxlabels, nx)
+          }
+        } else {
+          xaxlabels = if(is.null(xaxlabels)) {
+            if(is.numeric(x)) breaks else c(x[1L], x[c(diff(as.numeric(x)) > 0, TRUE)])
+          } else {
+            rep_len(xaxlabels, nx + 1L)
+          }
+        }
+        
+        # catch for x_by / y/by
+        if (isTRUE(x_by)) datapoints$by = rep(xaxlabels, each = ny) # each x label extends over ny rows
+        if (isTRUE(y_by)) datapoints$by = rep(yaxlabels, length.out = nrow(datapoints))
+          
+        ## grayscale flag
+        grayscale = length(unique(datapoints[["by"]])) == 1 && is.null(palette)
+        
+        out = list(
+          x = c(datapoints$xmin, datapoints$xmax), 
+          y = c(datapoints$ymin, datapoints$ymax),
+          ymin = datapoints$ymin, 
+          ymax = datapoints$ymax, 
+          xmin = datapoints$xmin, 
+          xmax = datapoints$xmax, 
+          col = col,
+          bg = bg,
+          datapoints = datapoints,
+          by = if (length(unique(datapoints$by)) == 1) by else datapoints$by, 
+          facet = if (length(unique(datapoints$facet)) == 1) facet else datapoints$facet,
+          axes = FALSE,
+          frame.plot = FALSE,
+          xaxt = "n",
+          yaxt = "n",
+          xaxs = "i",
+          yaxs = "i",
+          type_info = list(
+            off = off,
+            x.categorical = x.categorical,
+            nx = nx,
+            ny = ny,
+            xat = xat,
+            yat = yat,
+            xaxlabels = xaxlabels,
+            yaxlabels = yaxlabels,
+            breaks = breaks,
+            axes = axes,
+            xaxt = xaxt, 
+            yaxt = yaxt,
+            grayscale = grayscale,
+            x_by = x_by,
+            y_by = y_by
+          ),
+          facet.args = facet.args
+        )
+        
+        return(out)
+        
+    }
+    return(fun)
+}
+
+#' @importFrom grDevices gray.colors
+draw_spineplot = function(tol.ylab = 0.05, off = NULL, col = NULL, xaxlabels = NULL, yaxlabels = NULL) {
+    fun = function(ixmin, iymin, ixmax, iymax, ilty, ilwd, icol, ibg, 
+                   flip,
+                   facet_window_args,
+                   type_info,
+                   ifacet,
+                   ...) {
+      
+      if (is.null(off)) off = type_info[["off"]]
+      if (is.null(xaxlabels)) xaxlabels = type_info[["xaxlabels"]]
+      if (is.null(yaxlabels)) yaxlabels = type_info[["yaxlabels"]]
+      xat = type_info[["xat"]][[ifacet]]
+      yat = type_info[["yat"]][[ifacet]]
+      nx = type_info[["nx"]]
+      ny = type_info[["ny"]]
+      x.categorical = type_info[["x.categorical"]]
+      grayscale = type_info[["grayscale"]]
+      x_by = type_info[["x_by"]]
+      y_by = type_info[["y_by"]]
+      
+      ## graphical parameters
+      if (is.null(col)) {
+        if (is.null(ibg)) ibg = icol
+        if (isFALSE(y_by)) {
+          ibg = if (isTRUE(grayscale)) gray.colors(ny) else seq_palette(ibg, ny)
+        }
+        ibg = rep_len(ibg, ny)
+      } else {
+        ibg = col
+      }
+      
+      if (type_info[["xaxt"]] %in% c("l", "t", "n") &&
+          type_info[["yaxt"]] %in% c("l", "t", "n") &&
+          !all(c(type_info[["xaxt"]], type_info[["yaxt"]]) == "n")) ilwd = 0
+      
+      rect(
+          xleft = ixmin, ybottom = iymin, xright = ixmax, ytop = iymax,
+          lty = ilty,
+          lwd = ilwd,
+          border = par("fg"), #icol,
+          col = ibg
+      )
+      
+      ## axes
+      ## - standard categorical axes (xaxt/yaxt == "s") _without_ ticks
+      ## - never draw additional axis lines, box always for spinogram
+      if(type_info[["axes"]]) {
+          if (x.categorical) {
+              spine_axis(if (flip) 2 else 1, at = (xat[1L:nx] + xat[2L:(nx+1L)] - off)/2, labels = xaxlabels,
+                  type = type_info[["xaxt"]], categorical = TRUE)
+          } else {
+              spine_axis(if (flip) 2 else 1, at = xat, labels = xaxlabels,
+                  type = type_info[["xaxt"]], categorical = FALSE)
+          }
+          yat = yat[, if(flip) ncol(yat) else 1L]
+          equidist = any(diff(yat) < tol.ylab)
+          yat = if(equidist) seq.int(1/(2*ny), 1-1/(2*ny), by = 1/ny) else (yat[-1L] + yat[-length(yat)])/2
+          spine_axis(if (flip) 3 else 2, at = yat, labels = yaxlabels,
+              type = type_info[["yaxt"]], categorical = TRUE)
+          if (is_facet_position(if(flip) "bottom" else "right", ifacet, facet_window_args)) spine_axis(if (flip) 1 else 4,
+              type = type_info[["yaxt"]], categorical = FALSE)
+      }
+      if(!x.categorical && (is.null(ilwd) || ilwd > 0)) box()
+      
+    }
+    return(fun)
+}
+
+
+
+
+spine_axis = function(side, ..., type = "standard", categorical = TRUE) {
+    type = match.arg(type, c("standard", "none", "labels", "ticks", "axis"))
+    ## standard: with axis, ticks (unless categorical), and labels
+    ## none: no axes
+    ## labels: only labels without ticks and axis line
+    ## ticks: only ticks and labels without axis line
+    ## axis: only axis line and labels but no ticks
+
+    if (type == "none") {
+        invisible(numeric(0L))
+    } else {
+        args = list(side = side, ...)
+        if (type == "labels") {
+            args$tick = FALSE
+        } else if (type == "ticks") {
+            args$lwd = 0
+            if (!("lwd.ticks" %in% names(args))) args$lwd.ticks = if (categorical) 0 else 1
+        } else if (type == "axis") {
+            if (categorical) {
+                args$tick = FALSE
+            } else {
+                args$lwd.ticks = 0
+            }
+        } else {
+            args$tick = !categorical
+        }
+        do.call("axis", args)
+    }
+}
+
+#' @importFrom grDevices col2rgb convertColor hcl
+to_hcl = function(x) {
+    x = t(col2rgb(x, alpha = TRUE)/255)
+    alpha = x[, 4]
+    x = x[, 1:3]
+    x = convertColor(x, from = "sRGB", to = "Luv")
+    x = cbind(H = atan2(x[, 3L], x[, 2L]) * 180/pi, C = sqrt(x[, 2L]^2 + x[, 3L]^2), L = x[, 1L])
+    x[is.na(x[, 1L]), 1L] = 0
+    x[x[, 1L] < 0, 1L] = x[x[, 1L] < 0, 1L] + 360
+    attr(x, "alpha") = alpha
+    return(x)
+}
+
+seq_palette = function(x, n, power = 1.5) {
+    x = drop(to_hcl(x[1L]))
+    alpha = attr(x, "alpha")
+    hcl(
+      h = x[1L],
+      c = seq.int(from = x[2L]^(1/power), to = 0, length.out = n + 1)[1L:n]^power,
+      l = 100 - seq.int(from = (100 - x[3L])^(1/power), to = pmin(8, (100 - x[3L])/2)^(1/power), length.out = n)^power,
+      alpha = alpha
+    )[1L:n]
+}
diff --git a/R/zzz.R b/R/zzz.R
index 3ce682a2..754c4227 100644
--- a/R/zzz.R
+++ b/R/zzz.R
@@ -78,6 +78,7 @@
     "split_data",
     "type",
     "x",
+    "xaxs",
     "xaxt",
     "xlabs",
     "xlim",
@@ -85,6 +86,7 @@
     "xmax",
     "xmin",
     "y",
+    "yaxs",
     "yaxt",
     "ylabs",
     "ylim",
diff --git a/altdoc/quarto_website.yml b/altdoc/quarto_website.yml
index 4e990550..48701cb0 100644
--- a/altdoc/quarto_website.yml
+++ b/altdoc/quarto_website.yml
@@ -62,6 +62,8 @@ website:
               file: man/type_histogram.qmd
             - text: type_jitter
               file: man/type_jitter.qmd
+            - text: type_spineplot
+              file: man/type_spineplot.qmd
           #
           - section: Models
             contents:
diff --git a/inst/tinytest/_tinysnapshot/spineplot_auto_factor.svg b/inst/tinytest/_tinysnapshot/spineplot_auto_factor.svg
new file mode 100644
index 00000000..0bf56c89
--- /dev/null
+++ b/inst/tinytest/_tinysnapshot/spineplot_auto_factor.svg
@@ -0,0 +1,81 @@
+<?xml version='1.0' encoding='UTF-8' ?>
+<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' class='svglite' width='504.00pt' height='504.00pt' viewBox='0 0 504.00 504.00'>
+<defs>
+  <style type='text/css'><![CDATA[
+    .svglite line, .svglite polyline, .svglite polygon, .svglite path, .svglite rect, .svglite circle {
+      fill: none;
+      stroke: #000000;
+      stroke-linecap: round;
+      stroke-linejoin: round;
+      stroke-miterlimit: 10.00;
+    }
+    .svglite text {
+      white-space: pre;
+    }
+  ]]></style>
+</defs>
+<rect width='100%' height='100%' style='stroke: none; fill: #FFFFFF;'/>
+<defs>
+  <clipPath id='cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA='>
+    <rect x='0.00' y='0.00' width='504.00' height='504.00' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='266.40' y='485.28' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='23.35px' lengthAdjust='spacingAndGlyphs'>mpg</text>
+<text transform='translate(12.96,244.80) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='52.68px' lengthAdjust='spacingAndGlyphs'>factor(cyl)</text>
+</g>
+<defs>
+  <clipPath id='cpNTkuMDR8NDczLjc2fDU5LjA0fDQzMC41Ng=='>
+    <rect x='59.04' y='59.04' width='414.72' height='371.52' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpNTkuMDR8NDczLjc2fDU5LjA0fDQzMC41Ng==)'>
+<rect x='59.04' y='59.04' width='77.76' height='371.52' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='59.04' y='59.04' width='77.76' height='0.00' style='stroke-width: 0.75; fill: #AEAEAE;' />
+<rect x='59.04' y='59.04' width='77.76' height='0.00' style='stroke-width: 0.75; fill: #E6E6E6;' />
+<rect x='136.80' y='182.88' width='155.52' height='247.68' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='136.80' y='59.04' width='155.52' height='123.84' style='stroke-width: 0.75; fill: #AEAEAE;' />
+<rect x='136.80' y='59.04' width='155.52' height='0.00' style='stroke-width: 0.75; fill: #E6E6E6;' />
+<rect x='292.32' y='430.56' width='103.68' height='0.00' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='292.32' y='291.24' width='103.68' height='139.32' style='stroke-width: 0.75; fill: #AEAEAE;' />
+<rect x='292.32' y='59.04' width='103.68' height='232.20' style='stroke-width: 0.75; fill: #E6E6E6;' />
+<rect x='396.00' y='430.56' width='25.92' height='0.00' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='396.00' y='430.56' width='25.92' height='0.00' style='stroke-width: 0.75; fill: #AEAEAE;' />
+<rect x='396.00' y='59.04' width='25.92' height='371.52' style='stroke-width: 0.75; fill: #E6E6E6;' />
+<rect x='421.92' y='430.56' width='51.84' height='0.00' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='421.92' y='430.56' width='51.84' height='0.00' style='stroke-width: 0.75; fill: #AEAEAE;' />
+<rect x='421.92' y='59.04' width='51.84' height='371.52' style='stroke-width: 0.75; fill: #E6E6E6;' />
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<line x1='59.04' y1='430.56' x2='473.76' y2='430.56' style='stroke-width: 0.75;' />
+<line x1='59.04' y1='430.56' x2='59.04' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='136.80' y1='430.56' x2='136.80' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='292.32' y1='430.56' x2='292.32' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='396.00' y1='430.56' x2='396.00' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='421.92' y1='430.56' x2='421.92' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='430.56' x2='473.76' y2='437.76' style='stroke-width: 0.75;' />
+<text x='59.04' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='13.35px' lengthAdjust='spacingAndGlyphs'>10</text>
+<text x='136.80' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='13.35px' lengthAdjust='spacingAndGlyphs'>15</text>
+<text x='292.32' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='13.35px' lengthAdjust='spacingAndGlyphs'>20</text>
+<text x='396.00' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='13.35px' lengthAdjust='spacingAndGlyphs'>25</text>
+<text x='421.92' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='13.35px' lengthAdjust='spacingAndGlyphs'>30</text>
+<text x='473.76' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='13.35px' lengthAdjust='spacingAndGlyphs'>35</text>
+<text transform='translate(41.76,368.64) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='6.67px' lengthAdjust='spacingAndGlyphs'>8</text>
+<text transform='translate(41.76,244.80) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='6.67px' lengthAdjust='spacingAndGlyphs'>6</text>
+<text transform='translate(41.76,120.96) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='6.67px' lengthAdjust='spacingAndGlyphs'>4</text>
+<line x1='473.76' y1='430.56' x2='473.76' y2='59.04' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='430.56' x2='480.96' y2='430.56' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='356.26' x2='480.96' y2='356.26' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='281.95' x2='480.96' y2='281.95' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='207.65' x2='480.96' y2='207.65' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='133.34' x2='480.96' y2='133.34' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='59.04' x2='480.96' y2='59.04' style='stroke-width: 0.75;' />
+<text transform='translate(499.68,430.56) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.0</text>
+<text transform='translate(499.68,356.26) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.2</text>
+<text transform='translate(499.68,281.95) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.4</text>
+<text transform='translate(499.68,207.65) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.6</text>
+<text transform='translate(499.68,133.34) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.8</text>
+<text transform='translate(499.68,59.04) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>1.0</text>
+<polygon points='59.04,430.56 473.76,430.56 473.76,59.04 59.04,59.04 ' style='stroke-width: 0.75;' />
+</g>
+</svg>
diff --git a/inst/tinytest/_tinysnapshot/spineplot_auto_factors.svg b/inst/tinytest/_tinysnapshot/spineplot_auto_factors.svg
new file mode 100644
index 00000000..b02c1223
--- /dev/null
+++ b/inst/tinytest/_tinysnapshot/spineplot_auto_factors.svg
@@ -0,0 +1,60 @@
+<?xml version='1.0' encoding='UTF-8' ?>
+<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' class='svglite' width='504.00pt' height='504.00pt' viewBox='0 0 504.00 504.00'>
+<defs>
+  <style type='text/css'><![CDATA[
+    .svglite line, .svglite polyline, .svglite polygon, .svglite path, .svglite rect, .svglite circle {
+      fill: none;
+      stroke: #000000;
+      stroke-linecap: round;
+      stroke-linejoin: round;
+      stroke-miterlimit: 10.00;
+    }
+    .svglite text {
+      white-space: pre;
+    }
+  ]]></style>
+</defs>
+<rect width='100%' height='100%' style='stroke: none; fill: #FFFFFF;'/>
+<defs>
+  <clipPath id='cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA='>
+    <rect x='0.00' y='0.00' width='504.00' height='504.00' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='266.40' y='485.28' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='54.68px' lengthAdjust='spacingAndGlyphs'>factor(am)</text>
+<text transform='translate(12.96,244.80) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='52.68px' lengthAdjust='spacingAndGlyphs'>factor(cyl)</text>
+</g>
+<defs>
+  <clipPath id='cpNTkuMDR8NDczLjc2fDU5LjA0fDQzMC41Ng=='>
+    <rect x='59.04' y='59.04' width='414.72' height='371.52' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpNTkuMDR8NDczLjc2fDU5LjA0fDQzMC41Ng==)'>
+<rect x='59.04' y='195.92' width='241.41' height='234.64' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='59.04' y='117.70' width='241.41' height='78.21' style='stroke-width: 0.75; fill: #AEAEAE;' />
+<rect x='59.04' y='59.04' width='241.41' height='58.66' style='stroke-width: 0.75; fill: #E6E6E6;' />
+<rect x='308.58' y='373.40' width='165.18' height='57.16' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='308.58' y='287.67' width='165.18' height='85.74' style='stroke-width: 0.75; fill: #AEAEAE;' />
+<rect x='308.58' y='59.04' width='165.18' height='228.63' style='stroke-width: 0.75; fill: #E6E6E6;' />
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='179.75' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='6.67px' lengthAdjust='spacingAndGlyphs'>0</text>
+<text x='391.17' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='6.67px' lengthAdjust='spacingAndGlyphs'>1</text>
+<text transform='translate(41.76,313.24) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='6.67px' lengthAdjust='spacingAndGlyphs'>8</text>
+<text transform='translate(41.76,156.81) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='6.67px' lengthAdjust='spacingAndGlyphs'>6</text>
+<text transform='translate(41.76,88.37) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='6.67px' lengthAdjust='spacingAndGlyphs'>4</text>
+<line x1='473.76' y1='430.56' x2='473.76' y2='59.04' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='430.56' x2='480.96' y2='430.56' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='356.26' x2='480.96' y2='356.26' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='281.95' x2='480.96' y2='281.95' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='207.65' x2='480.96' y2='207.65' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='133.34' x2='480.96' y2='133.34' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='59.04' x2='480.96' y2='59.04' style='stroke-width: 0.75;' />
+<text transform='translate(499.68,430.56) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.0</text>
+<text transform='translate(499.68,356.26) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.2</text>
+<text transform='translate(499.68,281.95) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.4</text>
+<text transform='translate(499.68,207.65) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.6</text>
+<text transform='translate(499.68,133.34) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.8</text>
+<text transform='translate(499.68,59.04) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>1.0</text>
+</g>
+</svg>
diff --git a/inst/tinytest/_tinysnapshot/spineplot_breaks.svg b/inst/tinytest/_tinysnapshot/spineplot_breaks.svg
new file mode 100644
index 00000000..f18a3ae4
--- /dev/null
+++ b/inst/tinytest/_tinysnapshot/spineplot_breaks.svg
@@ -0,0 +1,80 @@
+<?xml version='1.0' encoding='UTF-8' ?>
+<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' class='svglite' width='504.00pt' height='504.00pt' viewBox='0 0 504.00 504.00'>
+<defs>
+  <style type='text/css'><![CDATA[
+    .svglite line, .svglite polyline, .svglite polygon, .svglite path, .svglite rect, .svglite circle {
+      fill: none;
+      stroke: #000000;
+      stroke-linecap: round;
+      stroke-linejoin: round;
+      stroke-miterlimit: 10.00;
+    }
+    .svglite text {
+      white-space: pre;
+    }
+  ]]></style>
+</defs>
+<rect width='100%' height='100%' style='stroke: none; fill: #FFFFFF;'/>
+<defs>
+  <clipPath id='cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA='>
+    <rect x='0.00' y='0.00' width='504.00' height='504.00' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='266.40' y='485.28' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='64.70px' lengthAdjust='spacingAndGlyphs'>Sepal.Width</text>
+<text transform='translate(12.96,244.80) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='42.70px' lengthAdjust='spacingAndGlyphs'>Species</text>
+</g>
+<defs>
+  <clipPath id='cpNTkuMDR8NDczLjc2fDU5LjA0fDQzMC41Ng=='>
+    <rect x='59.04' y='59.04' width='414.72' height='371.52' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpNTkuMDR8NDczLjc2fDU5LjA0fDQzMC41Ng==)'>
+<rect x='59.04' y='332.79' width='52.53' height='97.77' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='59.04' y='78.59' width='52.53' height='254.20' style='stroke-width: 0.75; fill: #AEAEAE;' />
+<rect x='59.04' y='59.04' width='52.53' height='19.55' style='stroke-width: 0.75; fill: #E6E6E6;' />
+<rect x='111.57' y='268.02' width='176.95' height='162.54' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='111.57' y='99.68' width='176.95' height='168.34' style='stroke-width: 0.75; fill: #AEAEAE;' />
+<rect x='111.57' y='59.04' width='176.95' height='40.64' style='stroke-width: 0.75; fill: #E6E6E6;' />
+<rect x='288.52' y='322.20' width='132.71' height='108.36' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='288.52' y='260.28' width='132.71' height='61.92' style='stroke-width: 0.75; fill: #AEAEAE;' />
+<rect x='288.52' y='59.04' width='132.71' height='201.24' style='stroke-width: 0.75; fill: #E6E6E6;' />
+<rect x='421.23' y='360.90' width='44.24' height='69.66' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='421.23' y='360.90' width='44.24' height='0.00' style='stroke-width: 0.75; fill: #AEAEAE;' />
+<rect x='421.23' y='59.04' width='44.24' height='301.86' style='stroke-width: 0.75; fill: #E6E6E6;' />
+<rect x='465.47' y='430.56' width='8.29' height='0.00' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='465.47' y='430.56' width='8.29' height='0.00' style='stroke-width: 0.75; fill: #AEAEAE;' />
+<rect x='465.47' y='59.04' width='8.29' height='371.52' style='stroke-width: 0.75; fill: #E6E6E6;' />
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<line x1='59.04' y1='430.56' x2='473.76' y2='430.56' style='stroke-width: 0.75;' />
+<line x1='59.04' y1='430.56' x2='59.04' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='111.57' y1='430.56' x2='111.57' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='288.52' y1='430.56' x2='288.52' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='421.23' y1='430.56' x2='421.23' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='465.47' y1='430.56' x2='465.47' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='430.56' x2='473.76' y2='437.76' style='stroke-width: 0.75;' />
+<text x='59.04' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='6.67px' lengthAdjust='spacingAndGlyphs'>2</text>
+<text x='111.57' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>2.5</text>
+<text x='288.52' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='6.67px' lengthAdjust='spacingAndGlyphs'>3</text>
+<text x='421.23' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>3.5</text>
+<text x='465.47' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='6.67px' lengthAdjust='spacingAndGlyphs'>4</text>
+<text transform='translate(41.76,381.68) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='44.02px' lengthAdjust='spacingAndGlyphs'>virginica</text>
+<text transform='translate(41.76,205.69) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='51.36px' lengthAdjust='spacingAndGlyphs'>versicolor</text>
+<text transform='translate(41.76,68.82) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='35.37px' lengthAdjust='spacingAndGlyphs'>setosa</text>
+<line x1='473.76' y1='430.56' x2='473.76' y2='59.04' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='430.56' x2='480.96' y2='430.56' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='356.26' x2='480.96' y2='356.26' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='281.95' x2='480.96' y2='281.95' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='207.65' x2='480.96' y2='207.65' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='133.34' x2='480.96' y2='133.34' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='59.04' x2='480.96' y2='59.04' style='stroke-width: 0.75;' />
+<text transform='translate(499.68,430.56) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.0</text>
+<text transform='translate(499.68,356.26) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.2</text>
+<text transform='translate(499.68,281.95) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.4</text>
+<text transform='translate(499.68,207.65) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.6</text>
+<text transform='translate(499.68,133.34) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.8</text>
+<text transform='translate(499.68,59.04) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>1.0</text>
+<polygon points='59.04,430.56 473.76,430.56 473.76,59.04 59.04,59.04 ' style='stroke-width: 0.75;' />
+</g>
+</svg>
diff --git a/inst/tinytest/_tinysnapshot/spineplot_breaks_flip.svg b/inst/tinytest/_tinysnapshot/spineplot_breaks_flip.svg
new file mode 100644
index 00000000..bc507ca4
--- /dev/null
+++ b/inst/tinytest/_tinysnapshot/spineplot_breaks_flip.svg
@@ -0,0 +1,80 @@
+<?xml version='1.0' encoding='UTF-8' ?>
+<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' class='svglite' width='504.00pt' height='504.00pt' viewBox='0 0 504.00 504.00'>
+<defs>
+  <style type='text/css'><![CDATA[
+    .svglite line, .svglite polyline, .svglite polygon, .svglite path, .svglite rect, .svglite circle {
+      fill: none;
+      stroke: #000000;
+      stroke-linecap: round;
+      stroke-linejoin: round;
+      stroke-miterlimit: 10.00;
+    }
+    .svglite text {
+      white-space: pre;
+    }
+  ]]></style>
+</defs>
+<rect width='100%' height='100%' style='stroke: none; fill: #FFFFFF;'/>
+<defs>
+  <clipPath id='cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA='>
+    <rect x='0.00' y='0.00' width='504.00' height='504.00' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='266.40' y='485.28' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='42.70px' lengthAdjust='spacingAndGlyphs'>Species</text>
+<text transform='translate(12.96,244.80) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='64.70px' lengthAdjust='spacingAndGlyphs'>Sepal.Width</text>
+</g>
+<defs>
+  <clipPath id='cpNTkuMDR8NDczLjc2fDU5LjA0fDQzMC41Ng=='>
+    <rect x='59.04' y='59.04' width='414.72' height='371.52' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpNTkuMDR8NDczLjc2fDU5LjA0fDQzMC41Ng==)'>
+<rect x='59.04' y='383.50' width='109.14' height='47.06' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='168.18' y='383.50' width='283.76' height='47.06' style='stroke-width: 0.75; fill: #AEAEAE;' />
+<rect x='451.93' y='383.50' width='21.83' height='47.06' style='stroke-width: 0.75; fill: #E6E6E6;' />
+<rect x='59.04' y='224.99' width='181.44' height='158.52' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='240.48' y='224.99' width='187.92' height='158.52' style='stroke-width: 0.75; fill: #AEAEAE;' />
+<rect x='428.40' y='224.99' width='45.36' height='158.52' style='stroke-width: 0.75; fill: #E6E6E6;' />
+<rect x='59.04' y='106.10' width='120.96' height='118.89' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='180.00' y='106.10' width='69.12' height='118.89' style='stroke-width: 0.75; fill: #AEAEAE;' />
+<rect x='249.12' y='106.10' width='224.64' height='118.89' style='stroke-width: 0.75; fill: #E6E6E6;' />
+<rect x='59.04' y='66.47' width='77.76' height='39.63' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='136.80' y='66.47' width='0.00' height='39.63' style='stroke-width: 0.75; fill: #AEAEAE;' />
+<rect x='136.80' y='66.47' width='336.96' height='39.63' style='stroke-width: 0.75; fill: #E6E6E6;' />
+<rect x='59.04' y='59.04' width='0.00' height='7.43' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='59.04' y='59.04' width='0.00' height='7.43' style='stroke-width: 0.75; fill: #AEAEAE;' />
+<rect x='59.04' y='59.04' width='414.72' height='7.43' style='stroke-width: 0.75; fill: #E6E6E6;' />
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<line x1='59.04' y1='430.56' x2='59.04' y2='59.04' style='stroke-width: 0.75;' />
+<line x1='59.04' y1='430.56' x2='51.84' y2='430.56' style='stroke-width: 0.75;' />
+<line x1='59.04' y1='383.50' x2='51.84' y2='383.50' style='stroke-width: 0.75;' />
+<line x1='59.04' y1='224.99' x2='51.84' y2='224.99' style='stroke-width: 0.75;' />
+<line x1='59.04' y1='106.10' x2='51.84' y2='106.10' style='stroke-width: 0.75;' />
+<line x1='59.04' y1='66.47' x2='51.84' y2='66.47' style='stroke-width: 0.75;' />
+<line x1='59.04' y1='59.04' x2='51.84' y2='59.04' style='stroke-width: 0.75;' />
+<text transform='translate(41.76,430.56) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='6.67px' lengthAdjust='spacingAndGlyphs'>2</text>
+<text transform='translate(41.76,383.50) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>2.5</text>
+<text transform='translate(41.76,224.99) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='6.67px' lengthAdjust='spacingAndGlyphs'>3</text>
+<text transform='translate(41.76,106.10) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>3.5</text>
+<text transform='translate(41.76,66.47) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='6.67px' lengthAdjust='spacingAndGlyphs'>4</text>
+<text x='128.16' y='41.76' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='44.02px' lengthAdjust='spacingAndGlyphs'>virginica</text>
+<text x='266.40' y='41.76' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='51.36px' lengthAdjust='spacingAndGlyphs'>versicolor</text>
+<text x='404.64' y='41.76' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='35.37px' lengthAdjust='spacingAndGlyphs'>setosa</text>
+<line x1='59.04' y1='430.56' x2='473.76' y2='430.56' style='stroke-width: 0.75;' />
+<line x1='59.04' y1='430.56' x2='59.04' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='141.98' y1='430.56' x2='141.98' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='224.93' y1='430.56' x2='224.93' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='307.87' y1='430.56' x2='307.87' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='390.82' y1='430.56' x2='390.82' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='430.56' x2='473.76' y2='437.76' style='stroke-width: 0.75;' />
+<text x='59.04' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.0</text>
+<text x='141.98' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.2</text>
+<text x='224.93' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.4</text>
+<text x='307.87' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.6</text>
+<text x='390.82' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.8</text>
+<text x='473.76' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>1.0</text>
+<polygon points='59.04,430.56 473.76,430.56 473.76,59.04 59.04,59.04 ' style='stroke-width: 0.75;' />
+</g>
+</svg>
diff --git a/inst/tinytest/_tinysnapshot/spineplot_facet.svg b/inst/tinytest/_tinysnapshot/spineplot_facet.svg
new file mode 100644
index 00000000..927328d1
--- /dev/null
+++ b/inst/tinytest/_tinysnapshot/spineplot_facet.svg
@@ -0,0 +1,152 @@
+<?xml version='1.0' encoding='UTF-8' ?>
+<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' class='svglite' width='504.00pt' height='504.00pt' viewBox='0 0 504.00 504.00'>
+<defs>
+  <style type='text/css'><![CDATA[
+    .svglite line, .svglite polyline, .svglite polygon, .svglite path, .svglite rect, .svglite circle {
+      fill: none;
+      stroke: #000000;
+      stroke-linecap: round;
+      stroke-linejoin: round;
+      stroke-miterlimit: 10.00;
+    }
+    .svglite text {
+      white-space: pre;
+    }
+  ]]></style>
+</defs>
+<rect width='100%' height='100%' style='stroke: none; fill: #FFFFFF;'/>
+<defs>
+  <clipPath id='cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA='>
+    <rect x='0.00' y='0.00' width='504.00' height='504.00' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='266.40' y='485.28' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='20.69px' lengthAdjust='spacingAndGlyphs'>Sex</text>
+<text transform='translate(12.96,244.80) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='46.70px' lengthAdjust='spacingAndGlyphs'>Survived</text>
+</g>
+<defs>
+  <clipPath id='cpNTkuMDR8MjQzLjM2fDU5LjA0fDIxNC41Ng=='>
+    <rect x='59.04' y='59.04' width='184.32' height='155.52' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpNTkuMDR8MjQzLjM2fDU5LjA0fDIxNC41Ng==)'>
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<rect x='59.04' y='43.20' width='184.32' height='15.84' style='stroke-width: 0.75; stroke: none;' />
+<text x='151.20' y='54.26' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.01px' lengthAdjust='spacingAndGlyphs'>1st</text>
+</g>
+<defs>
+  <clipPath id='cpMjg5LjQ0fDQ3My43Nnw1OS4wNHwyMTQuNTY='>
+    <rect x='289.44' y='59.04' width='184.32' height='155.52' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpMjg5LjQ0fDQ3My43Nnw1OS4wNHwyMTQuNTY=)'>
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<rect x='289.44' y='43.20' width='184.32' height='15.84' style='stroke-width: 0.75; stroke: none;' />
+<text x='381.60' y='54.26' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='20.02px' lengthAdjust='spacingAndGlyphs'>2nd</text>
+</g>
+<defs>
+  <clipPath id='cpNTkuMDR8MjQzLjM2fDI3NS4wNHw0MzAuNTY='>
+    <rect x='59.04' y='275.04' width='184.32' height='155.52' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpNTkuMDR8MjQzLjM2fDI3NS4wNHw0MzAuNTY=)'>
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<rect x='59.04' y='259.20' width='184.32' height='15.84' style='stroke-width: 0.75; stroke: none;' />
+<text x='151.20' y='270.26' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='17.34px' lengthAdjust='spacingAndGlyphs'>3rd</text>
+</g>
+<defs>
+  <clipPath id='cpMjg5LjQ0fDQ3My43NnwyNzUuMDR8NDMwLjU2'>
+    <rect x='289.44' y='275.04' width='184.32' height='155.52' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpMjg5LjQ0fDQ3My43NnwyNzUuMDR8NDMwLjU2)'>
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<rect x='289.44' y='259.20' width='184.32' height='15.84' style='stroke-width: 0.75; stroke: none;' />
+<text x='381.60' y='270.26' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='28.01px' lengthAdjust='spacingAndGlyphs'>Crew</text>
+</g>
+<g clip-path='url(#cpNTkuMDR8MjQzLjM2fDU5LjA0fDIxNC41Ng==)'>
+<rect x='59.04' y='160.99' width='100.08' height='53.57' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='59.04' y='59.04' width='100.08' height='101.95' style='stroke-width: 0.75; fill: #E6E6E6;' />
+<rect x='162.74' y='63.33' width='80.62' height='151.23' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='162.74' y='59.04' width='80.62' height='4.29' style='stroke-width: 0.75; fill: #E6E6E6;' />
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='109.08' y='236.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='21.57px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='203.05' y='236.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='33.18px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(44.70,187.78) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='16.24px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(44.70,110.02) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='12.72px' lengthAdjust='spacingAndGlyphs'>No</text>
+</g>
+<g clip-path='url(#cpMjg5LjQ0fDQ3My43Nnw1OS4wNHwyMTQuNTY=)'>
+<rect x='289.44' y='192.84' width='113.50' height='21.72' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='289.44' y='59.04' width='113.50' height='133.80' style='stroke-width: 0.75; fill: #E6E6E6;' />
+<rect x='406.55' y='78.11' width='67.21' height='136.45' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='406.55' y='59.04' width='67.21' height='19.07' style='stroke-width: 0.75; fill: #E6E6E6;' />
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='346.19' y='236.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='21.57px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='440.16' y='236.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='33.18px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(275.10,203.70) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='16.24px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(275.10,125.94) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='12.72px' lengthAdjust='spacingAndGlyphs'>No</text>
+<line x1='473.76' y1='214.56' x2='473.76' y2='59.04' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='214.56' x2='479.74' y2='214.56' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='183.46' x2='479.74' y2='183.46' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='152.35' x2='479.74' y2='152.35' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='121.25' x2='479.74' y2='121.25' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='90.14' x2='479.74' y2='90.14' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='59.04' x2='479.74' y2='59.04' style='stroke-width: 0.75;' />
+<text transform='translate(495.27,214.56) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.0</text>
+<text transform='translate(495.27,183.46) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.2</text>
+<text transform='translate(495.27,152.35) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.4</text>
+<text transform='translate(495.27,121.25) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.6</text>
+<text transform='translate(495.27,90.14) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.8</text>
+<text transform='translate(495.27,59.04) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>1.0</text>
+</g>
+<g clip-path='url(#cpNTkuMDR8MjQzLjM2fDI3NS4wNHw0MzAuNTY=)'>
+<rect x='59.04' y='403.73' width='130.54' height='26.83' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='59.04' y='275.04' width='130.54' height='128.69' style='stroke-width: 0.75; fill: #E6E6E6;' />
+<rect x='193.19' y='359.15' width='50.17' height='71.41' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='193.19' y='275.04' width='50.17' height='84.11' style='stroke-width: 0.75; fill: #E6E6E6;' />
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='124.31' y='452.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='21.57px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='218.28' y='452.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='33.18px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(44.70,417.14) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='16.24px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(44.70,339.38) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='12.72px' lengthAdjust='spacingAndGlyphs'>No</text>
+</g>
+<g clip-path='url(#cpMjg5LjQ0fDQ3My43NnwyNzUuMDR8NDMwLjU2)'>
+<rect x='289.44' y='395.92' width='176.01' height='34.64' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='289.44' y='275.04' width='176.01' height='120.88' style='stroke-width: 0.75; fill: #E6E6E6;' />
+<rect x='469.06' y='295.33' width='4.70' height='135.23' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='469.06' y='275.04' width='4.70' height='20.29' style='stroke-width: 0.75; fill: #E6E6E6;' />
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='377.44' y='452.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='21.57px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='471.41' y='452.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='33.18px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(275.10,413.24) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='16.24px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(275.10,335.48) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='12.72px' lengthAdjust='spacingAndGlyphs'>No</text>
+<line x1='473.76' y1='430.56' x2='473.76' y2='275.04' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='430.56' x2='479.74' y2='430.56' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='399.46' x2='479.74' y2='399.46' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='368.35' x2='479.74' y2='368.35' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='337.25' x2='479.74' y2='337.25' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='306.14' x2='479.74' y2='306.14' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='275.04' x2='479.74' y2='275.04' style='stroke-width: 0.75;' />
+<text transform='translate(495.27,430.56) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.0</text>
+<text transform='translate(495.27,399.46) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.2</text>
+<text transform='translate(495.27,368.35) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.4</text>
+<text transform='translate(495.27,337.25) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.6</text>
+<text transform='translate(495.27,306.14) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.8</text>
+<text transform='translate(495.27,275.04) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>1.0</text>
+</g>
+<defs>
+  <clipPath id='cpMTAyLjQxfDQ2NS4wOXw4NS4wNnwzNjkuODQ='>
+    <rect x='102.41' y='85.06' width='362.67' height='284.77' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpMTAyLjQxfDQ2NS4wOXw4NS4wNnwzNjkuODQ=)'>
+</g>
+</svg>
diff --git a/inst/tinytest/_tinysnapshot/spineplot_facet_by.svg b/inst/tinytest/_tinysnapshot/spineplot_facet_by.svg
new file mode 100644
index 00000000..e9aba91e
--- /dev/null
+++ b/inst/tinytest/_tinysnapshot/spineplot_facet_by.svg
@@ -0,0 +1,342 @@
+<?xml version='1.0' encoding='UTF-8' ?>
+<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' class='svglite' width='504.00pt' height='504.00pt' viewBox='0 0 504.00 504.00'>
+<defs>
+  <style type='text/css'><![CDATA[
+    .svglite line, .svglite polyline, .svglite polygon, .svglite path, .svglite rect, .svglite circle {
+      fill: none;
+      stroke: #000000;
+      stroke-linecap: round;
+      stroke-linejoin: round;
+      stroke-miterlimit: 10.00;
+    }
+    .svglite text {
+      white-space: pre;
+    }
+  ]]></style>
+</defs>
+<rect width='100%' height='100%' style='stroke: none; fill: #FFFFFF;'/>
+<defs>
+  <clipPath id='cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA='>
+    <rect x='0.00' y='0.00' width='504.00' height='504.00' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<rect x='449.98' y='218.43' width='16.75' height='16.75' style='stroke-width: 0.00; fill: #000000;' />
+<rect x='449.98' y='236.43' width='16.75' height='16.75' style='stroke-width: 0.00; stroke: #DF536B; fill: #DF536B;' />
+<rect x='449.98' y='254.43' width='16.75' height='16.75' style='stroke-width: 0.00; stroke: #61D04F; fill: #61D04F;' />
+<rect x='449.98' y='272.43' width='16.75' height='16.75' style='stroke-width: 0.00; stroke: #2297E6; fill: #2297E6;' />
+<text x='475.06' y='207.00' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='30.02px' lengthAdjust='spacingAndGlyphs'>Class</text>
+<text x='469.15' y='230.93' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.01px' lengthAdjust='spacingAndGlyphs'>1st</text>
+<text x='469.15' y='248.93' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='20.02px' lengthAdjust='spacingAndGlyphs'>2nd</text>
+<text x='469.15' y='266.93' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='17.34px' lengthAdjust='spacingAndGlyphs'>3rd</text>
+<text x='469.15' y='284.93' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='28.01px' lengthAdjust='spacingAndGlyphs'>Crew</text>
+</g>
+<defs>
+  <clipPath id='cpMC4wMHw0MTcuMzF8MC4wMHw1MDQuMDA='>
+    <rect x='0.00' y='0.00' width='417.31' height='504.00' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpMC4wMHw0MTcuMzF8MC4wMHw1MDQuMDA=)'>
+<text x='238.18' y='485.28' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='20.69px' lengthAdjust='spacingAndGlyphs'>Sex</text>
+<text transform='translate(12.96,244.80) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='46.70px' lengthAdjust='spacingAndGlyphs'>Survived</text>
+</g>
+<defs>
+  <clipPath id='cpNTkuMDR8MjE1LjE0fDU5LjA0fDIxNC41Ng=='>
+    <rect x='59.04' y='59.04' width='156.10' height='155.52' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpNTkuMDR8MjE1LjE0fDU5LjA0fDIxNC41Ng==)'>
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<rect x='59.04' y='43.20' width='156.10' height='15.84' style='stroke-width: 0.75; stroke: none;' />
+<text x='137.09' y='54.26' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.01px' lengthAdjust='spacingAndGlyphs'>1st</text>
+</g>
+<defs>
+  <clipPath id='cpMjYxLjIyfDQxNy4zMXw1OS4wNHwyMTQuNTY='>
+    <rect x='261.22' y='59.04' width='156.10' height='155.52' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpMjYxLjIyfDQxNy4zMXw1OS4wNHwyMTQuNTY=)'>
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<rect x='261.22' y='43.20' width='156.10' height='15.84' style='stroke-width: 0.75; stroke: none;' />
+<text x='339.26' y='54.26' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='20.02px' lengthAdjust='spacingAndGlyphs'>2nd</text>
+</g>
+<defs>
+  <clipPath id='cpNTkuMDR8MjE1LjE0fDI3NS4wNHw0MzAuNTY='>
+    <rect x='59.04' y='275.04' width='156.10' height='155.52' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpNTkuMDR8MjE1LjE0fDI3NS4wNHw0MzAuNTY=)'>
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<rect x='59.04' y='259.20' width='156.10' height='15.84' style='stroke-width: 0.75; stroke: none;' />
+<text x='137.09' y='270.26' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='17.34px' lengthAdjust='spacingAndGlyphs'>3rd</text>
+</g>
+<defs>
+  <clipPath id='cpMjYxLjIyfDQxNy4zMXwyNzUuMDR8NDMwLjU2'>
+    <rect x='261.22' y='275.04' width='156.10' height='155.52' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpMjYxLjIyfDQxNy4zMXwyNzUuMDR8NDMwLjU2)'>
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<rect x='261.22' y='259.20' width='156.10' height='15.84' style='stroke-width: 0.75; stroke: none;' />
+<text x='339.26' y='270.26' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='28.01px' lengthAdjust='spacingAndGlyphs'>Crew</text>
+</g>
+<g clip-path='url(#cpNTkuMDR8MjE1LjE0fDU5LjA0fDIxNC41Ng==)'>
+<rect x='59.04' y='160.99' width='84.76' height='53.57' style='stroke-width: 0.75; fill: #000000;' />
+<rect x='59.04' y='59.04' width='84.76' height='101.95' style='stroke-width: 0.75; fill: #E8E8E8;' />
+<rect x='146.86' y='63.33' width='68.28' height='151.23' style='stroke-width: 0.75; fill: #000000;' />
+<rect x='146.86' y='59.04' width='68.28' height='4.29' style='stroke-width: 0.75; fill: #E8E8E8;' />
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='101.42' y='236.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='21.57px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='181.00' y='236.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='33.18px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(44.70,187.78) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='16.24px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(44.70,110.02) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='12.72px' lengthAdjust='spacingAndGlyphs'>No</text>
+</g>
+<g clip-path='url(#cpMjYxLjIyfDQxNy4zMXw1OS4wNHwyMTQuNTY=)'>
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='309.27' y='236.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='21.57px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='388.85' y='236.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='33.18px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(246.87,203.70) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='16.24px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(246.87,125.94) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='12.72px' lengthAdjust='spacingAndGlyphs'>No</text>
+<line x1='417.31' y1='214.56' x2='417.31' y2='59.04' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='214.56' x2='423.29' y2='214.56' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='183.46' x2='423.29' y2='183.46' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='152.35' x2='423.29' y2='152.35' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='121.25' x2='423.29' y2='121.25' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='90.14' x2='423.29' y2='90.14' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='59.04' x2='423.29' y2='59.04' style='stroke-width: 0.75;' />
+<text transform='translate(438.83,214.56) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.0</text>
+<text transform='translate(438.83,183.46) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.2</text>
+<text transform='translate(438.83,152.35) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.4</text>
+<text transform='translate(438.83,121.25) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.6</text>
+<text transform='translate(438.83,90.14) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.8</text>
+<text transform='translate(438.83,59.04) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>1.0</text>
+</g>
+<g clip-path='url(#cpNTkuMDR8MjE1LjE0fDI3NS4wNHw0MzAuNTY=)'>
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='114.31' y='452.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='21.57px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='193.89' y='452.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='33.18px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(44.70,417.14) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='16.24px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(44.70,339.38) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='12.72px' lengthAdjust='spacingAndGlyphs'>No</text>
+</g>
+<g clip-path='url(#cpMjYxLjIyfDQxNy4zMXwyNzUuMDR8NDMwLjU2)'>
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='335.75' y='452.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='21.57px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='415.32' y='452.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='33.18px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(246.87,413.24) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='16.24px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(246.87,335.48) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='12.72px' lengthAdjust='spacingAndGlyphs'>No</text>
+<line x1='417.31' y1='430.56' x2='417.31' y2='275.04' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='430.56' x2='423.29' y2='430.56' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='399.46' x2='423.29' y2='399.46' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='368.35' x2='423.29' y2='368.35' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='337.25' x2='423.29' y2='337.25' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='306.14' x2='423.29' y2='306.14' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='275.04' x2='423.29' y2='275.04' style='stroke-width: 0.75;' />
+<text transform='translate(438.83,430.56) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.0</text>
+<text transform='translate(438.83,399.46) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.2</text>
+<text transform='translate(438.83,368.35) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.4</text>
+<text transform='translate(438.83,337.25) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.6</text>
+<text transform='translate(438.83,306.14) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.8</text>
+<text transform='translate(438.83,275.04) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>1.0</text>
+</g>
+<g clip-path='url(#cpNTkuMDR8MjE1LjE0fDU5LjA0fDIxNC41Ng==)'>
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='101.42' y='236.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='21.57px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='181.00' y='236.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='33.18px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(44.70,187.78) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='16.24px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(44.70,110.02) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='12.72px' lengthAdjust='spacingAndGlyphs'>No</text>
+</g>
+<g clip-path='url(#cpMjYxLjIyfDQxNy4zMXw1OS4wNHwyMTQuNTY=)'>
+<rect x='261.22' y='192.84' width='96.12' height='21.72' style='stroke-width: 0.75; fill: #E0536B;' />
+<rect x='261.22' y='59.04' width='96.12' height='133.80' style='stroke-width: 0.75; fill: #FFDAE0;' />
+<rect x='360.39' y='78.11' width='56.92' height='136.45' style='stroke-width: 0.75; fill: #E0536B;' />
+<rect x='360.39' y='59.04' width='56.92' height='19.07' style='stroke-width: 0.75; fill: #FFDAE0;' />
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='309.27' y='236.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='21.57px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='388.85' y='236.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='33.18px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(246.87,203.70) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='16.24px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(246.87,125.94) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='12.72px' lengthAdjust='spacingAndGlyphs'>No</text>
+<line x1='417.31' y1='214.56' x2='417.31' y2='59.04' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='214.56' x2='423.29' y2='214.56' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='183.46' x2='423.29' y2='183.46' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='152.35' x2='423.29' y2='152.35' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='121.25' x2='423.29' y2='121.25' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='90.14' x2='423.29' y2='90.14' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='59.04' x2='423.29' y2='59.04' style='stroke-width: 0.75;' />
+<text transform='translate(438.83,214.56) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.0</text>
+<text transform='translate(438.83,183.46) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.2</text>
+<text transform='translate(438.83,152.35) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.4</text>
+<text transform='translate(438.83,121.25) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.6</text>
+<text transform='translate(438.83,90.14) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.8</text>
+<text transform='translate(438.83,59.04) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>1.0</text>
+</g>
+<g clip-path='url(#cpNTkuMDR8MjE1LjE0fDI3NS4wNHw0MzAuNTY=)'>
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='114.31' y='452.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='21.57px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='193.89' y='452.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='33.18px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(44.70,417.14) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='16.24px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(44.70,339.38) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='12.72px' lengthAdjust='spacingAndGlyphs'>No</text>
+</g>
+<g clip-path='url(#cpMjYxLjIyfDQxNy4zMXwyNzUuMDR8NDMwLjU2)'>
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='335.75' y='452.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='21.57px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='415.32' y='452.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='33.18px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(246.87,413.24) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='16.24px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(246.87,335.48) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='12.72px' lengthAdjust='spacingAndGlyphs'>No</text>
+<line x1='417.31' y1='430.56' x2='417.31' y2='275.04' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='430.56' x2='423.29' y2='430.56' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='399.46' x2='423.29' y2='399.46' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='368.35' x2='423.29' y2='368.35' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='337.25' x2='423.29' y2='337.25' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='306.14' x2='423.29' y2='306.14' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='275.04' x2='423.29' y2='275.04' style='stroke-width: 0.75;' />
+<text transform='translate(438.83,430.56) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.0</text>
+<text transform='translate(438.83,399.46) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.2</text>
+<text transform='translate(438.83,368.35) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.4</text>
+<text transform='translate(438.83,337.25) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.6</text>
+<text transform='translate(438.83,306.14) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.8</text>
+<text transform='translate(438.83,275.04) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>1.0</text>
+</g>
+<g clip-path='url(#cpNTkuMDR8MjE1LjE0fDU5LjA0fDIxNC41Ng==)'>
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='101.42' y='236.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='21.57px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='181.00' y='236.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='33.18px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(44.70,187.78) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='16.24px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(44.70,110.02) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='12.72px' lengthAdjust='spacingAndGlyphs'>No</text>
+</g>
+<g clip-path='url(#cpMjYxLjIyfDQxNy4zMXw1OS4wNHwyMTQuNTY=)'>
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='309.27' y='236.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='21.57px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='388.85' y='236.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='33.18px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(246.87,203.70) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='16.24px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(246.87,125.94) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='12.72px' lengthAdjust='spacingAndGlyphs'>No</text>
+<line x1='417.31' y1='214.56' x2='417.31' y2='59.04' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='214.56' x2='423.29' y2='214.56' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='183.46' x2='423.29' y2='183.46' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='152.35' x2='423.29' y2='152.35' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='121.25' x2='423.29' y2='121.25' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='90.14' x2='423.29' y2='90.14' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='59.04' x2='423.29' y2='59.04' style='stroke-width: 0.75;' />
+<text transform='translate(438.83,214.56) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.0</text>
+<text transform='translate(438.83,183.46) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.2</text>
+<text transform='translate(438.83,152.35) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.4</text>
+<text transform='translate(438.83,121.25) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.6</text>
+<text transform='translate(438.83,90.14) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.8</text>
+<text transform='translate(438.83,59.04) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>1.0</text>
+</g>
+<g clip-path='url(#cpNTkuMDR8MjE1LjE0fDI3NS4wNHw0MzAuNTY=)'>
+<rect x='59.04' y='403.73' width='110.55' height='26.83' style='stroke-width: 0.75; fill: #60D050;' />
+<rect x='59.04' y='275.04' width='110.55' height='128.69' style='stroke-width: 0.75; fill: #CDF2CA;' />
+<rect x='172.65' y='359.15' width='42.49' height='71.41' style='stroke-width: 0.75; fill: #60D050;' />
+<rect x='172.65' y='275.04' width='42.49' height='84.11' style='stroke-width: 0.75; fill: #CDF2CA;' />
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='114.31' y='452.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='21.57px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='193.89' y='452.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='33.18px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(44.70,417.14) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='16.24px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(44.70,339.38) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='12.72px' lengthAdjust='spacingAndGlyphs'>No</text>
+</g>
+<g clip-path='url(#cpMjYxLjIyfDQxNy4zMXwyNzUuMDR8NDMwLjU2)'>
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='335.75' y='452.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='21.57px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='415.32' y='452.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='33.18px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(246.87,413.24) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='16.24px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(246.87,335.48) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='12.72px' lengthAdjust='spacingAndGlyphs'>No</text>
+<line x1='417.31' y1='430.56' x2='417.31' y2='275.04' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='430.56' x2='423.29' y2='430.56' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='399.46' x2='423.29' y2='399.46' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='368.35' x2='423.29' y2='368.35' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='337.25' x2='423.29' y2='337.25' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='306.14' x2='423.29' y2='306.14' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='275.04' x2='423.29' y2='275.04' style='stroke-width: 0.75;' />
+<text transform='translate(438.83,430.56) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.0</text>
+<text transform='translate(438.83,399.46) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.2</text>
+<text transform='translate(438.83,368.35) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.4</text>
+<text transform='translate(438.83,337.25) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.6</text>
+<text transform='translate(438.83,306.14) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.8</text>
+<text transform='translate(438.83,275.04) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>1.0</text>
+</g>
+<g clip-path='url(#cpNTkuMDR8MjE1LjE0fDU5LjA0fDIxNC41Ng==)'>
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='101.42' y='236.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='21.57px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='181.00' y='236.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='33.18px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(44.70,187.78) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='16.24px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(44.70,110.02) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='12.72px' lengthAdjust='spacingAndGlyphs'>No</text>
+</g>
+<g clip-path='url(#cpMjYxLjIyfDQxNy4zMXw1OS4wNHwyMTQuNTY=)'>
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='309.27' y='236.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='21.57px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='388.85' y='236.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='33.18px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(246.87,203.70) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='16.24px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(246.87,125.94) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='12.72px' lengthAdjust='spacingAndGlyphs'>No</text>
+<line x1='417.31' y1='214.56' x2='417.31' y2='59.04' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='214.56' x2='423.29' y2='214.56' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='183.46' x2='423.29' y2='183.46' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='152.35' x2='423.29' y2='152.35' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='121.25' x2='423.29' y2='121.25' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='90.14' x2='423.29' y2='90.14' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='59.04' x2='423.29' y2='59.04' style='stroke-width: 0.75;' />
+<text transform='translate(438.83,214.56) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.0</text>
+<text transform='translate(438.83,183.46) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.2</text>
+<text transform='translate(438.83,152.35) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.4</text>
+<text transform='translate(438.83,121.25) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.6</text>
+<text transform='translate(438.83,90.14) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.8</text>
+<text transform='translate(438.83,59.04) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>1.0</text>
+</g>
+<g clip-path='url(#cpNTkuMDR8MjE1LjE0fDI3NS4wNHw0MzAuNTY=)'>
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='114.31' y='452.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='21.57px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='193.89' y='452.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='33.18px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(44.70,417.14) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='16.24px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(44.70,339.38) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='12.72px' lengthAdjust='spacingAndGlyphs'>No</text>
+</g>
+<g clip-path='url(#cpMjYxLjIyfDQxNy4zMXwyNzUuMDR8NDMwLjU2)'>
+<rect x='261.22' y='395.92' width='149.06' height='34.64' style='stroke-width: 0.75; fill: #1D97E6;' />
+<rect x='261.22' y='275.04' width='149.06' height='120.88' style='stroke-width: 0.75; fill: #D4EAFF;' />
+<rect x='413.33' y='295.33' width='3.98' height='135.23' style='stroke-width: 0.75; fill: #1D97E6;' />
+<rect x='413.33' y='275.04' width='3.98' height='20.29' style='stroke-width: 0.75; fill: #D4EAFF;' />
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='335.75' y='452.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='21.57px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='415.32' y='452.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='33.18px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(246.87,413.24) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='16.24px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(246.87,335.48) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='12.72px' lengthAdjust='spacingAndGlyphs'>No</text>
+<line x1='417.31' y1='430.56' x2='417.31' y2='275.04' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='430.56' x2='423.29' y2='430.56' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='399.46' x2='423.29' y2='399.46' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='368.35' x2='423.29' y2='368.35' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='337.25' x2='423.29' y2='337.25' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='306.14' x2='423.29' y2='306.14' style='stroke-width: 0.75;' />
+<line x1='417.31' y1='275.04' x2='423.29' y2='275.04' style='stroke-width: 0.75;' />
+<text transform='translate(438.83,430.56) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.0</text>
+<text transform='translate(438.83,399.46) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.2</text>
+<text transform='translate(438.83,368.35) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.4</text>
+<text transform='translate(438.83,337.25) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.6</text>
+<text transform='translate(438.83,306.14) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.8</text>
+<text transform='translate(438.83,275.04) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>1.0</text>
+</g>
+<defs>
+  <clipPath id='cpMTAyLjQxfDM5Ny4wOHw4NS4wNnwzNjkuODQ='>
+    <rect x='102.41' y='85.06' width='294.66' height='284.77' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpMTAyLjQxfDM5Ny4wOHw4NS4wNnwzNjkuODQ=)'>
+</g>
+</svg>
diff --git a/inst/tinytest/_tinysnapshot/spineplot_facet_by_fancy.svg b/inst/tinytest/_tinysnapshot/spineplot_facet_by_fancy.svg
new file mode 100644
index 00000000..b9e218ff
--- /dev/null
+++ b/inst/tinytest/_tinysnapshot/spineplot_facet_by_fancy.svg
@@ -0,0 +1,318 @@
+<?xml version='1.0' encoding='UTF-8' ?>
+<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' class='svglite' width='504.00pt' height='504.00pt' viewBox='0 0 504.00 504.00'>
+<defs>
+  <style type='text/css'><![CDATA[
+    .svglite line, .svglite polyline, .svglite polygon, .svglite path, .svglite rect, .svglite circle {
+      fill: none;
+      stroke: #000000;
+      stroke-linecap: round;
+      stroke-linejoin: round;
+      stroke-miterlimit: 10.00;
+    }
+    .svglite text {
+      white-space: pre;
+    }
+  ]]></style>
+</defs>
+<rect width='100%' height='100%' style='stroke: none; fill: #FFFFFF;'/>
+<defs>
+  <clipPath id='cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA='>
+    <rect x='0.00' y='0.00' width='504.00' height='504.00' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='266.40' y='485.28' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='20.69px' lengthAdjust='spacingAndGlyphs'>Sex</text>
+<text transform='translate(12.96,244.80) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='46.70px' lengthAdjust='spacingAndGlyphs'>Survived</text>
+</g>
+<defs>
+  <clipPath id='cpNTkuMDR8MjQzLjM2fDU5LjA0fDIxNC41Ng=='>
+    <rect x='59.04' y='59.04' width='184.32' height='155.52' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpNTkuMDR8MjQzLjM2fDU5LjA0fDIxNC41Ng==)'>
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<rect x='59.04' y='43.20' width='184.32' height='15.84' style='stroke-width: 0.75; stroke: none;' />
+<text x='151.20' y='54.26' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.01px' lengthAdjust='spacingAndGlyphs'>1st</text>
+</g>
+<defs>
+  <clipPath id='cpMjg5LjQ0fDQ3My43Nnw1OS4wNHwyMTQuNTY='>
+    <rect x='289.44' y='59.04' width='184.32' height='155.52' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpMjg5LjQ0fDQ3My43Nnw1OS4wNHwyMTQuNTY=)'>
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<rect x='289.44' y='43.20' width='184.32' height='15.84' style='stroke-width: 0.75; stroke: none;' />
+<text x='381.60' y='54.26' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='20.02px' lengthAdjust='spacingAndGlyphs'>2nd</text>
+</g>
+<defs>
+  <clipPath id='cpNTkuMDR8MjQzLjM2fDI3NS4wNHw0MzAuNTY='>
+    <rect x='59.04' y='275.04' width='184.32' height='155.52' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpNTkuMDR8MjQzLjM2fDI3NS4wNHw0MzAuNTY=)'>
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<rect x='59.04' y='259.20' width='184.32' height='15.84' style='stroke-width: 0.75; stroke: none;' />
+<text x='151.20' y='270.26' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='17.34px' lengthAdjust='spacingAndGlyphs'>3rd</text>
+</g>
+<defs>
+  <clipPath id='cpMjg5LjQ0fDQ3My43NnwyNzUuMDR8NDMwLjU2'>
+    <rect x='289.44' y='275.04' width='184.32' height='155.52' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpMjg5LjQ0fDQ3My43NnwyNzUuMDR8NDMwLjU2)'>
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<rect x='289.44' y='259.20' width='184.32' height='15.84' style='stroke-width: 0.75; stroke: none;' />
+<text x='381.60' y='270.26' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='28.01px' lengthAdjust='spacingAndGlyphs'>Crew</text>
+</g>
+<g clip-path='url(#cpNTkuMDR8MjQzLjM2fDU5LjA0fDIxNC41Ng==)'>
+<rect x='59.04' y='160.99' width='100.08' height='53.57' style='stroke-width: 0.00; fill: #179E77;' />
+<rect x='59.04' y='59.04' width='100.08' height='101.95' style='stroke-width: 0.00; fill: #CFEFE1;' />
+<rect x='162.74' y='63.33' width='80.62' height='151.23' style='stroke-width: 0.00; fill: #179E77;' />
+<rect x='162.74' y='59.04' width='80.62' height='4.29' style='stroke-width: 0.00; fill: #CFEFE1;' />
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='109.08' y='236.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='21.57px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='203.05' y='236.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='33.18px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(44.70,187.78) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='16.24px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(44.70,110.02) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='12.72px' lengthAdjust='spacingAndGlyphs'>No</text>
+</g>
+<g clip-path='url(#cpMjg5LjQ0fDQ3My43Nnw1OS4wNHwyMTQuNTY=)'>
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='346.19' y='236.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='21.57px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='440.16' y='236.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='33.18px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(275.10,203.70) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='16.24px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(275.10,125.94) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='12.72px' lengthAdjust='spacingAndGlyphs'>No</text>
+<line x1='473.76' y1='214.56' x2='479.74' y2='214.56' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='183.46' x2='479.74' y2='183.46' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='152.35' x2='479.74' y2='152.35' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='121.25' x2='479.74' y2='121.25' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='90.14' x2='479.74' y2='90.14' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='59.04' x2='479.74' y2='59.04' style='stroke-width: 0.75;' />
+<text transform='translate(495.27,214.56) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.0</text>
+<text transform='translate(495.27,183.46) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.2</text>
+<text transform='translate(495.27,152.35) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.4</text>
+<text transform='translate(495.27,121.25) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.6</text>
+<text transform='translate(495.27,90.14) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.8</text>
+<text transform='translate(495.27,59.04) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>1.0</text>
+</g>
+<g clip-path='url(#cpNTkuMDR8MjQzLjM2fDI3NS4wNHw0MzAuNTY=)'>
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='124.31' y='452.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='21.57px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='218.28' y='452.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='33.18px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(44.70,417.14) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='16.24px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(44.70,339.38) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='12.72px' lengthAdjust='spacingAndGlyphs'>No</text>
+</g>
+<g clip-path='url(#cpMjg5LjQ0fDQ3My43NnwyNzUuMDR8NDMwLjU2)'>
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='377.44' y='452.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='21.57px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='471.41' y='452.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='33.18px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(275.10,413.24) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='16.24px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(275.10,335.48) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='12.72px' lengthAdjust='spacingAndGlyphs'>No</text>
+<line x1='473.76' y1='430.56' x2='479.74' y2='430.56' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='399.46' x2='479.74' y2='399.46' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='368.35' x2='479.74' y2='368.35' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='337.25' x2='479.74' y2='337.25' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='306.14' x2='479.74' y2='306.14' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='275.04' x2='479.74' y2='275.04' style='stroke-width: 0.75;' />
+<text transform='translate(495.27,430.56) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.0</text>
+<text transform='translate(495.27,399.46) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.2</text>
+<text transform='translate(495.27,368.35) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.4</text>
+<text transform='translate(495.27,337.25) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.6</text>
+<text transform='translate(495.27,306.14) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.8</text>
+<text transform='translate(495.27,275.04) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>1.0</text>
+</g>
+<g clip-path='url(#cpNTkuMDR8MjQzLjM2fDU5LjA0fDIxNC41Ng==)'>
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='109.08' y='236.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='21.57px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='203.05' y='236.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='33.18px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(44.70,187.78) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='16.24px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(44.70,110.02) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='12.72px' lengthAdjust='spacingAndGlyphs'>No</text>
+</g>
+<g clip-path='url(#cpMjg5LjQ0fDQ3My43Nnw1OS4wNHwyMTQuNTY=)'>
+<rect x='289.44' y='192.84' width='113.50' height='21.72' style='stroke-width: 0.00; fill: #DA5F04;' />
+<rect x='289.44' y='59.04' width='113.50' height='133.80' style='stroke-width: 0.00; fill: #FFDBCE;' />
+<rect x='406.55' y='78.11' width='67.21' height='136.45' style='stroke-width: 0.00; fill: #DA5F04;' />
+<rect x='406.55' y='59.04' width='67.21' height='19.07' style='stroke-width: 0.00; fill: #FFDBCE;' />
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='346.19' y='236.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='21.57px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='440.16' y='236.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='33.18px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(275.10,203.70) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='16.24px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(275.10,125.94) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='12.72px' lengthAdjust='spacingAndGlyphs'>No</text>
+<line x1='473.76' y1='214.56' x2='479.74' y2='214.56' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='183.46' x2='479.74' y2='183.46' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='152.35' x2='479.74' y2='152.35' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='121.25' x2='479.74' y2='121.25' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='90.14' x2='479.74' y2='90.14' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='59.04' x2='479.74' y2='59.04' style='stroke-width: 0.75;' />
+<text transform='translate(495.27,214.56) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.0</text>
+<text transform='translate(495.27,183.46) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.2</text>
+<text transform='translate(495.27,152.35) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.4</text>
+<text transform='translate(495.27,121.25) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.6</text>
+<text transform='translate(495.27,90.14) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.8</text>
+<text transform='translate(495.27,59.04) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>1.0</text>
+</g>
+<g clip-path='url(#cpNTkuMDR8MjQzLjM2fDI3NS4wNHw0MzAuNTY=)'>
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='124.31' y='452.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='21.57px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='218.28' y='452.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='33.18px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(44.70,417.14) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='16.24px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(44.70,339.38) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='12.72px' lengthAdjust='spacingAndGlyphs'>No</text>
+</g>
+<g clip-path='url(#cpMjg5LjQ0fDQ3My43NnwyNzUuMDR8NDMwLjU2)'>
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='377.44' y='452.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='21.57px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='471.41' y='452.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='33.18px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(275.10,413.24) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='16.24px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(275.10,335.48) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='12.72px' lengthAdjust='spacingAndGlyphs'>No</text>
+<line x1='473.76' y1='430.56' x2='479.74' y2='430.56' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='399.46' x2='479.74' y2='399.46' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='368.35' x2='479.74' y2='368.35' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='337.25' x2='479.74' y2='337.25' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='306.14' x2='479.74' y2='306.14' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='275.04' x2='479.74' y2='275.04' style='stroke-width: 0.75;' />
+<text transform='translate(495.27,430.56) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.0</text>
+<text transform='translate(495.27,399.46) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.2</text>
+<text transform='translate(495.27,368.35) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.4</text>
+<text transform='translate(495.27,337.25) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.6</text>
+<text transform='translate(495.27,306.14) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.8</text>
+<text transform='translate(495.27,275.04) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>1.0</text>
+</g>
+<g clip-path='url(#cpNTkuMDR8MjQzLjM2fDU5LjA0fDIxNC41Ng==)'>
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='109.08' y='236.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='21.57px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='203.05' y='236.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='33.18px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(44.70,187.78) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='16.24px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(44.70,110.02) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='12.72px' lengthAdjust='spacingAndGlyphs'>No</text>
+</g>
+<g clip-path='url(#cpMjg5LjQ0fDQ3My43Nnw1OS4wNHwyMTQuNTY=)'>
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='346.19' y='236.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='21.57px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='440.16' y='236.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='33.18px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(275.10,203.70) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='16.24px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(275.10,125.94) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='12.72px' lengthAdjust='spacingAndGlyphs'>No</text>
+<line x1='473.76' y1='214.56' x2='479.74' y2='214.56' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='183.46' x2='479.74' y2='183.46' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='152.35' x2='479.74' y2='152.35' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='121.25' x2='479.74' y2='121.25' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='90.14' x2='479.74' y2='90.14' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='59.04' x2='479.74' y2='59.04' style='stroke-width: 0.75;' />
+<text transform='translate(495.27,214.56) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.0</text>
+<text transform='translate(495.27,183.46) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.2</text>
+<text transform='translate(495.27,152.35) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.4</text>
+<text transform='translate(495.27,121.25) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.6</text>
+<text transform='translate(495.27,90.14) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.8</text>
+<text transform='translate(495.27,59.04) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>1.0</text>
+</g>
+<g clip-path='url(#cpNTkuMDR8MjQzLjM2fDI3NS4wNHw0MzAuNTY=)'>
+<rect x='59.04' y='403.73' width='130.54' height='26.83' style='stroke-width: 0.00; fill: #7570B3;' />
+<rect x='59.04' y='275.04' width='130.54' height='128.69' style='stroke-width: 0.00; fill: #E7E6FE;' />
+<rect x='193.19' y='359.15' width='50.17' height='71.41' style='stroke-width: 0.00; fill: #7570B3;' />
+<rect x='193.19' y='275.04' width='50.17' height='84.11' style='stroke-width: 0.00; fill: #E7E6FE;' />
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='124.31' y='452.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='21.57px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='218.28' y='452.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='33.18px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(44.70,417.14) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='16.24px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(44.70,339.38) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='12.72px' lengthAdjust='spacingAndGlyphs'>No</text>
+</g>
+<g clip-path='url(#cpMjg5LjQ0fDQ3My43NnwyNzUuMDR8NDMwLjU2)'>
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='377.44' y='452.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='21.57px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='471.41' y='452.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='33.18px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(275.10,413.24) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='16.24px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(275.10,335.48) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='12.72px' lengthAdjust='spacingAndGlyphs'>No</text>
+<line x1='473.76' y1='430.56' x2='479.74' y2='430.56' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='399.46' x2='479.74' y2='399.46' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='368.35' x2='479.74' y2='368.35' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='337.25' x2='479.74' y2='337.25' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='306.14' x2='479.74' y2='306.14' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='275.04' x2='479.74' y2='275.04' style='stroke-width: 0.75;' />
+<text transform='translate(495.27,430.56) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.0</text>
+<text transform='translate(495.27,399.46) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.2</text>
+<text transform='translate(495.27,368.35) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.4</text>
+<text transform='translate(495.27,337.25) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.6</text>
+<text transform='translate(495.27,306.14) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.8</text>
+<text transform='translate(495.27,275.04) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>1.0</text>
+</g>
+<g clip-path='url(#cpNTkuMDR8MjQzLjM2fDU5LjA0fDIxNC41Ng==)'>
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='109.08' y='236.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='21.57px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='203.05' y='236.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='33.18px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(44.70,187.78) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='16.24px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(44.70,110.02) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='12.72px' lengthAdjust='spacingAndGlyphs'>No</text>
+</g>
+<g clip-path='url(#cpMjg5LjQ0fDQ3My43Nnw1OS4wNHwyMTQuNTY=)'>
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='346.19' y='236.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='21.57px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='440.16' y='236.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='33.18px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(275.10,203.70) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='16.24px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(275.10,125.94) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='12.72px' lengthAdjust='spacingAndGlyphs'>No</text>
+<line x1='473.76' y1='214.56' x2='479.74' y2='214.56' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='183.46' x2='479.74' y2='183.46' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='152.35' x2='479.74' y2='152.35' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='121.25' x2='479.74' y2='121.25' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='90.14' x2='479.74' y2='90.14' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='59.04' x2='479.74' y2='59.04' style='stroke-width: 0.75;' />
+<text transform='translate(495.27,214.56) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.0</text>
+<text transform='translate(495.27,183.46) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.2</text>
+<text transform='translate(495.27,152.35) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.4</text>
+<text transform='translate(495.27,121.25) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.6</text>
+<text transform='translate(495.27,90.14) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.8</text>
+<text transform='translate(495.27,59.04) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>1.0</text>
+</g>
+<g clip-path='url(#cpNTkuMDR8MjQzLjM2fDI3NS4wNHw0MzAuNTY=)'>
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='124.31' y='452.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='21.57px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='218.28' y='452.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='33.18px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(44.70,417.14) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='16.24px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(44.70,339.38) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='12.72px' lengthAdjust='spacingAndGlyphs'>No</text>
+</g>
+<g clip-path='url(#cpMjg5LjQ0fDQ3My43NnwyNzUuMDR8NDMwLjU2)'>
+<rect x='289.44' y='395.92' width='176.01' height='34.64' style='stroke-width: 0.00; fill: #E8298A;' />
+<rect x='289.44' y='275.04' width='176.01' height='120.88' style='stroke-width: 0.00; fill: #FFD6ED;' />
+<rect x='469.06' y='295.33' width='4.70' height='135.23' style='stroke-width: 0.00; fill: #E8298A;' />
+<rect x='469.06' y='275.04' width='4.70' height='20.29' style='stroke-width: 0.00; fill: #FFD6ED;' />
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='377.44' y='452.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='21.57px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='471.41' y='452.07' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='33.18px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(275.10,413.24) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='16.24px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(275.10,335.48) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='12.72px' lengthAdjust='spacingAndGlyphs'>No</text>
+<line x1='473.76' y1='430.56' x2='479.74' y2='430.56' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='399.46' x2='479.74' y2='399.46' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='368.35' x2='479.74' y2='368.35' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='337.25' x2='479.74' y2='337.25' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='306.14' x2='479.74' y2='306.14' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='275.04' x2='479.74' y2='275.04' style='stroke-width: 0.75;' />
+<text transform='translate(495.27,430.56) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.0</text>
+<text transform='translate(495.27,399.46) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.2</text>
+<text transform='translate(495.27,368.35) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.4</text>
+<text transform='translate(495.27,337.25) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.6</text>
+<text transform='translate(495.27,306.14) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>0.8</text>
+<text transform='translate(495.27,275.04) rotate(-90)' text-anchor='middle' style='font-size: 9.96px; font-family: "Liberation Sans";' textLength='13.84px' lengthAdjust='spacingAndGlyphs'>1.0</text>
+</g>
+<defs>
+  <clipPath id='cpMTAyLjQxfDQ2NS4wOXw4NS4wNnwzNjkuODQ='>
+    <rect x='102.41' y='85.06' width='362.67' height='284.77' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpMTAyLjQxfDQ2NS4wOXw4NS4wNnwzNjkuODQ=)'>
+</g>
+</svg>
diff --git a/inst/tinytest/_tinysnapshot/spineplot_simple.svg b/inst/tinytest/_tinysnapshot/spineplot_simple.svg
new file mode 100644
index 00000000..a9945c7d
--- /dev/null
+++ b/inst/tinytest/_tinysnapshot/spineplot_simple.svg
@@ -0,0 +1,112 @@
+<?xml version='1.0' encoding='UTF-8' ?>
+<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' class='svglite' width='504.00pt' height='504.00pt' viewBox='0 0 504.00 504.00'>
+<defs>
+  <style type='text/css'><![CDATA[
+    .svglite line, .svglite polyline, .svglite polygon, .svglite path, .svglite rect, .svglite circle {
+      fill: none;
+      stroke: #000000;
+      stroke-linecap: round;
+      stroke-linejoin: round;
+      stroke-miterlimit: 10.00;
+    }
+    .svglite text {
+      white-space: pre;
+    }
+  ]]></style>
+</defs>
+<rect width='100%' height='100%' style='stroke: none; fill: #FFFFFF;'/>
+<defs>
+  <clipPath id='cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA='>
+    <rect x='0.00' y='0.00' width='504.00' height='504.00' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='266.40' y='485.28' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='64.70px' lengthAdjust='spacingAndGlyphs'>Sepal.Width</text>
+<text transform='translate(12.96,244.80) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='42.70px' lengthAdjust='spacingAndGlyphs'>Species</text>
+</g>
+<defs>
+  <clipPath id='cpNTkuMDR8NDczLjc2fDU5LjA0fDQzMC41Ng=='>
+    <rect x='59.04' y='59.04' width='414.72' height='371.52' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpNTkuMDR8NDczLjc2fDU5LjA0fDQzMC41Ng==)'>
+<rect x='59.04' y='337.68' width='11.06' height='92.88' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='59.04' y='59.04' width='11.06' height='278.64' style='stroke-width: 0.75; fill: #AEAEAE;' />
+<rect x='59.04' y='59.04' width='11.06' height='0.00' style='stroke-width: 0.75; fill: #E6E6E6;' />
+<rect x='70.10' y='430.56' width='19.35' height='0.00' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='70.10' y='112.11' width='19.35' height='318.45' style='stroke-width: 0.75; fill: #AEAEAE;' />
+<rect x='70.10' y='59.04' width='19.35' height='53.07' style='stroke-width: 0.75; fill: #E6E6E6;' />
+<rect x='89.45' y='259.09' width='35.94' height='171.47' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='89.45' y='59.04' width='35.94' height='200.05' style='stroke-width: 0.75; fill: #AEAEAE;' />
+<rect x='89.45' y='59.04' width='35.94' height='0.00' style='stroke-width: 0.75; fill: #E6E6E6;' />
+<rect x='125.40' y='236.72' width='63.59' height='193.84' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='125.40' y='59.04' width='63.59' height='177.68' style='stroke-width: 0.75; fill: #AEAEAE;' />
+<rect x='125.40' y='59.04' width='63.59' height='0.00' style='stroke-width: 0.75; fill: #E6E6E6;' />
+<rect x='188.99' y='286.08' width='99.53' height='144.48' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='188.99' y='131.28' width='99.53' height='154.80' style='stroke-width: 0.75; fill: #AEAEAE;' />
+<rect x='188.99' y='59.04' width='99.53' height='72.24' style='stroke-width: 0.75; fill: #E6E6E6;' />
+<rect x='288.52' y='291.24' width='66.36' height='139.32' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='288.52' y='198.36' width='66.36' height='92.88' style='stroke-width: 0.75; fill: #AEAEAE;' />
+<rect x='288.52' y='59.04' width='66.36' height='139.32' style='stroke-width: 0.75; fill: #E6E6E6;' />
+<rect x='354.87' y='327.36' width='49.77' height='103.20' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='354.87' y='286.08' width='49.77' height='41.28' style='stroke-width: 0.75; fill: #AEAEAE;' />
+<rect x='354.87' y='59.04' width='49.77' height='227.04' style='stroke-width: 0.75; fill: #E6E6E6;' />
+<rect x='404.64' y='393.41' width='27.65' height='37.15' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='404.64' y='393.41' width='27.65' height='0.00' style='stroke-width: 0.75; fill: #AEAEAE;' />
+<rect x='404.64' y='59.04' width='27.65' height='334.37' style='stroke-width: 0.75; fill: #E6E6E6;' />
+<rect x='432.29' y='348.00' width='24.88' height='82.56' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='432.29' y='348.00' width='24.88' height='0.00' style='stroke-width: 0.75; fill: #AEAEAE;' />
+<rect x='432.29' y='59.04' width='24.88' height='288.96' style='stroke-width: 0.75; fill: #E6E6E6;' />
+<rect x='457.17' y='430.56' width='8.29' height='0.00' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='457.17' y='430.56' width='8.29' height='0.00' style='stroke-width: 0.75; fill: #AEAEAE;' />
+<rect x='457.17' y='59.04' width='8.29' height='371.52' style='stroke-width: 0.75; fill: #E6E6E6;' />
+<rect x='465.47' y='430.56' width='5.53' height='0.00' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='465.47' y='430.56' width='5.53' height='0.00' style='stroke-width: 0.75; fill: #AEAEAE;' />
+<rect x='465.47' y='59.04' width='5.53' height='371.52' style='stroke-width: 0.75; fill: #E6E6E6;' />
+<rect x='471.00' y='430.56' width='2.76' height='0.00' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='471.00' y='430.56' width='2.76' height='0.00' style='stroke-width: 0.75; fill: #AEAEAE;' />
+<rect x='471.00' y='59.04' width='2.76' height='371.52' style='stroke-width: 0.75; fill: #E6E6E6;' />
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<line x1='59.04' y1='430.56' x2='473.76' y2='430.56' style='stroke-width: 0.75;' />
+<line x1='59.04' y1='430.56' x2='59.04' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='70.10' y1='430.56' x2='70.10' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='89.45' y1='430.56' x2='89.45' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='125.40' y1='430.56' x2='125.40' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='188.99' y1='430.56' x2='188.99' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='288.52' y1='430.56' x2='288.52' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='354.87' y1='430.56' x2='354.87' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='404.64' y1='430.56' x2='404.64' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='432.29' y1='430.56' x2='432.29' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='457.17' y1='430.56' x2='457.17' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='465.47' y1='430.56' x2='465.47' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='471.00' y1='430.56' x2='471.00' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='430.56' x2='473.76' y2='437.76' style='stroke-width: 0.75;' />
+<text x='59.04' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='6.67px' lengthAdjust='spacingAndGlyphs'>2</text>
+<text x='89.45' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>2.4</text>
+<text x='125.40' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>2.6</text>
+<text x='188.99' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>2.8</text>
+<text x='288.52' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='6.67px' lengthAdjust='spacingAndGlyphs'>3</text>
+<text x='354.87' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>3.2</text>
+<text x='404.64' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>3.4</text>
+<text x='432.29' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>3.6</text>
+<text x='465.47' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='6.67px' lengthAdjust='spacingAndGlyphs'>4</text>
+<text transform='translate(41.76,368.64) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='44.02px' lengthAdjust='spacingAndGlyphs'>virginica</text>
+<text transform='translate(41.76,244.80) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='51.36px' lengthAdjust='spacingAndGlyphs'>versicolor</text>
+<text transform='translate(41.76,120.96) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='35.37px' lengthAdjust='spacingAndGlyphs'>setosa</text>
+<line x1='473.76' y1='430.56' x2='473.76' y2='59.04' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='430.56' x2='480.96' y2='430.56' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='356.26' x2='480.96' y2='356.26' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='281.95' x2='480.96' y2='281.95' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='207.65' x2='480.96' y2='207.65' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='133.34' x2='480.96' y2='133.34' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='59.04' x2='480.96' y2='59.04' style='stroke-width: 0.75;' />
+<text transform='translate(499.68,430.56) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.0</text>
+<text transform='translate(499.68,356.26) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.2</text>
+<text transform='translate(499.68,281.95) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.4</text>
+<text transform='translate(499.68,207.65) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.6</text>
+<text transform='translate(499.68,133.34) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.8</text>
+<text transform='translate(499.68,59.04) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>1.0</text>
+<polygon points='59.04,430.56 473.76,430.56 473.76,59.04 59.04,59.04 ' style='stroke-width: 0.75;' />
+</g>
+</svg>
diff --git a/inst/tinytest/_tinysnapshot/spineplot_weights.svg b/inst/tinytest/_tinysnapshot/spineplot_weights.svg
new file mode 100644
index 00000000..faec3df3
--- /dev/null
+++ b/inst/tinytest/_tinysnapshot/spineplot_weights.svg
@@ -0,0 +1,57 @@
+<?xml version='1.0' encoding='UTF-8' ?>
+<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' class='svglite' width='504.00pt' height='504.00pt' viewBox='0 0 504.00 504.00'>
+<defs>
+  <style type='text/css'><![CDATA[
+    .svglite line, .svglite polyline, .svglite polygon, .svglite path, .svglite rect, .svglite circle {
+      fill: none;
+      stroke: #000000;
+      stroke-linecap: round;
+      stroke-linejoin: round;
+      stroke-miterlimit: 10.00;
+    }
+    .svglite text {
+      white-space: pre;
+    }
+  ]]></style>
+</defs>
+<rect width='100%' height='100%' style='stroke: none; fill: #FFFFFF;'/>
+<defs>
+  <clipPath id='cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA='>
+    <rect x='0.00' y='0.00' width='504.00' height='504.00' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='266.40' y='485.28' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='20.69px' lengthAdjust='spacingAndGlyphs'>Sex</text>
+<text transform='translate(12.96,244.80) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='46.70px' lengthAdjust='spacingAndGlyphs'>Survived</text>
+</g>
+<defs>
+  <clipPath id='cpNTkuMDR8NDczLjc2fDU5LjA0fDQzMC41Ng=='>
+    <rect x='59.04' y='59.04' width='414.72' height='371.52' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpNTkuMDR8NDczLjc2fDU5LjA0fDQzMC41Ng==)'>
+<rect x='59.04' y='351.79' width='319.77' height='78.77' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='59.04' y='59.04' width='319.77' height='292.75' style='stroke-width: 0.75; fill: #E6E6E6;' />
+<rect x='386.94' y='158.64' width='86.82' height='271.92' style='stroke-width: 0.75; fill: #4D4D4D;' />
+<rect x='386.94' y='59.04' width='86.82' height='99.60' style='stroke-width: 0.75; fill: #E6E6E6;' />
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='218.92' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='26.01px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='430.35' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='40.02px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(41.76,391.18) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='19.58px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(41.76,205.42) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='15.34px' lengthAdjust='spacingAndGlyphs'>No</text>
+<line x1='473.76' y1='430.56' x2='473.76' y2='59.04' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='430.56' x2='480.96' y2='430.56' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='356.26' x2='480.96' y2='356.26' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='281.95' x2='480.96' y2='281.95' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='207.65' x2='480.96' y2='207.65' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='133.34' x2='480.96' y2='133.34' style='stroke-width: 0.75;' />
+<line x1='473.76' y1='59.04' x2='480.96' y2='59.04' style='stroke-width: 0.75;' />
+<text transform='translate(499.68,430.56) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.0</text>
+<text transform='translate(499.68,356.26) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.2</text>
+<text transform='translate(499.68,281.95) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.4</text>
+<text transform='translate(499.68,207.65) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.6</text>
+<text transform='translate(499.68,133.34) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.8</text>
+<text transform='translate(499.68,59.04) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>1.0</text>
+</g>
+</svg>
diff --git a/inst/tinytest/_tinysnapshot/spineplot_xby.svg b/inst/tinytest/_tinysnapshot/spineplot_xby.svg
new file mode 100644
index 00000000..469ef747
--- /dev/null
+++ b/inst/tinytest/_tinysnapshot/spineplot_xby.svg
@@ -0,0 +1,90 @@
+<?xml version='1.0' encoding='UTF-8' ?>
+<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' class='svglite' width='504.00pt' height='504.00pt' viewBox='0 0 504.00 504.00'>
+<defs>
+  <style type='text/css'><![CDATA[
+    .svglite line, .svglite polyline, .svglite polygon, .svglite path, .svglite rect, .svglite circle {
+      fill: none;
+      stroke: #000000;
+      stroke-linecap: round;
+      stroke-linejoin: round;
+      stroke-miterlimit: 10.00;
+    }
+    .svglite text {
+      white-space: pre;
+    }
+  ]]></style>
+</defs>
+<rect width='100%' height='100%' style='stroke: none; fill: #FFFFFF;'/>
+<defs>
+  <clipPath id='cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA='>
+    <rect x='0.00' y='0.00' width='504.00' height='504.00' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<rect x='437.97' y='236.43' width='16.75' height='16.75' style='stroke-width: 0.00; stroke: #4E79A7; fill: #4E79A7;' />
+<rect x='437.97' y='254.43' width='16.75' height='16.75' style='stroke-width: 0.00; stroke: #F28E2B; fill: #F28E2B;' />
+<text x='469.05' y='225.00' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='20.69px' lengthAdjust='spacingAndGlyphs'>Sex</text>
+<text x='457.14' y='248.93' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='40.02px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text x='457.14' y='266.93' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='26.01px' lengthAdjust='spacingAndGlyphs'>Male</text>
+</g>
+<defs>
+  <clipPath id='cpMC4wMHw0MDUuMzB8MC4wMHw1MDQuMDA='>
+    <rect x='0.00' y='0.00' width='405.30' height='504.00' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpMC4wMHw0MDUuMzB8MC4wMHw1MDQuMDA=)'>
+<text x='232.17' y='485.28' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='20.69px' lengthAdjust='spacingAndGlyphs'>Sex</text>
+<text transform='translate(12.96,244.80) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='46.70px' lengthAdjust='spacingAndGlyphs'>Survived</text>
+</g>
+<defs>
+  <clipPath id='cpNTkuMDR8NDA1LjMwfDU5LjA0fDQzMC41Ng=='>
+    <rect x='59.04' y='59.04' width='346.26' height='371.52' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpNTkuMDR8NDA1LjMwfDU5LjA0fDQzMC41Ng==)'>
+<rect x='332.81' y='158.64' width='72.49' height='271.92' style='stroke-width: 0.75; fill: #4D79A7;' />
+<rect x='332.81' y='59.04' width='72.49' height='99.60' style='stroke-width: 0.75; fill: #DEE9FB;' />
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='192.53' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='26.01px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='369.06' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='40.02px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(41.76,391.18) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='19.58px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(41.76,205.42) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='15.34px' lengthAdjust='spacingAndGlyphs'>No</text>
+<line x1='405.30' y1='430.56' x2='405.30' y2='59.04' style='stroke-width: 0.75;' />
+<line x1='405.30' y1='430.56' x2='412.50' y2='430.56' style='stroke-width: 0.75;' />
+<line x1='405.30' y1='356.26' x2='412.50' y2='356.26' style='stroke-width: 0.75;' />
+<line x1='405.30' y1='281.95' x2='412.50' y2='281.95' style='stroke-width: 0.75;' />
+<line x1='405.30' y1='207.65' x2='412.50' y2='207.65' style='stroke-width: 0.75;' />
+<line x1='405.30' y1='133.34' x2='412.50' y2='133.34' style='stroke-width: 0.75;' />
+<line x1='405.30' y1='59.04' x2='412.50' y2='59.04' style='stroke-width: 0.75;' />
+<text transform='translate(431.22,430.56) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.0</text>
+<text transform='translate(431.22,356.26) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.2</text>
+<text transform='translate(431.22,281.95) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.4</text>
+<text transform='translate(431.22,207.65) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.6</text>
+<text transform='translate(431.22,133.34) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.8</text>
+<text transform='translate(431.22,59.04) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>1.0</text>
+</g>
+<g clip-path='url(#cpNTkuMDR8NDA1LjMwfDU5LjA0fDQzMC41Ng==)'>
+<rect x='59.04' y='351.79' width='266.98' height='78.77' style='stroke-width: 0.75; fill: #F38E2C;' />
+<rect x='59.04' y='59.04' width='266.98' height='292.75' style='stroke-width: 0.75; fill: #FFDFCA;' />
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='192.53' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='26.01px' lengthAdjust='spacingAndGlyphs'>Male</text>
+<text x='369.06' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='40.02px' lengthAdjust='spacingAndGlyphs'>Female</text>
+<text transform='translate(41.76,391.18) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='19.58px' lengthAdjust='spacingAndGlyphs'>Yes</text>
+<text transform='translate(41.76,205.42) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='15.34px' lengthAdjust='spacingAndGlyphs'>No</text>
+<line x1='405.30' y1='430.56' x2='405.30' y2='59.04' style='stroke-width: 0.75;' />
+<line x1='405.30' y1='430.56' x2='412.50' y2='430.56' style='stroke-width: 0.75;' />
+<line x1='405.30' y1='356.26' x2='412.50' y2='356.26' style='stroke-width: 0.75;' />
+<line x1='405.30' y1='281.95' x2='412.50' y2='281.95' style='stroke-width: 0.75;' />
+<line x1='405.30' y1='207.65' x2='412.50' y2='207.65' style='stroke-width: 0.75;' />
+<line x1='405.30' y1='133.34' x2='412.50' y2='133.34' style='stroke-width: 0.75;' />
+<line x1='405.30' y1='59.04' x2='412.50' y2='59.04' style='stroke-width: 0.75;' />
+<text transform='translate(431.22,430.56) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.0</text>
+<text transform='translate(431.22,356.26) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.2</text>
+<text transform='translate(431.22,281.95) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.4</text>
+<text transform='translate(431.22,207.65) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.6</text>
+<text transform='translate(431.22,133.34) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.8</text>
+<text transform='translate(431.22,59.04) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>1.0</text>
+</g>
+</svg>
diff --git a/inst/tinytest/_tinysnapshot/spineplot_yby.svg b/inst/tinytest/_tinysnapshot/spineplot_yby.svg
new file mode 100644
index 00000000..e8796d64
--- /dev/null
+++ b/inst/tinytest/_tinysnapshot/spineplot_yby.svg
@@ -0,0 +1,160 @@
+<?xml version='1.0' encoding='UTF-8' ?>
+<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' class='svglite' width='504.00pt' height='504.00pt' viewBox='0 0 504.00 504.00'>
+<defs>
+  <style type='text/css'><![CDATA[
+    .svglite line, .svglite polyline, .svglite polygon, .svglite path, .svglite rect, .svglite circle {
+      fill: none;
+      stroke: #000000;
+      stroke-linecap: round;
+      stroke-linejoin: round;
+      stroke-miterlimit: 10.00;
+    }
+    .svglite text {
+      white-space: pre;
+    }
+  ]]></style>
+</defs>
+<rect width='100%' height='100%' style='stroke: none; fill: #FFFFFF;'/>
+<defs>
+  <clipPath id='cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA='>
+    <rect x='0.00' y='0.00' width='504.00' height='504.00' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<rect x='426.63' y='227.43' width='16.75' height='16.75' style='stroke-width: 0.00; stroke: #FBB4AE; fill: #FBB4AE;' />
+<rect x='426.63' y='245.43' width='16.75' height='16.75' style='stroke-width: 0.00; stroke: #B3CDE3; fill: #B3CDE3;' />
+<rect x='426.63' y='263.43' width='16.75' height='16.75' style='stroke-width: 0.00; stroke: #CCEBC5; fill: #CCEBC5;' />
+<text x='463.38' y='216.00' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='42.70px' lengthAdjust='spacingAndGlyphs'>Species</text>
+<text x='445.80' y='239.93' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='35.37px' lengthAdjust='spacingAndGlyphs'>setosa</text>
+<text x='445.80' y='257.93' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='51.36px' lengthAdjust='spacingAndGlyphs'>versicolor</text>
+<text x='445.80' y='275.93' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='44.02px' lengthAdjust='spacingAndGlyphs'>virginica</text>
+</g>
+<defs>
+  <clipPath id='cpMC4wMHwzOTMuOTZ8MC4wMHw1MDQuMDA='>
+    <rect x='0.00' y='0.00' width='393.96' height='504.00' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpMC4wMHwzOTMuOTZ8MC4wMHw1MDQuMDA=)'>
+<text x='226.50' y='485.28' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='64.70px' lengthAdjust='spacingAndGlyphs'>Sepal.Width</text>
+<text transform='translate(12.96,244.80) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='42.70px' lengthAdjust='spacingAndGlyphs'>Species</text>
+</g>
+<defs>
+  <clipPath id='cpNTkuMDR8MzkzLjk2fDU5LjA0fDQzMC41Ng=='>
+    <rect x='59.04' y='59.04' width='334.92' height='371.52' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpNTkuMDR8MzkzLjk2fDU5LjA0fDQzMC41Ng==)'>
+<rect x='59.04' y='59.04' width='42.42' height='19.55' style='stroke-width: 0.75; fill: #FBB4AE;' />
+<rect x='101.46' y='59.04' width='142.90' height='40.64' style='stroke-width: 0.75; fill: #FBB4AE;' />
+<rect x='244.36' y='59.04' width='107.18' height='201.24' style='stroke-width: 0.75; fill: #FBB4AE;' />
+<rect x='351.54' y='59.04' width='35.73' height='301.86' style='stroke-width: 0.75; fill: #FBB4AE;' />
+<rect x='387.26' y='59.04' width='6.70' height='371.52' style='stroke-width: 0.75; fill: #FBB4AE;' />
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<line x1='59.04' y1='430.56' x2='393.96' y2='430.56' style='stroke-width: 0.75;' />
+<line x1='59.04' y1='430.56' x2='59.04' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='101.46' y1='430.56' x2='101.46' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='244.36' y1='430.56' x2='244.36' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='351.54' y1='430.56' x2='351.54' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='387.26' y1='430.56' x2='387.26' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='393.96' y1='430.56' x2='393.96' y2='437.76' style='stroke-width: 0.75;' />
+<text x='59.04' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='6.67px' lengthAdjust='spacingAndGlyphs'>2</text>
+<text x='101.46' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>2.5</text>
+<text x='244.36' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='6.67px' lengthAdjust='spacingAndGlyphs'>3</text>
+<text x='351.54' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>3.5</text>
+<text x='387.26' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='6.67px' lengthAdjust='spacingAndGlyphs'>4</text>
+<text transform='translate(41.76,381.68) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='44.02px' lengthAdjust='spacingAndGlyphs'>virginica</text>
+<text transform='translate(41.76,205.69) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='51.36px' lengthAdjust='spacingAndGlyphs'>versicolor</text>
+<text transform='translate(41.76,68.82) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='35.37px' lengthAdjust='spacingAndGlyphs'>setosa</text>
+<line x1='393.96' y1='430.56' x2='393.96' y2='59.04' style='stroke-width: 0.75;' />
+<line x1='393.96' y1='430.56' x2='401.16' y2='430.56' style='stroke-width: 0.75;' />
+<line x1='393.96' y1='356.26' x2='401.16' y2='356.26' style='stroke-width: 0.75;' />
+<line x1='393.96' y1='281.95' x2='401.16' y2='281.95' style='stroke-width: 0.75;' />
+<line x1='393.96' y1='207.65' x2='401.16' y2='207.65' style='stroke-width: 0.75;' />
+<line x1='393.96' y1='133.34' x2='401.16' y2='133.34' style='stroke-width: 0.75;' />
+<line x1='393.96' y1='59.04' x2='401.16' y2='59.04' style='stroke-width: 0.75;' />
+<text transform='translate(419.88,430.56) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.0</text>
+<text transform='translate(419.88,356.26) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.2</text>
+<text transform='translate(419.88,281.95) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.4</text>
+<text transform='translate(419.88,207.65) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.6</text>
+<text transform='translate(419.88,133.34) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.8</text>
+<text transform='translate(419.88,59.04) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>1.0</text>
+<polygon points='59.04,430.56 393.96,430.56 393.96,59.04 59.04,59.04 ' style='stroke-width: 0.75;' />
+</g>
+<g clip-path='url(#cpNTkuMDR8MzkzLjk2fDU5LjA0fDQzMC41Ng==)'>
+<rect x='59.04' y='78.59' width='42.42' height='254.20' style='stroke-width: 0.75; fill: #B3CDE3;' />
+<rect x='101.46' y='99.68' width='142.90' height='168.34' style='stroke-width: 0.75; fill: #B3CDE3;' />
+<rect x='244.36' y='260.28' width='107.18' height='61.92' style='stroke-width: 0.75; fill: #B3CDE3;' />
+<rect x='351.54' y='360.90' width='35.73' height='0.00' style='stroke-width: 0.75; fill: #B3CDE3;' />
+<rect x='387.26' y='430.56' width='6.70' height='0.00' style='stroke-width: 0.75; fill: #B3CDE3;' />
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<line x1='59.04' y1='430.56' x2='393.96' y2='430.56' style='stroke-width: 0.75;' />
+<line x1='59.04' y1='430.56' x2='59.04' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='101.46' y1='430.56' x2='101.46' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='244.36' y1='430.56' x2='244.36' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='351.54' y1='430.56' x2='351.54' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='387.26' y1='430.56' x2='387.26' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='393.96' y1='430.56' x2='393.96' y2='437.76' style='stroke-width: 0.75;' />
+<text x='59.04' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='6.67px' lengthAdjust='spacingAndGlyphs'>2</text>
+<text x='101.46' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>2.5</text>
+<text x='244.36' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='6.67px' lengthAdjust='spacingAndGlyphs'>3</text>
+<text x='351.54' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>3.5</text>
+<text x='387.26' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='6.67px' lengthAdjust='spacingAndGlyphs'>4</text>
+<text transform='translate(41.76,381.68) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='44.02px' lengthAdjust='spacingAndGlyphs'>virginica</text>
+<text transform='translate(41.76,205.69) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='51.36px' lengthAdjust='spacingAndGlyphs'>versicolor</text>
+<text transform='translate(41.76,68.82) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='35.37px' lengthAdjust='spacingAndGlyphs'>setosa</text>
+<line x1='393.96' y1='430.56' x2='393.96' y2='59.04' style='stroke-width: 0.75;' />
+<line x1='393.96' y1='430.56' x2='401.16' y2='430.56' style='stroke-width: 0.75;' />
+<line x1='393.96' y1='356.26' x2='401.16' y2='356.26' style='stroke-width: 0.75;' />
+<line x1='393.96' y1='281.95' x2='401.16' y2='281.95' style='stroke-width: 0.75;' />
+<line x1='393.96' y1='207.65' x2='401.16' y2='207.65' style='stroke-width: 0.75;' />
+<line x1='393.96' y1='133.34' x2='401.16' y2='133.34' style='stroke-width: 0.75;' />
+<line x1='393.96' y1='59.04' x2='401.16' y2='59.04' style='stroke-width: 0.75;' />
+<text transform='translate(419.88,430.56) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.0</text>
+<text transform='translate(419.88,356.26) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.2</text>
+<text transform='translate(419.88,281.95) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.4</text>
+<text transform='translate(419.88,207.65) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.6</text>
+<text transform='translate(419.88,133.34) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.8</text>
+<text transform='translate(419.88,59.04) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>1.0</text>
+<polygon points='59.04,430.56 393.96,430.56 393.96,59.04 59.04,59.04 ' style='stroke-width: 0.75;' />
+</g>
+<g clip-path='url(#cpNTkuMDR8MzkzLjk2fDU5LjA0fDQzMC41Ng==)'>
+<rect x='59.04' y='332.79' width='42.42' height='97.77' style='stroke-width: 0.75; fill: #CCEBC5;' />
+<rect x='101.46' y='268.02' width='142.90' height='162.54' style='stroke-width: 0.75; fill: #CCEBC5;' />
+<rect x='244.36' y='322.20' width='107.18' height='108.36' style='stroke-width: 0.75; fill: #CCEBC5;' />
+<rect x='351.54' y='360.90' width='35.73' height='69.66' style='stroke-width: 0.75; fill: #CCEBC5;' />
+<rect x='387.26' y='430.56' width='6.70' height='0.00' style='stroke-width: 0.75; fill: #CCEBC5;' />
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<line x1='59.04' y1='430.56' x2='393.96' y2='430.56' style='stroke-width: 0.75;' />
+<line x1='59.04' y1='430.56' x2='59.04' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='101.46' y1='430.56' x2='101.46' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='244.36' y1='430.56' x2='244.36' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='351.54' y1='430.56' x2='351.54' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='387.26' y1='430.56' x2='387.26' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='393.96' y1='430.56' x2='393.96' y2='437.76' style='stroke-width: 0.75;' />
+<text x='59.04' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='6.67px' lengthAdjust='spacingAndGlyphs'>2</text>
+<text x='101.46' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>2.5</text>
+<text x='244.36' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='6.67px' lengthAdjust='spacingAndGlyphs'>3</text>
+<text x='351.54' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>3.5</text>
+<text x='387.26' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='6.67px' lengthAdjust='spacingAndGlyphs'>4</text>
+<text transform='translate(41.76,381.68) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='44.02px' lengthAdjust='spacingAndGlyphs'>virginica</text>
+<text transform='translate(41.76,205.69) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='51.36px' lengthAdjust='spacingAndGlyphs'>versicolor</text>
+<text transform='translate(41.76,68.82) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='35.37px' lengthAdjust='spacingAndGlyphs'>setosa</text>
+<line x1='393.96' y1='430.56' x2='393.96' y2='59.04' style='stroke-width: 0.75;' />
+<line x1='393.96' y1='430.56' x2='401.16' y2='430.56' style='stroke-width: 0.75;' />
+<line x1='393.96' y1='356.26' x2='401.16' y2='356.26' style='stroke-width: 0.75;' />
+<line x1='393.96' y1='281.95' x2='401.16' y2='281.95' style='stroke-width: 0.75;' />
+<line x1='393.96' y1='207.65' x2='401.16' y2='207.65' style='stroke-width: 0.75;' />
+<line x1='393.96' y1='133.34' x2='401.16' y2='133.34' style='stroke-width: 0.75;' />
+<line x1='393.96' y1='59.04' x2='401.16' y2='59.04' style='stroke-width: 0.75;' />
+<text transform='translate(419.88,430.56) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.0</text>
+<text transform='translate(419.88,356.26) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.2</text>
+<text transform='translate(419.88,281.95) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.4</text>
+<text transform='translate(419.88,207.65) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.6</text>
+<text transform='translate(419.88,133.34) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>0.8</text>
+<text transform='translate(419.88,59.04) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'>1.0</text>
+<polygon points='59.04,430.56 393.96,430.56 393.96,59.04 59.04,59.04 ' style='stroke-width: 0.75;' />
+</g>
+</svg>
diff --git a/inst/tinytest/test-spineplot.R b/inst/tinytest/test-spineplot.R
new file mode 100644
index 00000000..6012130d
--- /dev/null
+++ b/inst/tinytest/test-spineplot.R
@@ -0,0 +1,91 @@
+source("helpers.R")
+using("tinysnapshot")
+
+ttnc = as.data.frame(Titanic)
+
+#
+## simple spineplot
+
+f = function() {
+  tinyplot(Species ~ Sepal.Width, data = iris, type = "spineplot")
+}
+expect_snapshot_plot(f, label = "spineplot_simple")
+
+f = function() {
+  tinyplot(Species ~ Sepal.Width, data = iris, type = type_spineplot(breaks = 4))
+}
+expect_snapshot_plot(f, label = "spineplot_breaks")
+
+f = function() {
+  tinyplot(Species ~ Sepal.Width, data = iris, type = type_spineplot(breaks = 4), flip = TRUE)
+}
+expect_snapshot_plot(f, label = "spineplot_breaks_flip")
+
+f = function() {
+  tinyplot(Survived ~ Sex, data = ttnc, type = type_spineplot(weights = ttnc$Freq))
+}
+expect_snapshot_plot(f, label = "spineplot_weights")
+
+
+#
+## grouped boxplots
+
+# special cases for x==by and y==by
+f = function() {
+  tinyplot(
+    Survived ~ Sex | Sex, data = ttnc,
+    type = type_spineplot(weights = ttnc$Freq),
+    palette = "tableau"
+  )
+}
+expect_snapshot_plot(f, label = "spineplot_xby")
+f = function() {
+  tinyplot(
+    Species ~ Sepal.Width | Species, data = iris,
+    type = type_spineplot(breaks = 4),
+    palette = "Pastel 1"
+  )
+}
+expect_snapshot_plot(f, label = "spineplot_yby")
+
+
+#
+## facets
+
+f = function() {
+  tinyplot(
+    Survived ~ Sex, facet = ~Class, data = ttnc,
+    type = type_spineplot(weights = ttnc$Freq)
+  )
+}
+expect_snapshot_plot(f, label = "spineplot_facet")
+
+f = function() {
+  tinyplot(
+    Survived ~ Sex | Class, facet = "by", data = ttnc,
+    type = type_spineplot(weights = ttnc$Freq)
+  )
+}
+expect_snapshot_plot(f, label = "spineplot_facet_by")
+
+f = function() {
+  tinyplot(
+    Survived ~ Sex | Class, facet = "by", data = ttnc,
+    type = type_spineplot(weights = ttnc$Freq),
+    palette = "Dark 2",  axes = "t", legend = FALSE
+  )
+}
+expect_snapshot_plot(f, label = "spineplot_facet_by_fancy")
+
+#
+## factor ~ numeric / factor ~ factor should auto-coerce to spineplot type
+
+f = function() {
+  plt(factor(cyl) ~ mpg, data = mtcars)
+}
+expect_snapshot_plot(f, label = "spineplot_auto_factor")
+
+f = function() {
+  plt(factor(cyl) ~ factor(am), data = mtcars)
+}
+expect_snapshot_plot(f, label = "spineplot_auto_factors")
diff --git a/man/tinyplot.Rd b/man/tinyplot.Rd
index 425c8a13..f6a08fd6 100644
--- a/man/tinyplot.Rd
+++ b/man/tinyplot.Rd
@@ -54,6 +54,8 @@ tinyplot(x, ...)
   xaxt = NULL,
   yaxt = NULL,
   flip = FALSE,
+  xaxs = NULL,
+  yaxs = NULL,
   ...
 )
 
@@ -123,8 +125,6 @@ likely the names of existing vectors or columns of data frames. See the
 \code{\link[grDevices]{xy.coords}} for details. If supplied separately, \code{x}
 and \code{y} must be of the same length.}
 
-\item{...}{other graphical parameters (see \code{\link[graphics]{par}}).}
-
 \item{by}{grouping variable(s). The default behaviour is for groups to be
 represented in the form of distinct colours, which will also trigger an
 automatic legend. (See \code{legend} below for customization options.) However,
@@ -447,6 +447,8 @@ See \code{axes} for the possible values.}
 y-axis is on the horizontal plane and the x-axis is on the vertical plane?
 Default is FALSE.}
 
+\item{xaxs, yaxs, ...}{other graphical parameters (see \code{\link[graphics]{par}}).}
+
 \item{formula}{a \code{\link[stats]{formula}} that optionally includes
 grouping variable(s) after a vertical bar, e.g. \code{y ~ x | z}. One-sided
 formulae are also permitted, e.g. \code{~ y | z}. Multiple grouping variables
diff --git a/man/type_spineplot.Rd b/man/type_spineplot.Rd
new file mode 100644
index 00000000..1042a298
--- /dev/null
+++ b/man/type_spineplot.Rd
@@ -0,0 +1,99 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/type_spineplot.R
+\name{type_spineplot}
+\alias{type_spineplot}
+\title{Spineplot and spinogram type}
+\usage{
+type_spineplot(
+  breaks = NULL,
+  tol.ylab = 0.05,
+  off = NULL,
+  ylevels = NULL,
+  col = NULL,
+  xaxlabels = NULL,
+  yaxlabels = NULL,
+  weights = NULL
+)
+}
+\arguments{
+\item{breaks}{if the explanatory variable is numeric, this controls how
+    it is discretized. \code{breaks} is passed to \code{\link[graphics]{hist}} and can
+    be a list of arguments.}
+
+\item{tol.ylab}{convenience tolerance parameter for y-axis annotation.
+    If the distance between two labels drops under this threshold, they are
+    plotted equidistantly.}
+
+\item{off}{vertical offset between the bars (in per cent). It is fixed to
+    \code{0} for spinograms and defaults to \code{2} for spine plots.}
+
+\item{ylevels}{a character or numeric vector specifying in which order
+    the levels of the dependent variable should be plotted.}
+
+\item{col}{a vector of fill colors of the same length as \code{levels(y)}.
+    The default is to call \code{\link{gray.colors}}.}
+
+\item{xaxlabels, yaxlabels}{character vectors for annotation of x and y axis.
+    Default to \code{levels(y)} and \code{levels(x)}, respectively for the
+    spine plot. For \code{xaxlabels} in the spinogram, the breaks are
+    used.}
+
+\item{weights}{numeric. A vector of frequency weights for each
+    observation in the data. If \code{NULL} all weights are implicitly
+    assumed to be 1. If \code{x} is already a 2-way table, the weights
+    are ignored.}
+}
+\description{
+Spineplot and spinogram type
+}
+\examples{
+# "spineplot" type convenience string
+tinyplot(Species ~ Sepal.Width, data = iris, type = "spineplot")
+
+# Aside: specifying the type is redundant for this example, since tinyplot
+# default's to "spineplot" if y is a factor (just like base plot).
+tinyplot(Species ~ Sepal.Width, data = iris)
+
+# Use `type_spineplot()` to pass extra arguments for customization
+tinyplot(Species ~ Sepal.Width, data = iris, type = type_spineplot(breaks = 4))
+
+p = palette.colors(3, "Pastel 1")
+tinyplot(Species ~ Sepal.Width, data = iris, type = type_spineplot(breaks = 4, col = p))
+rm(p)
+
+# More idiomatic tinyplot way of drawing the previous plot: use y == by
+tinyplot(
+  Species ~ Sepal.Width | Species, data = iris, type = type_spineplot(breaks = 4),
+  palette = "Pastel 1", legend = FALSE
+)
+
+# Grouped and faceted spineplots
+
+ttnc = as.data.frame(Titanic)
+
+tinyplot(
+  Survived ~ Sex, facet = ~ Class, data = ttnc,
+  type = type_spineplot(weights = ttnc$Freq)
+)
+
+# For grouped "by" spineplots, it's better visually to facet as well
+tinyplot(
+  Survived ~ Sex | Class, facet = "by", data = ttnc,
+  type = type_spineplot(weights = ttnc$Freq)
+)
+
+# Fancier version. Note the smart inheritance of spacing etc.
+tinyplot(
+  Survived ~ Sex | Class, facet = "by", data = ttnc,
+  type = type_spineplot(weights = ttnc$Freq),
+  palette = "Dark 2", facet.args = list(nrow = 1), axes = "t"
+)
+
+# Note: It's possible to use "by" on its own (without faceting), but the
+# overlaid result isn't great. We will likely overhaul this behaviour in a
+# future version of tinyplot...
+tinyplot(Survived ~ Sex | Class, data = ttnc,
+  type = type_spineplot(weights = ttnc$Freq), alpha = 0.3
+)
+
+}
diff --git a/vignettes/types.qmd b/vignettes/types.qmd
index 166aca1c..552d3047 100644
--- a/vignettes/types.qmd
+++ b/vignettes/types.qmd
@@ -74,10 +74,11 @@ Shapes:
 
 Visualizations:
 
-- `"jitter"` / `type_jitter()`: Jittered points.
 - `"boxplot"` / `type_boxplot()`: Creates a box-and-whisker plot.
-- `"histogram"` / `type_histogram()`: Creates a histogram of a single variable.
 - `"density"`: Plots the density estimate of a variable.
+- `"histogram"` / `type_histogram()`: Creates a histogram of a single variable.
+- `"jitter"` / `type_jitter()`: Jittered points.
+- `"spineplot"` / `type_spineplot()`: Creates a spineplot or spinogram.
 
 To see the difference between the convenience strings and their respective
 companion `type_*` functions, let's quickly walk through two examples.
