Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c376b59

Browse files
Add type_density() function (grantmcdermott#284)
* type_density * add alpha support for type_area while we're at it * docs * clean up * revamped tinyplot.density method * namespace and docs * docs * update tests * readme * switch to individual bandwidths - add joint.bw arg for override * news - reword other sections while we're at it * don't set xlim and ylim * namespace and fix tests
1 parent cba67f0 commit c376b59

36 files changed

+2144
-1922
lines changed

DESCRIPTION

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ Depends:
4141
Imports:
4242
graphics,
4343
grDevices,
44-
methods,
4544
stats,
4645
tools,
4746
utils

NAMESPACE

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export(tpar)
1414
export(type_abline)
1515
export(type_area)
1616
export(type_boxplot)
17+
export(type_density)
1718
export(type_errorbar)
1819
export(type_function)
1920
export(type_glm)
@@ -88,10 +89,14 @@ importFrom(graphics,segments)
8889
importFrom(graphics,strwidth)
8990
importFrom(graphics,text)
9091
importFrom(graphics,title)
91-
importFrom(methods,as)
9292
importFrom(stats,approx)
9393
importFrom(stats,as.formula)
9494
importFrom(stats,ave)
95+
importFrom(stats,bw.SJ)
96+
importFrom(stats,bw.bcv)
97+
importFrom(stats,bw.nrd)
98+
importFrom(stats,bw.nrd0)
99+
importFrom(stats,bw.ucv)
95100
importFrom(stats,density)
96101
importFrom(stats,dnorm)
97102
importFrom(stats,glm)
@@ -108,7 +113,7 @@ importFrom(stats,qt)
108113
importFrom(stats,quantile)
109114
importFrom(stats,spline)
110115
importFrom(stats,terms)
111-
importFrom(stats,update)
116+
importFrom(stats,weighted.mean)
112117
importFrom(tools,file_ext)
113118
importFrom(utils,globalVariables)
114119
importFrom(utils,head)

NEWS.md

Lines changed: 49 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -7,43 +7,34 @@ where the formatting is also better._
77
## 0.2.1.99 (dev version)
88

99
**tinyplot** v0.3.0 is a big release with many new features, both internal and
10-
user-facing. Below we have tried to group alike news items together, starting
11-
with the new plot type processing system.
12-
13-
New plot `type` processing system:
14-
15-
- In previous versions of `tinyplot` the plot `type` was specified by character
16-
arguments, i.e., either the standard character shortcuts (such `"p"`, `"l"`,
17-
etc.) or labels (such as `"hist"`, `"boxplot"`, etc.). In addition, the
18-
`type` argument now accepts functional `type_*()` equivalents (e.g.,
19-
`type_hist()`) which enable a variety of additional features, as well as a
20-
more disciplined approach to explicit argument passing for customized type
21-
behavior. (#222 @vincentarelbundock)
22-
- All plot types provided in the package can be specified either by a character
23-
label or the corresponding function. Thus, the following two are equivalent:
24-
`tinyplot(Nile, type = "hist")` and `tinyplot(Nile, type = type_hist())`.
25-
- The main advantage of the function specification is that many more plot types
26-
can be supported (see list below) and users can define their own custom types
27-
by creating `type_<typename>()` functions.
28-
- Enabling these new features comes at the cost of a different approach for
29-
specifying ancilliary arguments of the type function. It is recommended to
30-
pass such arguments explicitly to the `type_*()` function call, e.g., as in
31-
`tinyplot(Nile, type = type_hist(breaks = 30))`. In many situations it is
32-
still possible to use the character specification plus extra arguments
33-
instead, e.g., as in `tinyplot(Nile, type = "hist", breaks = 30)`. However,
34-
this only works if the ancilliary type arguments do not match or even
35-
partially match any of the arguments of the `tinyplot()` function itself.
36-
This is why the former approach is recommended (unless using only the
37-
default type).
38-
- Due to this change in the processing of the ancilliary type arguments there
39-
are a few breaking changes but we have tried to minimize them. One argument
40-
that was deprecated explicitly is `ribbon.alpha` in `tinyplot()`. Use the
41-
`alpha` argument of the `type_ribbon()` function instead:
42-
`tinyplot(..., type = type_ribbon(alpha = 0.5))`. Note that it is not
43-
equivalent to use `tinyplot(..., type = "ribbon", alpha = 0.5)` because the
44-
latter matches the `alpha` argument of `tinyplot()` (rather than of
45-
`type_ribbon()`) and modifies the `palette` rather than the ribbon only.
46-
- More details are provided in the dedicated
10+
user-facing. Related updates are grouped below for easier navigation.
11+
12+
New plot `type` processing system (#222 @vincentarelbundock):
13+
14+
- In addition to the standard character labels (e.g., `"p"`, `"density"`), the
15+
`type` argument now supports _functional_ equivalents (e.g., `type_points()`,
16+
`type_density()`. These new functional types all take the form `type_*()`.
17+
- The character and functional types are interchangeable. For example,
18+
`tinyplot(Nile, type = "hist")` and `tinyplot(Nile, type = type_hist())`
19+
produce exactly the same result.
20+
- The main advantage of the functional `type_*()` variants is that they offer
21+
much more flexibility and control beyond the default case(s). Users can pass
22+
appropriate arguments to existing types for customization and can even define
23+
their own `type_<typename>()` functions.
24+
- On the development side, overhauling the `type` system has also allowed us to
25+
introduce a number of new plot types and features (see list below). We have
26+
also simplified our internal codebase, since explicit argument passing
27+
requires less guesswork on our end.
28+
- Speaking of which, we now recommended that users explicitly pass ancillary
29+
type-specific arguments as part of the relevant `type_*()` call. For example:
30+
`tinyplot(Nile, type = type_hist(breaks = 30))` is preferable to
31+
`tinyplot(Nile, type = "hist", breaks = 30)`. While the latter option will
32+
still work in this particular case, we cannot guarantee that it will for other
33+
cases. (Reason: Passing ancillary type-specific arguments at the top level of
34+
the plot call only works if these do not conflict with the main arguments of
35+
the `tinyplot()` function itself; see #267.)
36+
- Some minor breaking changes were unavoidable; see further below.
37+
- For more details on the new `type` system, please see the dedicated
4738
[Plot types vignette](https://grantmcdermott.com/tinyplot/vignettes/types.html)
4839
on the website.
4940

@@ -107,6 +98,27 @@ dedicated
10798
[Themes vignette](https://grantmcdermott.com/tinyplot/vignettes/themes.html)
10899
on the website. (#258 @vincentarelbundock and @grantmcdermott)
109100

101+
Breaking changes:
102+
103+
- There are a few breaking changes to grouped density plots. (#284 @grantmcdermott)
104+
- The default smoothing bandwidth is now computed independently for each data
105+
subgroup, rather than being computed from the joint density. Users can still
106+
opt into using a joint bandwidth by invoking the
107+
`type_density(joint.bw = <option>)` argument. See the function documentation
108+
for details.
109+
- Grouped and/or faceted plots are no longer possible on density objects
110+
(i.e., via the `tinyplot.density()` method). Instead, please rather call
111+
`tinyplot(..., type = "density")` or `tinyplot(..., type = type_density())`
112+
on the raw data and pass grouping or facet arguments as needed.
113+
- The `ribbon.alpha` argument in `tinyplot()` has been deprecated. Use the
114+
`alpha` argument in `type_ribbon()` (and equivalents) instead: e.g.,
115+
`tinyplot(..., type = type_ribbon(alpha = 0.5))`.
116+
- Aside: Please note that this is _not_ equivalent to using
117+
`tinyplot(..., type = "ribbon", alpha = 0.5)` because the latter matches the
118+
top-level `alpha` argument of `tinyplot()` itself (and thus modifies the
119+
entire `palette`, rather than just the ribbon). See our warning about passing
120+
ancillary type-specific arguments above.
121+
110122
Bug fixes:
111123

112124
- Better preserve facet attributes, thus avoiding misarrangement of facet grids

R/sanitize.R

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ sanitize_type = function(type, x, y, dots) {
3737
"abline" = type_abline,
3838
"area" = type_area,
3939
"boxplot" = type_boxplot,
40+
"density" = type_density,
4041
"errorbar" = type_errorbar,
4142
"function" = type_function,
4243
"glm" = type_glm,

R/tinyplot.R

Lines changed: 83 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@
103103
#' - `"text"` / [`type_text()`]: Add text annotations.
104104
#' - Visualizations:
105105
#' - `"boxplot"` / [`type_boxplot()`]: Creates a box-and-whisker plot.
106-
#' - `"density"`: Plots the density estimate of a variable.
106+
#' - `"density"` / [`type_density()`]: Plots the density estimate of a variable.
107107
#' - `"histogram"` / [`type_histogram()`]: Creates a histogram of a single variable.
108108
#' - `"jitter"` / [`type_jitter()`]: Jittered points.
109109
#' - `"qq"` / [`type_qq()`]: Creates a quantile-quantile plot.
@@ -602,11 +602,15 @@ tinyplot.default = function(
602602
# type factories vs. strings
603603
type = sanitize_type(type, x, y, dots)
604604
if ("dots" %in% names(type)) dots = type$dots
605+
606+
# retrieve type-specific data and drawing functions
605607
type_data = type$data
606608
type_draw = type$draw
607609
type = type$name
610+
611+
# area flag (mostly for legend)
608612
was_area_type = identical(type, "area")
609-
613+
# check flip flag is logical
610614
assert_flag(flip)
611615

612616
palette = substitute(palette)
@@ -719,12 +723,14 @@ tinyplot.default = function(
719723
ymax_dep = deparse(substitute(ymax))
720724
y_dep = paste0("[", ymin_dep, ", ", ymax_dep, "]")
721725
y = rep(NA, length(x))
722-
} else if (!type %in% c("density", "histogram", "function")) {
726+
} else if (type == "density") {
727+
if (is.null(ylab)) ylab = "Density"
728+
} else if (type %in% c("histogram", "function")) {
729+
if (is.null(ylab)) ylab = "Frequency"
730+
} else {
723731
y = x
724732
x = seq_along(x)
725733
if (is.null(xlab)) xlab = "Index"
726-
} else {
727-
if (is.null(ylab)) ylab = "Frequency"
728734
}
729735
}
730736

@@ -734,13 +740,6 @@ tinyplot.default = function(
734740
# alias
735741
if (is.null(bg) && !is.null(fill)) bg = fill
736742

737-
# type-specific settings and arguments
738-
if (isTRUE(type == "density")) {
739-
fargs = mget(ls(environment(), sorted = FALSE))
740-
fargs = density_args(fargs = fargs, dots = dots, by_dep = by_dep)
741-
return(do.call(tinyplot.density, args = fargs))
742-
}
743-
744743
datapoints = list(x = x, y = y, xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax, ygroup = ygroup)
745744
datapoints = Filter(function(z) length(z) > 0, datapoints)
746745
datapoints = data.frame(datapoints)
@@ -1354,8 +1353,12 @@ tinyplot.formula = function(
13541353
}
13551354

13561355
## nice axis and legend labels
1356+
dens_type = (is.atomic(type) && identical(type, "density")) || (!is.atomic(type) && identical(type$name, "density"))
13571357
hist_type = (is.atomic(type) && type %in% c("hist", "histogram")) || (!is.atomic(type) && identical(type$name, "histogram"))
1358-
if (!is.null(type) && hist_type) {
1358+
if (!is.null(type) && dens_type) {
1359+
if (is.null(ylab)) ylab = "Density"
1360+
if (is.null(xlab)) xlab = xnam
1361+
} else if (!is.null(type) && hist_type) {
13591362
if (is.null(ylab)) ylab = "Frequency"
13601363
if (is.null(xlab)) xlab = xnam
13611364
} else if (is.null(y)) {
@@ -1396,6 +1399,73 @@ tinyplot.formula = function(
13961399
)
13971400
}
13981401

1402+
#' @rdname tinyplot
1403+
#' @export
1404+
tinyplot.density = function(
1405+
x = NULL,
1406+
type = c("l", "area"),
1407+
...) {
1408+
1409+
dots = list(...)
1410+
1411+
if (!is.null(dots[["by"]]) || !is.null(dots[["facet"]])) {
1412+
stop(
1413+
'\nGrouped and/or faceted plots are no longer supported with the tinyplot.density() method. ',
1414+
'\nPlease use the dedicated type argument instead, e.g. `tinyplot(..., type = "density")`. See `?type_density` for details.',
1415+
'\n\nThis breaking change was introduced in tinyplot v0.3.0.'
1416+
)
1417+
}
1418+
1419+
type = match.arg(type)
1420+
1421+
## override if bg = "by"
1422+
if (!is.null(dots[["bg"]]) || !is.null(dots[["fill"]])) type = "area"
1423+
1424+
if (inherits(x, "density")) {
1425+
object = x
1426+
# legend_args = list(x = NULL)
1427+
# # Grab by label to pass on legend title to tinyplot.default
1428+
# legend_args[["title"]] = deparse(substitute(by))
1429+
} else {
1430+
## An internal catch for non-density objects that were forcibly
1431+
## passed to tinyplot.density (e.g., via a one-side formula)
1432+
if (anyNA(x)) {
1433+
x = na.omit(x)
1434+
x = as.numeric(x)
1435+
}
1436+
object = density(x)
1437+
}
1438+
1439+
x = object$x
1440+
y = object$y
1441+
1442+
if (type == "area") {
1443+
ymin = rep(0, length(y))
1444+
ymax = y
1445+
# # set extra legend params to get bordered boxes with fill
1446+
# legend_args[["x.intersp"]] = 1.25
1447+
# legend_args[["lty"]] = 0
1448+
# legend_args[["pt.lwd"]] = 1
1449+
}
1450+
1451+
# splice in change arguments
1452+
dots[["x"]] = x
1453+
dots[["y"]] = y
1454+
dots[["type"]] = type
1455+
1456+
## axes range
1457+
if (is.null(dots[["xlim"]])) dots[["xlim"]] = range(x)
1458+
if (is.null(dots[["ylim"]])) dots[["ylim"]] = range(y)
1459+
1460+
## nice labels and titles
1461+
if (is.null(dots[["ylab"]])) dots[["ylab"]] = "Density"
1462+
if (is.null(dots[["xlab"]])) dots[["xlab"]] = paste0("N = ", object$n, " Bandwidth = ", sprintf("%.4g", object$bw))
1463+
if (is.null(dots[["main"]])) dots[["main"]] = paste0(paste(object$call, collapse = "(x = "), ")")
1464+
1465+
do.call(tinyplot.default, args = dots)
1466+
1467+
}
1468+
13991469

14001470
#' @export
14011471
#' @name plt

R/type_area.R

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,27 @@
11
#' @rdname type_ribbon
22
#' @export
3-
type_area = function() {
3+
type_area = function(alpha = NULL) {
44
out = list(
55
draw = NULL,
6-
data = data_area(),
6+
data = data_area(alpha = alpha),
77
name = "area"
88
)
99
class(out) = "tinyplot_type"
1010
return(out)
1111
}
1212

1313

14-
data_area = function() {
14+
data_area = function(alpha = alpha) {
15+
ribbon.alpha = if (is.null(alpha)) .tpar[["ribbon.alpha"]] else (alpha)
1516
fun = function(datapoints, ...) {
1617
datapoints$ymax = datapoints$y
1718
datapoints$ymin = rep.int(0, nrow(datapoints))
1819
out = list(
1920
datapoints = datapoints,
2021
ymax = datapoints$ymax,
2122
ymin = datapoints$ymin,
22-
type = "ribbon"
23+
type = "ribbon",
24+
ribbon.alpha = ribbon.alpha
2325
)
2426
return(out)
2527
}

0 commit comments

Comments
 (0)