diff --git a/.Rbuildignore b/.Rbuildignore index cd3d2eba53..428f44cb98 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -20,3 +20,6 @@ revdep/ README.Rmd abbvie.R ^\.httr-oauth$ +^\.github$ +^\.venv$ +CLAUDE\.md diff --git a/.github/.gitignore b/.github/.gitignore new file mode 100644 index 0000000000..2d19fc766d --- /dev/null +++ b/.github/.gitignore @@ -0,0 +1 @@ +*.html diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml new file mode 100644 index 0000000000..18a9ebf3e8 --- /dev/null +++ b/.github/workflows/R-CMD-check.yaml @@ -0,0 +1,110 @@ +# NOTE: This workflow is overkill for most R packages +# check-standard.yaml is likely a better choice +# usethis::use_github_action("check-standard") will install it. +# +# For help debugging build failures open an issue on the RStudio community with the 'github-actions' tag. +# https://community.rstudio.com/new-topic?category=Package%20development&tags=github-actions +on: + push: + branches: + - main + - master + pull_request: + branches: + - main + - master + +name: R-CMD-check + +jobs: + R-CMD-check: + runs-on: ${{ matrix.config.os }} + + name: ${{ matrix.config.os }} (${{ matrix.config.r }}) + + strategy: + fail-fast: false + matrix: + config: + # vdiffr & shinytest only runs on mac r-release since the results aren't cross-platform + - {os: macOS-latest, r: 'release', visual_tests: true, node: "14.x", shinytest: true} + - {os: windows-latest, r: 'release'} + # - {os: windows-latest, r: 'oldrel-1'} # pak is having issues + - {os: ubuntu-latest, r: 'devel'} + - {os: ubuntu-latest, r: 'release'} + - {os: ubuntu-latest, r: 'oldrel-1'} + - {os: ubuntu-latest, r: 'oldrel-2'} + # - {os: ubuntu-latest, r: 'oldrel-3'} # dependency issues with oldrel-3 + # - {os: ubuntu-latest, r: 'oldrel-4'} # dependency issues with oldrel-4 + + env: + VISUAL_TESTS: ${{ matrix.config.visual_tests }} + SHINYTEST: ${{ matrix.config.shinytest }} + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + MAPBOX_TOKEN: ${{ secrets.MAPBOX_TOKEN }} + plotly_username: ${{ secrets.PLOTLY_USERNAME }} + plotly_api_key: ${{ secrets.PLOTLY_API_KEY }} + + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + + - uses: r-lib/actions/setup-r@v2 + id: install-r + with: + r-version: ${{ matrix.config.r }} + use-public-rspm: true + + - uses: r-lib/actions/setup-pandoc@v2 + + - uses: r-lib/actions/setup-r-dependencies@v2 + with: + cache-version: 3 + needs: check + + - name: Set up Python (for reticulate) + if: matrix.config.visual_tests == true + uses: actions/setup-python@v4 + with: + python-version: '3.11' + + - name: Install kaleido + if: matrix.config.visual_tests == true + run: | + # We pin kaleido to v0.2.1 here since >=v1.0 doesn't appear to be correctly rendering some plots + Rscript -e 'library(reticulate); use_python(Sys.which("python")); py_install(c("kaleido==0.2.1", "plotly"))' + + # Run test() before R CMD check since, for some reason, rcmdcheck::rcmdcheck() skips vdiffr tests + - name: Run Tests + run: | + options(crayon.enabled = TRUE, testthat.progress.max_fails=1000) + res <- devtools::test() + df <- as.data.frame(res) + if (sum(df$failed) > 0 || any(df$error)) stop("GHA CI tests failed") + shell: Rscript {0} + + # Upload the whole pkg since tests where run with devtools::test() + - name: Upload check results + if: always() + uses: actions/upload-artifact@master + with: + name: ${{ runner.os }}-r${{ matrix.config.r }}-results + path: | + ./ + !./.git/ + + - name: Check package + uses: r-lib/actions/check-r-package@v2 + with: + check-dir: '"check"' + # Run check with --no-tests since we ran them abve + # 2023-01-03: `{purrr}` v1.0.0 had trouble on Windows without the `--no-multiarch` + # https://github.com/plotly/plotly.R/pull/2221 + args: 'c("--no-tests", "--no-manual", "--as-cran", "--no-multiarch")' + error-on: '"warning"' + + #- name: Show testthat output + # if: always() + # run: find check -name 'testthat.Rout*' -exec cat '{}' \; || true + # shell: bash diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000000..5b35c0c015 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,74 @@ +# Add this file to plotly/plotly.R at .github/workflows/docs.yml +# +# This workflow builds and deploys the R documentation site from +# the graphing-library-docs repository to this repo's GitHub Pages. + +name: Deploy R Documentation + +on: + # Manual trigger + workflow_dispatch: + + # Run weekly to pick up any docs changes + schedule: + - cron: '0 0 * * 0' # Every Sunday at midnight UTC + + # Optional: trigger from docs repo via repository_dispatch + repository_dispatch: + types: [docs-updated] + +# Sets permissions for GitHub Pages deployment +permissions: + contents: read + pages: write + id-token: write + +# Allow only one concurrent deployment +concurrency: + group: "pages" + cancel-in-progress: false + +env: + # Change this if the docs repo moves to a different location + DOCS_REPO: cpsievert/graphing-library-docs + DOCS_BRANCH: master + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout docs repository + uses: actions/checkout@v4 + with: + repository: ${{ env.DOCS_REPO }} + ref: ${{ env.DOCS_BRANCH }} + + - name: Setup Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.2' + bundler-cache: true + + - name: Fetch R/ggplot2 docs from plotly.r-docs + run: make fetch + + - name: Build site + run: bundle exec jekyll build --config _config.yml,_config_production.yml + env: + JEKYLL_ENV: production + + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: _site + + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index 95606952c2..902c8e5c72 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ Rapp.history *.RData *.Rproj.user *.DS_Store +.venv node_modules/ build_site.R revdep_email.R @@ -17,3 +18,5 @@ rsconnect/ revdep/ travis_debug.R .httr-oauth +tests/testthat/Rplots.pdf +.venv/ diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index f92a04f9ee..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,38 +0,0 @@ -language: R -cache: packages -sudo: true -dist: trusty -warnings_are_errors: false -r: - - devel - - oldrel - - release - -env: - global: - # don't treat missing suggested packages as error - - _R_CHECK_FORCE_SUGGESTS_=false - # plotly_api_key (for posting to plot.ly) - - secure: "WsvmMHN4YVhnk0bLRE04APcLbs5s4vWKSHjEdU0bPXd0xdMTzZeP5D7pxyF1983C+P5LpSnGHv4dgwLMBkNzxJwBR7/Ta7lfO1akYILWwxib+1DVbCqUH5Z4Ba1FSCQptIrLNGR3P7+0Lem4hEhqKdPKltFnxhnXO0Y+MeG71IQ=" - # MAPBOX_TOKEN (for testing `plot_mapbox()`) - - secure: "QPBEqtLRdwb4ablJORzD0JdCT9ESe3nNdIehM1oxfcNKfpSdf2OFxH3TkeYY1nMpv0mLxiMNTy6xcj9Yk5MaaBCIA0P7q6OdZv9ruzQD1j3g84gP45KwBilbPGjb+/EvOS0fM25vR/pAmA8IyoUfPC2J8HwiNnW8DYdt/hJOJ9A=" - # GITHUB_PAT - - secure: "lZf7GBt1+ogux5WAXmIZ6/VBTmR1G7rv+8Aevogfan7GWb32K3IVatsrKr1pSvz0hysP0MDueQqTv0GcNOvrFnYvobyo6fFpx+n33WkXQCGybUOHyfJpPdw1L2wtAy88ugNJDl+n9fdXr4yL2cWvRqq4WBKeeSi6hpdiKOaoB3Y=" - -before_install: - - echo "Sys.setenv('plotly_username' = 'cpsievert')" > ~/.Rprofile - # sf system dependencies - - sudo add-apt-repository ppa:ubuntugis/ubuntugis-unstable --yes - - sudo apt-get --yes --force-yes update -qq - - sudo apt-get install --yes libudunits2-dev libproj-dev libgeos-dev libgdal-dev - # make sure R pkgs are upt-to-date - - Rscript -e 'update.packages(ask = FALSE)' - -before_script: - - if [[ "$TRAVIS_R_VERSION_STRING" == "release" ]]; then docker run -e GITHUB_PAT=$GITHUB_PAT -e MAPBOX_TOKEN=$MAPBOX_TOKEN -e VMODE="ci" -v $(pwd):/home/plotly --privileged cpsievert/plotly-orca; fi - -# work around temporary travis + R 3.5 bug -r_packages: devtools - -# temporary: needed for plotly input testing in shiny -r_github_packages: rstudio/shinytest diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000000..bad151e8b0 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,98 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +plotly is an R package for creating interactive web graphics via the plotly.js JavaScript library. It provides two main interfaces: +- `ggplotly()`: Converts ggplot2 objects to interactive plotly visualizations +- `plot_ly()`: Direct interface to plotly.js for specialized chart types + +## Common Commands + +### Running Tests +```r +# Run all tests +devtools::test() + +# Run visual tests (requires kaleido via reticulate) +Sys.setenv("VISUAL_TESTS" = "true") +devtools::test() + +# Run a single test file +devtools::test(filter = "ggplot-bar") +``` + +### Package Check +```r +rcmdcheck::rcmdcheck() +``` + +### Building Documentation +```r +devtools::document() +``` + +### Visual Testing via Docker +For consistent visual test results: +```shell +docker run -v $(pwd):/home/plotly --privileged -p 3838:3838 cpsievert/plotly-orca +``` +Access the validation Shiny app at http://0.0.0.0:3838 + +CI-only visual test run: +```shell +docker run -e VMODE="ci" -v $(pwd):/home/plotly --privileged cpsievert/plotly-orca +``` + +## Architecture + +### ggplot2 to plotly Conversion Pipeline + +The conversion from ggplot2 to plotly follows this flow: + +1. **`ggplotly()`** (`R/ggplotly.R`): Entry point that dispatches on input type +2. **`gg2list()`** (`R/ggplotly.R`): Main conversion function that: + - Builds the ggplot object to extract computed data + - Processes each layer through `layers2traces()` + - Processes layout through `layers2layout()` +3. **`layers2traces()`** (`R/layers2traces.R`): Converts ggplot2 geom layers to plotly trace objects +4. **`layers2layout()`** (`R/layers2layout.R`): Converts ggplot2 theme/coordinate settings to plotly layout + +### Direct plotly Interface + +1. **`plot_ly()`** (`R/plotly.R`): Creates a plotly object with trace attributes +2. **`add_trace()`** and `add_*()` functions (`R/add.R`): Add traces to existing plots +3. **`layout()`** (`R/layout.R`): Modify plot layout +4. **`plotly_build()`** (`R/plotly_build.R`): Evaluates lazy attributes and creates final JSON for plotly.js + +### Key Modules + +- `R/shiny.R`: Shiny integration and event handling +- `R/subplots.R`: Combining multiple plots +- `R/highlight.R`: Linked brushing/crosstalk support +- `R/animate.R`: Animation support +- `R/kaleido.R`, `R/orca.R`: Static image export + +## Testing Patterns + +Tests should check the return value of `plotly_build()`: +```r +test_that("example test", { + p <- plot_ly(x = 1:10, y = 1:10) + built <- plotly_build(p) + expect_equal(built$x$data[[1]]$x, 1:10) +}) +``` + +Visual tests use `expect_doppelganger()` from `tests/testthat/helper-vdiffr.R`: +```r +test_that("visual test", { + p <- plot_ly(x = 1:10, y = 1:10) + expect_doppelganger(p, "scatter-basic") +}) +``` + +## Code Style + +Follow the tidyverse style guide: http://style.tidyverse.org/ diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..bc83715229 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,43 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at accounts@plot.ly. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.4, available at [http://contributor-covenant.org/version/1/4](http://contributor-covenant.org/version/1/4/), and may also be found online at . diff --git a/DESCRIPTION b/DESCRIPTION index 6089fe3366..3cbf41b62d 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: plotly Title: Create Interactive Web Graphics via 'plotly.js' -Version: 4.8.0.9000 +Version: 4.12.0.9000 Authors@R: c(person("Carson", "Sievert", role = c("aut", "cre"), email = "cpsievert1@gmail.com", comment = c(ORCID = "0000-0002-4958-2844")), person("Chris", "Parmer", role = "aut", @@ -15,32 +15,33 @@ Authors@R: c(person("Carson", "Sievert", role = c("aut", "cre"), email = "marianne.corvellec@igdore.org", comment = c(ORCID = "0000-0002-1994-3581")), person("Pedro", "Despouy", role = "aut", email = "pedro@plot.ly"), + person("Salim", "Brüggemann", role = "ctb", + email = "salim-b@pm.me", comment = c(ORCID = "0000-0002-5329-5987")), person("Plotly Technologies Inc.", role = "cph")) License: MIT + file LICENSE Description: Create interactive web graphics from 'ggplot2' graphs and/or a custom interface to the (MIT-licensed) JavaScript library 'plotly.js' inspired by the grammar of graphics. -URL: https://plotly-book.cpsievert.me, https://github.com/ropensci/plotly#readme, https://plot.ly/r -BugReports: https://github.com/ropensci/plotly/issues +URL: https://plotly-r.com, https://github.com/plotly/plotly.R, https://plotly.com/r/ +BugReports: https://github.com/plotly/plotly.R/issues Depends: R (>= 3.2.0), ggplot2 (>= 3.0.0) Imports: tools, scales, - httr, + httr (>= 1.3.0), jsonlite (>= 1.6), magrittr, digest, viridisLite, base64enc, htmltools (>= 0.3.6), - htmlwidgets (>= 1.3), - tidyr, - hexbin, + htmlwidgets (>= 1.5.2.9001), + tidyr (>= 1.0.0), RColorBrewer, dplyr, + vctrs, tibble, - lazyeval (>= 0.2.0), - rlang, + rlang (>= 1.0.0), crosstalk, purrr, data.table, @@ -48,30 +49,41 @@ Imports: Suggests: MASS, maps, + hexbin, ggthemes, GGally, + ggalluvial, testthat, knitr, - devtools, shiny (>= 1.1.0), - shinytest (> 1.3.0), + shinytest2, curl, rmarkdown, - vdiffr, Cairo, broom, webshot, listviewer, dendextend, sf, - maptools, - rgeos, png, IRdisplay, processx, plotlyGeoAssets, - forcats + forcats, + withr, + palmerpenguins, + rversions, + reticulate, + rsvg, + ggridges LazyData: true -RoxygenNote: 6.1.1 +RoxygenNote: 7.3.3 Encoding: UTF-8 Roxygen: list(markdown = TRUE) +Config/Needs/check: + tidyverse/ggplot2, + ggobi/GGally, + rcmdcheck, + devtools, + reshape2, + s2 diff --git a/LICENSE.md b/LICENSE.md index feb4e544e3..fa66b17d20 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ -The MIT License (MIT) +MIT License -Copyright (c) 2017 Plotly Technologies Inc +Copyright (c) 2017-2024 Plotly Technologies Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/NAMESPACE b/NAMESPACE index dd80145f23..a799edaa2d 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -3,11 +3,7 @@ S3method(api_create,data.frame) S3method(api_create,ggplot) S3method(api_create,plotly) -S3method(arrange_,plotly) -S3method(distinct_,plotly) -S3method(do_,plotly) S3method(embed_notebook,plotly) -S3method(filter_,plotly) S3method(fortify,SharedData) S3method(geom2trace,GeomBar) S3method(geom2trace,GeomBlank) @@ -17,6 +13,7 @@ S3method(geom2trace,GeomErrorbarh) S3method(geom2trace,GeomPath) S3method(geom2trace,GeomPoint) S3method(geom2trace,GeomPolygon) +S3method(geom2trace,GeomRidgelineGradient) S3method(geom2trace,GeomText) S3method(geom2trace,GeomTile) S3method(geom2trace,default) @@ -25,26 +22,30 @@ S3method(ggplotly,"NULL") S3method(ggplotly,ggmatrix) S3method(ggplotly,ggplot) S3method(ggplotly,plotly) -S3method(group_by_,plotly) -S3method(groups,plotly) +S3method(highlight_key,default) +S3method(highlight_key,plotly) S3method(layout,matrix) S3method(layout,plotly) S3method(layout,shiny.tag.list) -S3method(mutate_,plotly) +S3method(linewidth_or_size,Geom) +S3method(linewidth_or_size,default) +S3method(linewidth_or_size,element) S3method(plotly_build,"NULL") S3method(plotly_build,gg) +S3method(plotly_build,ggmatrix) S3method(plotly_build,list) S3method(plotly_build,plotly) S3method(print,api) S3method(print,api_grid) S3method(print,api_grid_local) S3method(print,api_plot) +S3method(print,kaleidoScope) S3method(print,plotly_data) -S3method(rename_,plotly) -S3method(select_,plotly) -S3method(slice_,plotly) -S3method(summarise_,plotly) +S3method(process,api_image) +S3method(process,api_plot) +S3method(process,default) S3method(to_basic,GeomAbline) +S3method(to_basic,GeomAlluvium) S3method(to_basic,GeomAnnotationMap) S3method(to_basic,GeomArea) S3method(to_basic,GeomBoxplot) @@ -53,9 +54,14 @@ S3method(to_basic,GeomContour) S3method(to_basic,GeomCrossbar) S3method(to_basic,GeomDensity) S3method(to_basic,GeomDensity2d) +S3method(to_basic,GeomDensityLine) +S3method(to_basic,GeomDensityRidges) +S3method(to_basic,GeomDensityRidges2) +S3method(to_basic,GeomDensityRidgesGradient) S3method(to_basic,GeomDotplot) S3method(to_basic,GeomErrorbar) S3method(to_basic,GeomErrorbarh) +S3method(to_basic,GeomFunction) S3method(to_basic,GeomHex) S3method(to_basic,GeomHline) S3method(to_basic,GeomJitter) @@ -68,18 +74,19 @@ S3method(to_basic,GeomRaster) S3method(to_basic,GeomRasterAnn) S3method(to_basic,GeomRect) S3method(to_basic,GeomRibbon) +S3method(to_basic,GeomRidgeline) +S3method(to_basic,GeomRidgelineGradient) S3method(to_basic,GeomRug) S3method(to_basic,GeomSegment) S3method(to_basic,GeomSf) S3method(to_basic,GeomSmooth) S3method(to_basic,GeomSpoke) S3method(to_basic,GeomStep) +S3method(to_basic,GeomStratum) S3method(to_basic,GeomTile) S3method(to_basic,GeomViolin) S3method(to_basic,GeomVline) S3method(to_basic,default) -S3method(transmute_,plotly) -S3method(ungroup,plotly) export("%>%") export(TeX) export(add_annotations) @@ -94,6 +101,7 @@ export(add_heatmap) export(add_histogram) export(add_histogram2d) export(add_histogram2dcontour) +export(add_image) export(add_lines) export(add_markers) export(add_mesh) @@ -146,6 +154,7 @@ export(hide_guides) export(hide_legend) export(highlight) export(highlight_key) +export(kaleido) export(knit_print.api_grid) export(knit_print.api_grid_local) export(knit_print.api_plot) @@ -178,6 +187,7 @@ export(remove_typedarray_polyfill) export(rename) export(rename_) export(renderPlotly) +export(save_image) export(schema) export(select) export(select_) @@ -240,25 +250,23 @@ importFrom(htmlwidgets,saveWidget) importFrom(htmlwidgets,shinyRenderWidget) importFrom(htmlwidgets,shinyWidgetOutput) importFrom(htmlwidgets,sizingPolicy) -importFrom(httr,GET) -importFrom(httr,PATCH) -importFrom(httr,POST) +importFrom(httr,RETRY) importFrom(httr,add_headers) +importFrom(httr,authenticate) importFrom(httr,config) importFrom(httr,content) importFrom(httr,stop_for_status) importFrom(httr,warn_for_status) +importFrom(httr,write_disk) importFrom(jsonlite,parse_json) importFrom(jsonlite,read_json) importFrom(jsonlite,toJSON) -importFrom(lazyeval,all_dots) -importFrom(lazyeval,f_eval) -importFrom(lazyeval,f_new) -importFrom(lazyeval,is_formula) -importFrom(lazyeval,is_lang) importFrom(magrittr,"%>%") importFrom(purrr,transpose) +importFrom(rlang,"!!!") +importFrom(rlang,"!!") importFrom(rlang,eval_tidy) +importFrom(rlang,is_na) importFrom(stats,complete.cases) importFrom(stats,is.leaf) importFrom(stats,quantile) @@ -268,6 +276,7 @@ importFrom(tidyr,unnest) importFrom(tools,file_ext) importFrom(tools,file_path_sans_ext) importFrom(utils,browseURL) +importFrom(utils,capture.output) importFrom(utils,data) importFrom(utils,file.edit) importFrom(utils,getFromNamespace) diff --git a/NEWS.md b/NEWS.md index a2a365a482..4324cfddb6 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,9 +1,249 @@ -# 4.8.0.9000 +# plotly (development version) + +* Removed the dependency on the `{lazyeval}` package. + + +# plotly 4.12.0 + +## Changes to plotly.js + +Upgrades plotly.js from v2.11.1 to v2.25.2 (35 releases). Key new features now available: + +* **Multiple legends**: Support for `legend2`, `legend3`, etc. with separate positioning and visibility control +* **Shape labels**: New `label` attribute for shapes and `label.texttemplate` for parametric shapes +* **Marker direction**: New `marker.angle`, `marker.angleref`, and `marker.standoff` properties for directional markers +* **Y-axis positioning**: `shift` and `autoshift` properties to avoid y-axis overlapping in multi-axis plots +* **Mapbox clustering**: Clustering options and bounds support for `scattermapbox` traces +* **Equal Earth projection**: New map projection option for geo subplots +* **Pattern fills**: Pattern support extended to pie, funnelarea, sunburst, icicle, and treemap charts +* **Editable selections**: Persistent and editable selections over cartesian subplots with `editSelection` config option +* **Axis label aliases**: `labelalias` for simplified axis label customization +* **Grid styling**: `griddash` property and minor tick/grid line styling options + +Also includes a security fix for prototype pollution and ~90KB bundle size reduction. + +See the [plotly.js releases page](https://github.com/plotly/plotly.js/releases) for the full changelog. + +## Improvements + +* `save_image()` now works with kaleido v1.0 and higher. (#2447) + +## Bug fixes + +* `plotly_build()` now works with `ggmatrix` objects (e.g., from `GGally::ggpairs()`). (#2447) +* Closed #2415: `ggplotly()` now shows variables named 'group' in tooltips when mapped to aesthetics like `colour`. +* Closed #2455, #2460: `ggplotly()` no longer creates empty shapes when `panel.border` is `element_blank()` (ggplot2 4.0.0 compatibility). +* Closed #2466: `ggplotly()` no longer errors when `scale_*_manual()` has unused aesthetics (e.g., `aesthetics = c("colour", "fill")` when only colour is used). +* Closed #2305: `ggplotly()` now respects `geom_boxplot(outlier.shape = NA)` to hide outlier points. +* Closed #2467: `ggplotly()` now correctly shows legends and splits traces when scales have multiple aesthetics. +* Closed #2407, #2187: `ggplotly()` now translates `legend.position` theme element to plotly layout (supports "bottom", "top", "left", and numeric positions). +* Closed #2281: `ggplotly()` no longer drops legends when `geom_blank()` is present in the plot. + +# plotly 4.11.0 + +## New features + +* `ggplotly()` now supports the `{ggridges}` package. (#2314) + +## Improvements + +* Various updates to `ggplotly()` to better support recent versions of ggplot2. (#2315, #2368, #2442, thanks @teunbrand). + +## Bug fixes + +* Closed #2337: Creating a new `event_data()` handler no longer causes a spurious reactive update of existing `event_data()`s. (#2339) +* Closed #2376: Removes errant boxmode warning for grouped boxplot. (#2396) +* Closed #2392: Trivial warning about RColorBrewer minimal n value is no longer thrown (#1999) + +# 4.10.4 + +## Improvements + +* `ggplotly()` now works better with the development version of ggplot2 (> v3.4.4). (#2315) + +# 4.10.3 + +## Improvements + +* `ggplotly()` now works better with the development version of ggplot2 (> v3.4.3). (#2301) + +## Bug fixes + +* Closed #1947: `ggplotly()` now correctly handles `geom_vline`/`geom_hline` with empty data. Previously, if `geom_vline`/`geom_hline` was passed an empty data frame, it would result in an error. The plot is drawn even if no lines are found; this is the same behavior as `ggplot2`. + +* Closed #1214: Do not warn in RStudio on Windows when scattergl is used. Recent RStudio versions can render scattergl correctly. + +* Closed #2298: Fix fill assignment in geom_point when a single shape value was used with multiple fill and colour values mapped (@zeehio) + +# 4.10.2 + +## New features + +* Closed #2216: Additional selectize.js options can now be passed along to `highlight()`'s `selectize` argument. (#2217) + +## Improvements + +* Closed #2259: `ggplotly()` now provides better support for ggplot2 >v3.4.2. (#2262) + +## Bug fixes + +* Closed #2212: `ggplotly()` no longer silently drops legends that are customized through `ggplot2::guide_legend()`. +* Closed #2179: `save_image()` no longer needs `reticulate::py_run_string("import sys")` in order to run without error. (#2179) +* Closed #2218: `highlight(selectize = TRUE)` no longer yields an incorrect selectize.js result when there is a combination of crosstalk and non-crosstalk traces. (#2217) +* Closed #2208: `ggplotly()` no longer errors given a `geom_area()` with 1 or less data points (error introduced by new behavior in ggplot2 v3.4.0). (#2209) +* Closed #2220: `ggplotly()` no longer errors on `stat_summary(geom = "crossbar")`. (#2222) +* Closed #2212: `ggplotly()` no longer removes legends when setting guide properties via `guides(aes = guide_xxx(...))`. + +# 4.10.1 + +## Changes to plotly.js + +* This version of the R package upgrades the version of the underlying plotly.js library from v2.5.1 to v2.11.1. This includes many bug fixes and improvements. The [plotly.js release page](https://github.com/plotly/plotly.js/releases) has the full list of changes. + +## New features + +* `plotlyOutput()` gains a new `fill` parameter. When `TRUE` (the default), the widget's container element is allowed to grow/shrink to fit it's parent container so long as that parent is opinionated about its height and has been marked with `htmltools::bindFillRole(x, container = TRUE)`. (#2198) + * The primary motivation for this is to allow plots to grow/shrink by default [inside `bslib::card_body_fill()`](https://rstudio.github.io/bslib/articles/cards.html#responsive-sizing) +* `ggplotly()` now supports the `{ggalluvial}` package. (#2061, thanks @moutikabdessabour) +* `highlight()` now supports `on="plotly_selecting"`, enabling client-side linked brushing via mouse click+drag (no mouse-up event required, as with `on="plotly_selected"`). (#1280) +* `raster2uri()` supports nativeRaster objects. This enables nativeRaster support for + the `annotation_raster()` geom (#2174, @zeehio). + +## Bug fixes + +* `ggplotly()` now converts `stat_ecdf()` properly. (#2065) +* `ggplotly()` now correctly handles `geom_tile()` with no `fill` aesthetic. (#2063) +* `ggplotly()` now respects `guide(aes = "none")` (e.g., `guide(fill = "none")`) when constructing legend entries. (#2067) +* Fixed an issue with translating `GGally::ggcorr()` via `ggplotly()`. (#2012) +* Fixed an issue where clearing a crosstalk filter would raise an error in the JS console (#2087) +* Fixed an issue where `map_color()` would throw an error on R 4.2 (#2131) + +## Improvements + +* `ggplotly()` does not issue warnings with `options(warnPartialMatchArgs = TRUE)` any longer. (#2046, thanks @bersbersbers) +* `ggplotly()` does not issue warnings related to use of deprecated `tidyr::gather_()` in internals. (#2125, thanks @simonpcouch) + +# 4.10.0 + +## Breaking changes in JavaScript API + +* This version of the R package upgrades the version of the underlying plotly.js library from v1.57.1 to v2.5.1. This includes many breaking changes, bug fixes, and improvements to the underlying JavaScript library. Most of the breaking changes are summarized in [this announcement of the 2.0 release](https://community.plotly.com/t/announcing-plotly-js-2-0/53675), but [see here](https://github.com/plotly/plotly.js/blob/HEAD/CHANGELOG.md) for the full changelog. + +## Breaking changes in R API + +* `ggplotly()` now uses the `layout.legend.title` (instead of `layout.annotations`) plotly.js API to convert guides for discrete scales. (#1961) +* `renderPlotly()` now uses `Plotly.react()` (instead of `Plotly.newPlot()`) to redraw when `layout(transition = )` is specified. This makes it possible/easier to implement a smooth transitions when `renderPlotly()` gets re-executed. (#2001) + +## New Features + +* Added new functions for static image exporting via the [kaleido python package](https://github.com/plotly/Kaleido), namely `save_image()` and `kaleido()`. See `help(save_image, package = "plotly")` for installation info and example usage. (#1971) + +## Improvements + +* `ggplotly()` now better positions axis titles for `facet_wrap()`/`facet_grid()`. (#1975) + +# 4.9.4.1 + +## BUG FIXES + +* Fixes a bug in `ggplotly()` with `{crosstalk}` and `{ggplot2}` v3.3.4 (#1952). + +# 4.9.4 + +## BUG FIXES + +* Duplicate `highlight(selectize=T)` dropdowns are no longer rendered in Shiny (#1936). +* `group_by.plotly()` now properly retains crosstalk information across `{dplyr}` versions (#1920). +* Adds fixes in `ggplotly()` for the upcoming `{ggplot2}` v3.3.4 release (#1952). +* Fixes some issues with `name` and `frames` when both attributes are specified. (#1903 and #1618). + +# 4.9.3 + +## Changes to plotly.js + +* This version of the R package upgrades the version of the underlying plotly.js library from v1.52.2 to v1.57.1. This includes many bug fixes and improvements. The [plotly.js release page](https://github.com/plotly/plotly.js/releases) has the full list of changes. + +## NEW FEATURES + +* `renderPlotly()` now works well with `shiny::bindCache()`, meaning that plotly graphs can now be persistently cached in Shiny apps with `renderPlotly(expr) %>% shiny::bindCache()` (#1879). + +* `ggplotly()` now works well with the [**thematic** package](https://rstudio.github.io/thematic/). That is, it can now correctly translate **ggplot2** styling that derives from **thematic**. Note that, in order to use **thematic**'s auto theming in Shiny with `ggplotly()`, you need **shiny** v1.5.0 (or higher) and **htmlwidgets** v1.5.2.9000 (or higher). Relatedly, if these versions are available, one may now also call `getCurrentOutputInfo()` inside `renderPlotly()` to get CSS styles of the output container (#1801 and #1802). + +## IMPROVEMENTS + +* All HTTP requests are now retried upon failure (#1656, @jameslamb). + +* R linebreaks (`\n`) in _factor labels_ are now translated to HTML linebreaks (`
`), too. Before, this conversion was only done for colums of type character. ([#1700](https://github.com/plotly/plotly.R/pull/1700), @salim-b). + +## BUG FIXES + +* When R's `POSIXt` class is serialized to JSON, the time of day is now correctly preserved (in plotly.js expected `'yyyy-mm-dd HH:MM:SS.ssssss'` format). This should fix a whole host of issues where date-times were being rounded. (#1871, @FlukeAndFeather). + +* `ggplotly()` now handles discrete axes of a `facet_wrap` and `facet_grid` correctly when there is only one category in panels > 1 (#1577 and #1720). + +* `ggplotly()` now correctly accounts for linebreaks in tick label text when computing plot margins (#1791, @trekonom). + +* `ggplotly()` now handles `element_blank()` and `factor()` labels in positional scales correctly (#1731 and #1772). + +* `ggplotly()` now handles missing `y` aesthetic in `geom_errorbar()` (#1779, @trekonom). + +# 4.9.2.1 + +This is minor patch release with a few minor bug fixes and updates test expectations in anticipation of new R 4.0 defaults. + +## BUG FIXES + +* Fixes rendering issues non-HTML **rmarkdown** output formats, which was introduced in the 4.9.2 release (#1702). +* Fixes a `ggplotly()` bug in axis tick translation (#1725, #1721). +* `plot_mapbox()` now correctly defaults to a scattermapbox trace (unless z is present, then it defaults to choroplethmapbox) (#1707). +* `ggplotly()` now correctly resolves overlapping axis tick text in `coord_sf()` (#1673). +* A false-positive warning is no longer thrown when attempting to cast `toWebGL()` (#1569). + +# 4.9.2 + +## Changes to plotly.js + +* This version of the R package upgrades the version of the underlying plotly.js library from v1.49.4 to v1.52.2. This includes many bug fixes, improvements, as well as 2 new trace types: `treemap` and `image`. The [plotly.js release page](https://github.com/plotly/plotly.js/releases) has the full list of changes. + +## IMPROVEMENTS + +* The `add_image()` function was added to make it easier to create image traces via `raster` objects. + +## BUG FIXES + +* `add_sf()`/`geom_sf()` now correctly handle geometry columns that are named something other than `"geometry"` (#1659). +* Specifying an english locale no longer results in error (#1686). + +# 4.9.1 + +## Changes to plotly.js + +* This version of the R package upgrades the version of the underlying plotly.js library from v1.46.1 to v1.49.4. The [plotly.js release page](https://github.com/plotly/plotly.js/releases) has the full list of changes. + +## IMPROVEMENTS + +* `event_data()` gains support for the `plotly_sunburstclick` event (#1648) + +## BUG FIXES + +* Fixed an issue with correctly capturing the return value of user-expressions to `renderPlotly()` (#1528). +* Fixed a resizing issue where graphs could be incorrectly resized to their initial size in some cases (#1553). +* `ggplotly()` now positions the x-axis in the last column of a `facet_wrap()` properly (#1501). +* `ggplotly()` now handles `geom_hline()`/`geom_vline()` correctly in conjunction with `coord_flip()` (#1519). +* `event_data()` now correctly relays the `key` attribute for statistical traces (#1610). + +# 4.9.0 + +## Changes to plotly.js + +* This version of the R package upgrades the version of the underlying plotly.js library from v1.42.3 to v1.46.1. The [plotly.js release page](https://github.com/plotly/plotly.js/releases) has the full list of changes, but here is summary most pertainent ones for the R package: + * New trace types: `sunburst`, `waterfall`, `isosurface`. + * New `hovertemplate` attribute allows for finer-tuned control over tooltip text. See [here](https://plotly-r.com/controlling-tooltips.html#fig:tooltip-format-heatmap) for an example. + * Providing a string to `title` is now deprecated (but still works). Instead, use `title = list(text = "title")`. This change was made to support a new title placement API (e.g., `title = list(text = "title", xanchor = "left")`). Note that these changes are relevant for `layout.title` as well as `layout.xaxis.title`/`layout.yaxis.title`/etc. ## NEW FEATURES & IMPROVEMENTS -* Upgraded to plotly.js v1.42.5. -* Several new features and improvements related to accessing plotly.js events in shiny (learn more about them in this RStudio [webinar](https://resources.rstudio.com/webinars/accessing-and-responding-to-plotly-events-in-shiny-carson-sievert)): +* Several new features and improvements related to accessing plotly.js events in shiny (learn more about them in this RStudio [webinar](https://posit.co/resources/videos/accessing-and-responding-to-plotly-events-in-shiny/)): * The `event` argument of the `event_data()` function now supports the following events: `plotly_selecting`, `plotly_brushed`, `plotly_brushing`, `plotly_restyle`, `plotly_legendclick`, `plotly_legenddoubleclick`, `plotly_clickannotation`, `plotly_afterplot`, `plotly_doubleclick`, `plotly_deselect`, `plotly_unhover`. For examples, see `plotly_example("shiny", "event_data")`, `plotly_example("shiny", "event_data_legends")`, and `plotly_example("shiny", "event_data_annotation")`, * New `event_register()` and `event_unregister()` functions for declaring which events to transmit over the wire (i.e., from the browser to the shiny server). Events that are likely to have large overhead are not registered by default, so you'll need to register these: `plotly_selecting`, `plotly_unhover`, `plotly_restyle`, `plotly_legendclick`, and `plotly_legenddoubleclick`. * A new `priority` argument. By setting `priority='event'`, the `event` is treated like a true event: any reactive expression using the `event` becomes invalidated (regardless of whether the input values has changed). For an example, see `plotly_example("shiny", "event_priority")`. @@ -14,21 +254,28 @@ * The `orca()` function now supports conversion of much larger figures (#1322) and works without a mapbox api token (#1314). * The `orca_serve()` function was added for efficient exporting of many plotly graphs. For examples, see `help(orca_serve)`. * The `orca()` function gains new arguments `more_args` and `...` for finer control over the underlying system commands. - + +* `ggplotly()` now respects horizontal alignment of **ggplot2** titles (e.g., `ggplotly(qplot(1:10) + ggtitle("A title") + theme(plot.title = element_text(hjust = 1)))`). * **plotly** objects can now be serialized and unserialized in different environments (i.e., you can now use `saveRDS()` to save an object as an rds file and restore it on another machine with `readRDS()`). Note this object is *dynamically* linked to JavaScript libraries, so one should take care to use consistent versions of **plotly** when serializing and unserializing (#1376). * The `style()` function now supports "partial updates" (i.e. modification of a particular property of an object, rather than the entire object). For example, notice how the first plot retains the original marker shape (a square): `p <- plot_ly(x = 1:10, y = 1:10, symbol = I(15)); subplot(style(p, marker.color = "red"), style(p, marker = list(color = "red")))` (#1342). * The `method` argument of `plotlyProxyInvoke()` gains support for a `"reconfig"` method. This makes it possible to modify just the configuration of a plot in a **shiny** app. For an example use, see `plotly_example("shiny", "event_data_annotation")`. * The `plotly_example()` function will now attempt to open the source file(s) used to run the example. Set `edit = FALSE` to prevent the source file(s) from opening. +* An informative warning is now thrown if invalid argument names are supplied to `config()`. ## CHANGES -* The 'collaborate' button no longer appears in the modebar, and as a result, the `config()` function no longer has a `collaborate` argument. +* If `stroke` is specified, `span` now defaults to `I(1)`. This results in a slightly narrower default span for some trace types (e.g., `box`, `contour`), but it also ensures the `stroke` is always visible when it's relevant (e.g. `plot_ly(x = 1:10, y = 1:10, stroke = I("black"))`), making for a more consistent overall default (#1507). +* The 'collaborate' button no longer appears in the modebar, and is longer supported, so the `config()` function no longer has a `collaborate` argument. +* The `cloud` argument is now deprecated and will be removed in a future version. Use `showSendToCloud` instead. +* `ggplotly()` now translates title information to `layout.title.text` (instead of `layout.title`) and `layout.title.font` (instead of `layout.titlefont`) ## BUG FIXES * `subplot()` now works much better with annotations, images, and shapes: - When `xref`/`yref` references an x/y axis these references are bumped accordingly (#1181). - When `xref`/`yref` references paper coordinates, these coordinates are updated accordingly (#1332). +* `subplot()` now repositions shapes with fixed height/width (i.e., `xsizemode`/`ysizemode` of `"pixel"`) correctly (#1494). +* The `colorscale` attribute now correctly handles a wider range of input values (#1432, #1485) * The colorscale generated via the `color` argument in `plot_ly()` now uses an evenly spaced grid of values instead of quantiles (#1308). * When using **shinytest** to test a **shiny** that contains **plotly** graph, false positive differences are no longer reported (rstudio/shinytest#174). * When the `size` argument maps to `marker.size`, it now converts to an array of appropriate length (#1479). @@ -41,6 +288,7 @@ * Recursive attribute validation is now only performed on recursive objects (#1315). * The `text` attribute is no longer collapsed to a string when `hoveron='fills+points'` (#1448). * `layout.[x-y]axis.domain` is no longer supplied a default when `layout.grid` is specified (#1427). +* When uploading charts to a plot.ly account via `api_create()`, layout attributes are no longer incorrectly src-ified, which was causing inconsistencies in local/remote rendering of `ggplotly()` charts (#1197). # 4.8.0 @@ -59,8 +307,8 @@ ### Other improvements relevant for all **plotly** objects -* LaTeX rendering via MathJax is now supported and the new `TeX()` function may be used to flag a character vector as LaTeX (#375). Use the new `mathjax` argument in `config()` to specify either external (`mathjax="cdn"`) or local (`mathjax="local"`) MathJaX. If `"cdn"`, mathjax is loaded externally (meaning an internet connection is needed for TeX rendering). If `"local"`, the PLOTLY_MATHJAX_PATH environment variable must be set to the location (a local file path) of MathJax. IMPORTANT: **plotly** uses SVG-based mathjax rendering which doesn't play nicely with HTML-based rendering (e.g., **rmarkdown** documents and **shiny** apps). To leverage both types of rendering, you must `