Library / SDK
plotly/plotly.R avatar
plotly/plotly.R

plotly for R: interactive web graphics from ggplot2 or plot_ly()

An interactive graphing library for R

2,682 stars641 forksRNOASSERTION

At a glance

What is it?
The R package plotly wraps plotly.js so R users can turn static ggplot2 output into interactive web charts, or build charts directly with plot_ly(). It is a good fit for Shiny dashboards and HTML reports, and a poor fit for anyone who needs a static PDF figure pipeline.
Who is it for?
Adopt plotly for R when the deliverable is an interactive HTML page or a Shiny app and you already work in ggplot2 or want plotly.js chart types such as surface and mesh. Do not adopt it when the deliverable must be a static print figure or a non-HTML format, because the package renders through plotly.js in a browser.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 67 days ago.
What is it written in?
Mainly R, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What plotly for R solves, and for whom

R has a strong static graphics tradition, and ggplot2 in particular produces publication-quality output. What it does not produce by default is a chart a reader can hover over, zoom into, or filter. plotly for R exists to close that gap. The README describes it as "An R package for creating interactive web graphics via the open source JavaScript graphing library plotly.js." The R code you write is a front end; the rendering happens in JavaScript in the browser.

The audience is therefore specific. Analysts who already have ggplot2 code and want to publish it as an interactive HTML page. Shiny developers who need charts that respond to input. People who need chart types the ggplot2 API does not cover, which the README names directly: parallel coordinates, maps, surface, mesh, trisurf. If your output goes to a journal PDF or a printed report, this package is aimed at a different problem, and the README makes no claim otherwise.

There is also a maintenance signal worth reading carefully. The repository carries the badge "Maintained by the Plotly Community" linking to dash.plotly.com/project-maintenance, and the last push to the master branch was on 2026-07-25, with release v4.12.1 tagged the same day. That is recent, but the community-maintained badge is a statement about who does the work, not a promise about how fast issues close.

Two entry points: ggplotly() and plot_ly()

The package offers two ways in, and they lead to the same place. The first is ggplotly(), which converts an existing ggplot2 object. The README states that by default ggplotly() "tries to replicate the static ggplot2 version exactly (before any interaction occurs)", which is the design goal: the initial frame should look like the plot you already have, and interactivity is added on top. The conversion is not a rasterization step. The ggplot2 specification is translated into plotly.js trace attributes.

The second entry point is plot_ly(), described in the README as "a more direct interface to plotly.js". This is where you go for chart types ggplot2 will not express. The README's own example is a surface plot of the volcano dataset, and it names parallel coordinates, maps, mesh and trisurf as further cases.

The two paths converge because ggplotly() returns a plotly object, not a foreign structure. The README says you can then apply "essentially any function from the R package on that object", and lists layout() for customizing the layout, add_traces() and its add_*() siblings such as add_polygons() for adding data, subplot() for combining multiple plotly objects, and plotly_json() for inspecting the underlying JSON sent to plotly.js. That last function is the most useful debugging tool in the package: when a chart does not look the way you expect, you can read the JSON that actually reaches the JavaScript layer rather than guessing at the translation.

Installing plotly for R and drawing a first chart

The README gives two install routes. The stable release comes from CRAN, and the development version comes from GitHub through the remotes package. Run one of these in an R session; the first is the one most users want.

r
install.packages("plotly")

If you need the code currently on the master branch rather than the released version, the README gives this alternative. It requires remotes to be installed first.

r
remotes::install_github("plotly/plotly")

For a first real chart, the README's getting-started example starts from ggplot2 and converts it. The code below is copied from the README: it loads plotly, builds a density plot of the faithful dataset, and passes it to ggplotly().

r
library(plotly)
g <- ggplot(faithful, aes(x = eruptions, y = waiting)) +
  stat_density_2d(aes(fill = ..level..), geom = "polygon") +
  xlim(1, 6) + ylim(40, 100)
ggplotly(g)

What you should see is the same density plot rendered in a browser context, with hover tooltips and axis zoom. If you want a chart the ggplot2 API cannot express, the README's one-line example is the direct interface, and it renders a 3D surface from the volcano matrix.

r
plot_ly(z = ~volcano, type = "surface")

The package ships with runnable examples, which is the fastest way to see what the translation does in practice. The README says to list them with demo(package = "plotly"), and to list the Shiny and R Markdown examples with plotly_example("shiny") or plotly_example("rmd"). The demo/ directory in the repository contains the source for those, including crosstalk-filter and crosstalk-highlight examples and several sf-mapbox examples.

Tuning the translation, and where it stops being exact

The claim that ggplotly() replicates the static plot exactly holds for the initial render, and the README is explicit that this is "before any interaction occurs". Once a reader zooms or the axis recomputes, the two can diverge. The package gives you two levers over that behavior.

The first is a set of high-level arguments on ggplotly() itself. The README singles out dynamicTicks, which "tells plotly.js to dynamically recompute axes, when appropriate". This is a real trade-off rather than a free improvement: recomputed axes can produce a cleaner view of a zoomed region, and they can also change tick labels in ways that surprise a reader who expects the original scale to persist.

The second lever is style(), which modifies the underlying trace attributes used to generate the plot. The README's example combines both, setting dynamicTicks on the y axis and then adjusting hover behavior.

r
gg <- ggplotly(g, dynamicTicks = "y")
style(gg, hoveron = "points", hoverinfo = "x+y+text", hoverlabel = list(bgcolor = "white"))

The arguments here are plotly.js trace attributes, not ggplot2 concepts, and the README links to the plotly.com/r/reference/ page for hoveron. That is the boundary to understand: the moment you reach for style() you have left the ggplot2 grammar and are configuring the JavaScript layer through R. The README also notes that ggplotly() respects some aesthetics it calls "unofficial" in ggplot2, namely text for customizing the tooltip, frame for creating animations, and ids for ensuring sensible smooth transitions. Unofficial is the operative word. These are conventions the package honors, not part of the ggplot2 contract.

