Skip to content

Reporting of output styles (colors and fonts) #2740

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 54 commits into from
May 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
e9f2e0d
wip
cpsievert Jan 16, 2020
65a47c0
grep for hex codes properly and return exit length 0 character string…
cpsievert Jan 16, 2020
fc09d1c
Support a named vector as an override to computed colors
cpsievert Jan 16, 2020
d8080d1
only assign default for aes that are relevant and non-transparent
cpsievert Jan 17, 2020
82c04ca
facet strips shouldn't have stroke and fill should be a semi-lighten …
cpsievert Jan 17, 2020
f736718
Add support for lattice and better default palette() for col scaling
cpsievert Jan 17, 2020
303f264
Implement plot.autocolors for cached plots
jcheng5 Jan 19, 2020
6e767fc
More robust un-setting of autocolor params
jcheng5 Jan 19, 2020
83a5fea
More autocolor fixes
jcheng5 Jan 19, 2020
47c1202
Tweak ggplot2 colors to look closer to defaults
jcheng5 Jan 19, 2020
3fbbabd
Better autocolors for bars and other geoms that don't have colour; li…
jcheng5 Jan 24, 2020
a1a22e8
Report font-family and colors in getCurrentOutputInfo() if .shiny-rep…
cpsievert Feb 7, 2020
a20c3a3
make sure ggplot_apply_auto_colors always returns a built plot
cpsievert Feb 7, 2020
867daee
Add accent (link) color and qualitative color palettes
cpsievert Feb 14, 2020
ecd72f1
Add sequential colorscale for ggplot2 based on the accent color
cpsievert Feb 18, 2020
afad039
Use htmltools::parseCssColors
jcheng5 Feb 19, 2020
330da2d
code review feedback; introduce autoThemeOptions()
cpsievert Feb 20, 2020
f942c08
mix colors using scales::colour_ramp
cpsievert Feb 20, 2020
be912cf
Set default scales via plot_env for old ggplot2 and options for new g…
cpsievert Mar 2, 2020
0692334
cleanup
cpsievert Mar 3, 2020
4c8ec8b
allow autoTheme options to be reactive
cpsievert Mar 3, 2020
164ad8c
Add autoThemeOptions() to pkgdown
cpsievert Mar 3, 2020
a3d224b
suggest scales; other R CMD check things
cpsievert Mar 4, 2020
b10b6d4
default to bg='white', not transparent
cpsievert Mar 4, 2020
819ad4c
newpage should always come before ggplot_build
cpsievert Mar 5, 2020
dce4028
sequential colorscale now mixes fg/bg with accent (for the endpoints)
cpsievert Mar 5, 2020
b269487
port auto-theming logic to new thematic package
cpsievert Mar 11, 2020
4e59f55
wip font support
cpsievert Apr 8, 2020
5855aa2
First pass at an auto-theming interface
cpsievert Apr 10, 2020
393d416
Auto-theming interface will come from thematic
cpsievert Apr 14, 2020
16196ee
ragg will take priority over Cairo
cpsievert Apr 14, 2020
89d6a3d
User-supplied bg to renderPlot should take 1st priority
cpsievert Apr 14, 2020
7ddf416
no need to call thematic
cpsievert Apr 14, 2020
dfb4924
Provide a device argument to renderPlot() and plotPNG()
cpsievert Apr 14, 2020
a05f713
code review with Barret
cpsievert Apr 15, 2020
db3d7ee
bump version
cpsievert Apr 17, 2020
44cfde7
missed passing device in renderCachedPlot()
cpsievert Apr 23, 2020
b408d93
somehow messed up rebase
cpsievert Apr 27, 2020
97ea4e2
change device bg default only if the thematic option is set
cpsievert Apr 28, 2020
1a0a53a
Auto values aren't resolved until plot time, so if we see one, resolv…
cpsievert Apr 28, 2020
dd1c653
Rollback the custom device arg (may come later) in favor of a shiny.u…
cpsievert Apr 30, 2020
9d2f8cb
Pass check
cpsievert Apr 30, 2020
1e2a874
let showtext know about the resolution
cpsievert Apr 30, 2020
0738f6a
default to FALSE for now
cpsievert Apr 30, 2020
2107923
code review with Winston
cpsievert May 1, 2020
6d7e2b8
generalize internal is_installed and use it in startPNG()
cpsievert May 5, 2020
5d4855f
comments
cpsievert May 5, 2020
cf410e3
Use is_available() more widely and remove unneeded complexity in chec…
cpsievert May 5, 2020
26dff7e
Wrap styles in reactive() so that calling getCurrentOutputInfo() does…
cpsievert May 5, 2020
3dac31a
update news and add to comment
cpsievert May 6, 2020
c7f0484
smaller bump in version
cpsievert May 6, 2020
acad455
make shiny.useragg an unofficial option that takes priority over quartz
cpsievert May 6, 2020
c95d3ef
safe-guard against NA values
cpsievert May 6, 2020
079871d
Use getStyle() to support old browsers
cpsievert May 6, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Package: shiny
Type: Package
Title: Web Application Framework for R
Version: 1.4.0.9002
Version: 1.4.0.9003
Authors@R: c(
person("Winston", "Chang", role = c("aut", "cre"), email = "winston@rstudio.com"),
person("Joe", "Cheng", role = "aut", email = "joe@rstudio.com"),
Expand Down Expand Up @@ -70,7 +70,7 @@ Imports:
jsonlite (>= 0.9.16),
xtable,
digest,
htmltools (>= 0.4.0.9001),
htmltools (>= 0.4.0.9003),
R6 (>= 2.0),
sourcetools,
later (>= 1.0.0),
Expand All @@ -95,7 +95,9 @@ Suggests:
shinytest,
yaml,
future,
dygraphs
dygraphs,
ragg,
showtext
Remotes:
rstudio/htmltools,
rstudio/shinytest
Expand Down
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ shiny 1.4.0.9001

* Resolved [#2732](https://github.com/rstudio/shiny/issues/2732): `markdown()` is a new function for writing Markdown with Github extensions directly in Shiny UIs. Markdown rendering is performed by the [commonmark](https://github.com/jeroen/commonmark) package. ([#2737](https://github.com/rstudio/shiny/pull/2737))

* The `getCurrentOutputInfo()` function can now return the background color (`bg`), foreground color (`fg`), `accent` (i.e., hyperlink) color, and `font` information of the output's HTML container. This information is reported by `plotOutput()`, `imageOutput()`, and any other output bindings containing a class of `.shiny-report-theme`. This feature allows developers to style an output's contents based on the container's CSS styling. ([#2740](https://github.com/rstudio/shiny/pull/2740))

### Minor new features and improvements

* Fixed [#2042](https://github.com/rstudio/shiny/issues/2042), [#2628](https://github.com/rstudio/shiny/issues/2628): In a `dateInput` and `dateRangeInput`, disabled months and years are now a lighter gray, to make it easier to see that they are disabled. ([#2690](https://github.com/rstudio/shiny/pull/2690))
Expand Down
5 changes: 2 additions & 3 deletions R/app_template.R
Original file line number Diff line number Diff line change
Expand Up @@ -116,13 +116,12 @@ shinyAppTemplate <- function(path = NULL, examples = "default", dryrun = FALSE)
}

if ("shinytest" %in% examples) {
if (system.file(package = "shinytest") != "" &&
utils::packageVersion("shinytest") <= "1.3.1.9000")
if (!is_available("shinytest", "1.4.0"))
{
message(
"The tests/shinytest directory needs shinytest 1.4.0 or later to work properly.\n",
)
if (system.file(package = "shinytest") != "") {
if (is_available("shinytest")) {
message("You currently have shinytest ",
utils::packageVersion("shinytest"), " installed.")
}
Expand Down
12 changes: 2 additions & 10 deletions R/globals.R
Original file line number Diff line number Diff line change
Expand Up @@ -28,22 +28,14 @@ register_s3_method <- function(pkg, generic, class, fun = NULL) {
}

register_upgrade_message <- function(pkg, version) {
# Is an out-dated version of this package installed?
needs_upgrade <- function() {
if (system.file(package = pkg) == "")
return(FALSE)
if (utils::packageVersion(pkg) >= version)
return(FALSE)
TRUE
}

msg <- sprintf(
"This version of Shiny is designed to work with '%s' >= %s.
Please upgrade via install.packages('%s').",
pkg, version, pkg
)

if (pkg %in% loadedNamespaces() && needs_upgrade()) {
if (pkg %in% loadedNamespaces() && !is_available(pkg, version)) {
packageStartupMessage(msg)
}

Expand All @@ -53,7 +45,7 @@ register_upgrade_message <- function(pkg, version) {
setHook(
packageEvent(pkg, "onLoad"),
function(...) {
if (needs_upgrade()) packageStartupMessage(msg)
if (!is_available(pkg, version)) packageStartupMessage(msg)
}
)
}
Expand Down
21 changes: 5 additions & 16 deletions R/graph.R
Original file line number Diff line number Diff line change
@@ -1,31 +1,20 @@
is_installed <- function(package, version) {
installedVersion <- tryCatch(utils::packageVersion(package), error = function(e) NA)
!is.na(installedVersion) && installedVersion >= version
}

# Check that the version of an suggested package satisfies the requirements
#
# @param package The name of the suggested package
# @param version The version of the package
check_suggested <- function(package, version, location) {
check_suggested <- function(package, version = NULL) {

if (is_installed(package, version)) {
if (is_available(package, version)) {
return()
}

missing_location <- missing(location)
msg <- paste0(
sQuote(package),
if (is.na(version)) "" else paste0("(>= ", version, ")"),
" must be installed for this functionality.",
if (!missing_location)
paste0(
"\nPlease install the missing package: \n",
" source(\"https://install-github.me/", location, "\")"
)
if (is.na(version %OR% NA)) "" else paste0("(>= ", version, ")"),
" must be installed for this functionality."
)

if (interactive() && missing_location) {
if (interactive()) {
message(msg, "\nWould you like to install it?")
if (utils::menu(c("Yes", "No")) == 1) {
return(utils::install.packages(package))
Expand Down
44 changes: 37 additions & 7 deletions R/imageutils.R
Original file line number Diff line number Diff line change
@@ -1,17 +1,47 @@
startPNG <- function(filename, width, height, res, ...) {
# If quartz is available, use png() (which will default to quartz).
# Otherwise, if the Cairo package is installed, use CairoPNG().
# Finally, if neither quartz nor Cairo, use png().
if (capabilities("aqua")) {
# shiny.useragg is an experimental option that isn't officially supported or
# documented. It's here in the off chance that someone really wants
# to use ragg (say, instead of showtext, for custom font rendering).
# In the next shiny release, this option will likely be superseded in
# favor of a fully customizable graphics device option
if ((getOption('shiny.useragg') %OR% TRUE) && is_available("ragg")) {
pngfun <- ragg::agg_png
} else if (capabilities("aqua")) {
# i.e., png(type = 'quartz')
pngfun <- grDevices::png
} else if ((getOption('shiny.usecairo') %OR% TRUE) &&
nchar(system.file(package = "Cairo"))) {
} else if ((getOption('shiny.usecairo') %OR% TRUE) && is_available("Cairo")) {
pngfun <- Cairo::CairoPNG
} else {
# i.e., png(type = 'cairo')
pngfun <- grDevices::png
}

pngfun(filename=filename, width=width, height=height, res=res, ...)
args <- rlang::list2(filename=filename, width=width, height=height, res=res, ...)

# Set a smarter default for the device's bg argument (based on thematic's global state).
# Note that, technically, this is really only needed for CairoPNG, since the other
# devices allow their bg arg to be overridden by par(bg=...), which thematic does prior
# to plot-time, but it shouldn't hurt to inform other the device directly as well
if (is.null(args$bg) && isNamespaceLoaded("thematic")) {
# TODO: use :: once thematic is on CRAN
args$bg <- getFromNamespace("thematic_get_option", "thematic")("bg", "white")
# auto vals aren't resolved until plot time, so if we see one, resolve it
if (isTRUE("auto" == args$bg)) {
args$bg <- getCurrentOutputInfo()[["bg"]]()
}
}

# Handle both bg and background device arg
# https://github.com/r-lib/ragg/issues/35
fmls <- names(formals(pngfun))
if (("background" %in% fmls) && (!"bg" %in% fmls)) {
if (is.null(args$background)) {
args$background <- args$bg
}
args$bg <- NULL
}

do.call(pngfun, args)
# Call plot.new() so that even if no plotting operations are performed at
# least we have a blank background. N.B. we need to set the margin to 0
# temporarily before plot.new() because when the plot size is small (e.g.
Expand Down
14 changes: 14 additions & 0 deletions R/render-plot.R
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,17 @@ drawPlot <- function(name, session, func, width, height, pixelratio, res, ...) {
domain <- createGraphicsDevicePromiseDomain(device)
grDevices::dev.control(displaylist = "enable")

# In some cases (at least when `png(type='cairo')), showtext's font
# rendering needs to know about the device's resolution to work properly.
# I don't see any immediate harm in setting the dpi option for any device,
# but it's worth noting that the option doesn't currently work with CairoPNG.
# https://github.com/yixuan/showtext/issues/33
showtextOpts <- if (isNamespaceLoaded("showtext")) {
showtext::showtext_opts(dpi = res)
} else {
NULL
}

hybrid_chain(
hybrid_chain(
promises::with_promise_domain(domain, {
Expand Down Expand Up @@ -246,6 +257,9 @@ drawPlot <- function(name, session, func, width, height, pixelratio, res, ...) {
}),
finally = function() {
grDevices::dev.off(device)
if (length(showtextOpts)) {
showtext::showtext_opts(showtextOpts)
}
}
),
function(result) {
Expand Down
43 changes: 43 additions & 0 deletions R/shiny.R
Original file line number Diff line number Diff line change
Expand Up @@ -1319,6 +1319,13 @@ ShinySession <- R6Class(

# If we don't already have width for this output info, see if it's
# present, and if so, add it.

# Note that all the following clientData values (which are reactiveValues)
# are wrapped in reactive() so that users can take a dependency on particular
# output info (i.e., just depend on width/height, or just depend on bg, fg, etc).
# To put it another way, if getCurrentOutputInfo() simply returned a list of values
# from self$clientData, than anything that calls getCurrentOutputInfo() would take
# a reactive dependency on all of these values.
if (! ("width" %in% names(tmp_info)) ) {
width_name <- paste0("output_", name, "_width")
if (width_name %in% cd_names()) {
Expand All @@ -1337,6 +1344,42 @@ ShinySession <- R6Class(
}
}

# parseCssColors() currently errors out if you hand it any NAs
# This'll make sure we're always working with a string (and if
# that string isn't a valid CSS color, will return NA)
# https://github.com/rstudio/htmltools/issues/161
parse_css_colors <- function(x) {
htmltools::parseCssColors(x %OR% "", mustWork = FALSE)
}

bg <- paste0("output_", name, "_bg")
if (bg %in% cd_names()) {
tmp_info$bg <- reactive({
parse_css_colors(self$clientData[[bg]])
})
}

fg <- paste0("output_", name, "_fg")
if (fg %in% cd_names()) {
tmp_info$fg <- reactive({
parse_css_colors(self$clientData[[fg]])
})
}

accent <- paste0("output_", name, "_accent")
if (accent %in% cd_names()) {
tmp_info$accent <- reactive({
parse_css_colors(self$clientData[[accent]])
})
}

font <- paste0("output_", name, "_font")
if (font %in% cd_names()) {
tmp_info$font <- reactive({
self$clientData[[font]]
})
}

private$outputInfo[[name]] <- tmp_info
private$outputInfo[[name]]
},
Expand Down
10 changes: 10 additions & 0 deletions R/utils.R
Original file line number Diff line number Diff line change
Expand Up @@ -1873,3 +1873,13 @@ findEnclosingApp <- function(path = ".") {
path <- dirname(path)
}
}

# Check if a package is installed, and if version is specified,
# that we have at least that version
is_available <- function(package, version = NULL) {
installed <- nzchar(system.file(package = package))
if (is.null(version)) {
return(installed)
}
installed && isTRUE(utils::packageVersion(package) >= version)
}
91 changes: 90 additions & 1 deletion inst/www/shared/shiny.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion inst/www/shared/shiny.js.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions inst/www/shared/shiny.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion inst/www/shared/shiny.min.js.map

Large diffs are not rendered by default.

Loading