Changes in version 4.12.0.9000
- Completed the plot_ly() documentation for what happens when type is
not specified (#2362).
- Removed the dependency on the {lazyeval} package.
Bug fixes
- Closed #2483: save_image() no longer embeds Windows file paths
directly into Python source passed to reticulate, fixing static
image export with Kaleido on Windows.
Changes in version 4.12.0 (2026-01-24)
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 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.
Changes in version 4.11.0 (2025-06-19)
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)
Changes in version 4.10.4 (2024-01-13)
Improvements
- ggplotly() now works better with the development version of ggplot2
(> v3.4.4). (#2315)
Changes in version 4.10.3 (2023-10-21)
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)
Changes in version 4.10.2 (2023-06-03)
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(...)).
Changes in version 4.10.1 (2022-11-07)
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 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()
- 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)
Changes in version 4.10.0 (2021-10-09)
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, but see here 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, 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)
Changes in version 4.9.4.1 (2021-06-18)
BUG FIXES
- Fixes a bug in ggplotly() with {crosstalk} and {ggplot2} v3.3.4
(#1952).
Changes in version 4.9.4 (2021-06-08)
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).
Changes in version 4.9.3 (2021-01-10)
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 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. 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, @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).
Changes in version 4.9.2.1 (2020-04-04)
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).
Changes in version 4.9.2 (2020-02-12)
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 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).
Changes in version 4.9.1 (2019-11-07)
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 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).
Changes in version 4.9.0 (2019-04-10)
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 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 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
- Several new features and improvements related to accessing plotly.js
events in shiny (learn more about them in this RStudio webinar):
- 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").
- The event_data() function now relays the (official plotly.js)
customdata attribute in similar fashion to (unofficial) key
attribute (#1423). Run plotly_example("shiny", "event_data") for
an example.
- event_data("plotly_selected") is no longer too eager to clear.
That is, it is no longer set to NULL when clicking on a plot
after triggering the "plotly_selected" event (#1121) (#1122).
- Several new features and improvements for exporting static graphs
with the orca command-line utility:
- 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
- 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).
- The color and stroke arguments now work as expected for trace types
with fillcolor but no fill attribute (e.g. box traces) (#1292).
- Information emitted by in event_data() for heatmaps with atomic
vectors for x/y/z is now correct (#1141).
- Fixed issue where dplyr groups caused a problem in the ordering of
data arrays passed to marker objects (#1351).
- In some cases, a ggplotly() colorbar would cause issues with hover
behavior, which is now fixed (#1381).
- An articial marker no longer appears when clearing a crosstalk
selection of a plot with a colorbar (#1406).
- Clearing a highlight event via crosstalk no longer deletes all the
traces added since initial draw (#1436).
- 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).
Changes in version 4.8.0 (2018-07-20)
NEW FEATURES & IMPROVEMENTS
plotly.js and plot_ly() specific improvements
- Upgraded to plotly.js v1.39.2. A huge amount of features and
improvements have been made since v1.29.2 (i.e., the version
included in the last CRAN release of the R package - v4.7.1).
Highlights include a complete re-write of scattergl to make it
nearly feature complete with scatter, localization of text rendering
(i.e., international translations), and six new trace types (cone,
scatterpolar, scatterpolargl, splom, table, & violin)! See here for
a complete list of plotly.js-specific improvements.
- Support for sf (simple feature) data structures was added to
plot_ly(), plot_mapbox(), and plot_geo() (via the new add_sf()
function). See this blog post for an overview.
- Better control over the stroke (i.e., outline) appearance of various
filled graphical marks via the new "special arguments" (stroke,
strokes, alpha_stroke, span, and spans). For an overview, see the sf
blog post linked to in the bullet point above and the new package
demos (list all demos with demo(package = "plotly")).
ggplotly() specific improvements
- ggplotly() now supports conversion of ggplot2's geom_sf().
- One may now inform ggplotly() about the relevant shiny output size
via session$clientData. This ensures ggplotly() sizing is closer to
ggplot2 sizing, even on window resize. For an example, run
plotly_example("shiny", "ggplotly_sizing").
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