Limitations: browser rendering, no rollback story, and the ggplot2 ceiling

The most consequential limitation is structural. The output is a web graphic. The README frames the package entirely around "interactive web graphics", and the rendering library is JavaScript. If your target is a static image, you are working against the design. The README points to a page on "editing and generating static images" at plotly-r.com, so export exists, but it is a separate concern from the interactive path rather than the default.

The second limitation is that ggplotly() cannot exceed what it is translating. The README states that plot_ly() exists partly because some visualization "the ggplot2 API won't ever support", naming surface, mesh and trisurf. If your chart type is outside ggplot2's vocabulary, the conversion route is not available to you and you start from plot_ly().

The third is documentation coverage for the upgrade path. The repository has a NEWS.md at the top level, which is where release notes live, but the README does not document rollback or a downgrade procedure, and it does not describe a deprecation policy for the trace attributes that style() exposes. Those attributes belong to plotly.js, whose own release cycle is separate from this package's. A pinned version in your environment is the only reliable way to keep a working chart stable, and the README does not tell you that; it is an inference from the fact that the R package is a wrapper around a JavaScript library with its own versioning.

How plotly for R differs from building charts in Python

The comparison users most often reach for is plotly for Python. Both are official bindings to the same plotly.js renderer, so the browser output is generated by the same library and the chart types available are largely the same set. The difference is the host language and what comes with it. In R, the distinctive feature is ggplotly(): the ability to take an existing ggplot2 specification and translate it, which has no equivalent in the Python binding because there is no ggplot2 there. The README also points to a specific R-oriented tutorial site, plotly-r.com, and describes it as "meant to be more wholistic tutorial written by and for the R user", in contrast to plotly.com/r/, which the README calls "essentially a language-agnostic how-to guide for learning plotly.js".

Against a purely static R graphics stack, the difference is the output format rather than the API. A base R or ggplot2 plot goes to a device and becomes a file. A plotly object goes to an HTML page and stays live. That is the whole trade, and it is worth stating plainly because it is not reversible without rework: interactivity is not something you add to a finished static figure, it is a different rendering target.

Within R itself, the package's Shiny integration is the other axis. The README links to a chapter on linking views with Shiny, and the repository's demo/ directory contains a set of crosstalk examples, including crosstalk-filter-dynamic-axis.R and several crosstalk-highlight variants. Crosstalk is the mechanism for linking multiple htmlwidgets so a selection in one filters another, which is the R-native answer to cross-chart brushing.

Licence, releases and what an upgrade actually costs

The repository's licence metadata reports NOASSERTION, and the top level contains both a LICENSE and a LICENSE.md file. That means an automated licence classifier did not reach a confident conclusion, and you should read those two files directly before you rely on the package in a distributed product. This is a factual observation about the metadata, not a legal opinion; if the licence terms matter to your organization, that is a question for whoever handles licensing, not for a README.

On upgrade cost, the release cadence is visible. v4.11.0 was tagged on 2025-06-19, v4.12.0 on 2026-01-24, and v4.12.1 on 2026-07-25. The gap between 4.11.0 and 4.12.0 is roughly seven months, and the patch release followed six months later. Minor releases at that spacing can carry behavior changes in the ggplotly() translation, and the package exposes plotly.js trace attributes through style(), so a plotly.js bump inside a minor release can alter hover or axis behavior even when your R code is untouched. The practical mitigation is to pin the package version in whatever environment builds your reports, and to use plotly_json() to capture the JSON a working chart produces so you have a before-and-after comparison when you upgrade. The README documents plotly_json() as a tool for "inspecting the underlying JSON sent to plotly.js"; using it as an upgrade regression check is an application of that documented function, not a feature the README advertises.

Editorial conclusion

Adopt plotly for R when the deliverable is an interactive HTML page or a Shiny app and you already work in ggplot2 or want plotly.js chart types such as surface and mesh. Do not adopt it when the deliverable must be a static print figure or a non-HTML format, because the package renders through plotly.js in a browser. Verify first that your deployment target can serve the HTML dependencies and that the chart types you need appear in the plotly.js reference the package points to, then run demo(package = "plotly") locally to see which of the shipped examples match your use case.

Frequently asked questions

How do I install plotly for R?

The README gives two routes: install.packages("plotly") for the CRAN release, or remotes::install_github("plotly/plotly") for the latest development version on GitHub.

What are the disadvantages of using plotly for R?

The package renders interactive web graphics through plotly.js, so the output is HTML rather than a static figure, and ggplotly() can only translate what the ggplot2 API expresses. The README notes that chart types such as surface, mesh and trisurf require plot_ly() instead.

Is plotly for R free?

The repository's licence metadata reports NOASSERTION and it ships both LICENSE and LICENSE.md files at the top level, so the terms are not stated in the README. Read those files directly rather than relying on the metadata field.

How do I use plotly for R?

There are two entry points. ggplotly() converts an existing ggplot2 object, and plot_ly() is the more direct interface to plotly.js for chart types ggplot2 does not cover. Both return plotly objects, so functions such as layout(), add_traces() and subplot() apply to either.

Should I use plotly for R or plotly for Python?

Both wrap the same plotly.js renderer, so the browser output comes from the same library. The R package's distinctive feature is ggplotly(), which translates an existing ggplot2 specification; that has no equivalent in the Python binding because ggplot2 does not exist there.

Official sources

  1. Issues
  2. plotly/plotly.R on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/plotly-plotly-r.svg)](https://hysenlabs.com/projects/plotly-plotly-r)