Note: This package was forked from Yihui Xie and is based on the last release of Baidu Echarts2 (v2.2.7). The documentation here always reflects the latest development version of recharts on Github. The package recharts2 that is based on Echarts3 is still under development.
To install the package:
if (!require(devtools)) library(devtools)
install_github("madlogos/recharts")
The R package recharts provides an interface to the JavaScript library ECharts2 for data visualization. The goal of this package is to make it easy to create charts with only a few lines of R code. R users should be able to get started with ECharts without having to know HTML or JavaScript, although advanced users will benefit from their knowledge of JavaScript. Here is an example of a scatterplot that shows the basic syntax of this package:
library(recharts)
echartr(iris, Sepal.Length, Sepal.Width, series = Species)
You can always call
browseVignettes("recharts")
to view the manual locally.
The recharts package was built on top of htmlwidgets, which can save us a lot of time on managing JavaScript dependencies and dealing with different types of output documents such as R Markdown and Shiny. You just create a chart, and we will take care of the rest of things when the chart is renderd in R Markdown, Shiny, or the R console / RStudio.
The main function in this package is the echartr()
function (an S3 generic function), and we want to make it smart enough to deal with different types of R data automatically. For example, when a data frame is passed to echart()
, and the x
/y
variables are numeric, it should automatically figure out that you probably need a scatterplot, and the axes will be automatically generated. Of course, you can also override the automatic guess.
Follow the steps below to make a plot yourself.
Always start from data itself. Let’s use mtcars
in the package datasets
. You can type ?mtcars
to read the instruction.
head(mtcars)
## mpg cyl disp hp drat wt qsec vs am gear carb
## Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
## Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
## Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
## Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
## Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
## Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1
We want to know the relationship between wt
(weight) and mpg
(miles per gallon), a scatterplot is a good fit. It requires x and y variables of numeric.
Use echartr
to build the basic chart.
echartr(mtcars, wt, mpg)
The grammar of echartr
is
## function (data, x = NULL, y = NULL, series = NULL, weight = NULL,
## facet = NULL, t = NULL, lat = NULL, lng = NULL, type = "auto",
## subtype = NULL, elementId = NULL, ...)
Arg | Interpretation |
---|---|
data |
source data in the form of data.frame |
x |
Independent variable(s). One or more columns of
|
y |
dependent variable(s). One or more columns of |
series |
series variable. A column of |
weight |
weight variable used in bubble, bar/column, line/area chart, linking with the size of graph elements. |
facet |
facet variable to devide the canvas into facets. Only applicable for multi-coordinate system charts (e.g., pie charts). |
t |
time variable. If |
lat |
latitude variable for map/heatmap. |
lng |
longitude variable for map/heatmap. |
type |
chart type. Default ‘auto’. |
subtype |
chart subtype. Default NULL. |
echartr
now supports the following types (the regex patterns in ‘name’ column, case insensitive). The ‘type’ column lists chart type names supported by Echarts2.
knitr::kable(recharts:::validChartTypes[,c(1:3,5)])
id | name | type | misc |
---|---|---|---|
1 | ^(scatter|point)$ | scatter | |
2 | ^(bubble)$ | scatter | bubble |
3 | ^(bar|hbar)$ | bar | flip |
4 | ^(vbar|column)$ | bar | |
5 | ^(histogram|hist)$ | hist | |
6 | ^(line)$ | line | |
7 | ^(curve)$ | line | smooth |
8 | ^(area)$ | line | fill |
9 | ^(wave)$ | line | fill_smooth |
10 | ^(map_world|world_map)$ | map | world |
11 | ^(map_china|china_map)$ | map | china |
12 | ^(map_world_multi|world_map_multi)$ | map | world_multi |
13 | ^(map_china_multi|china_map_multi)$ | map | china_multi |
14 | ^(map)$ | map | geojson |
15 | ^(k|candlestick)$ | k | |
16 | ^(pie)$ | pie | |
17 | ^(ring)$ | pie | ring |
18 | ^(rose)$ | pie | rose |
19 | ^(chord)$ | chord | |
20 | ^(force|force_curve)$ | force | |
21 | ^(force_line)$ | force | line |
22 | ^(funnel)$ | funnel | |
23 | ^(pyramid)$ | funnel | ascending |
24 | ^(tree|vtree|tree_vertical)$ | tree | |
25 | ^(htree|tree_horizontal)$ | tree | horizontal |
26 | ^(tree_inv|vtree_inv|tree_vertical_inv)$ | tree | inv |
27 | ^(htree_inv|tree_horizontal_inv)$ | tree | horizontal_inv |
28 | ^(treemap)$ | treemap | |
29 | ^(wordcloud)$ | wordCloud | |
30 | ^(heatmap)$ | heatmap | |
31 | ^(radar|spider|star)$ | radar | |
32 | ^(gauge|dashboard)$ | gauge | |
33 | ^(eventriver)$ | eventRiver | |
34 | ^(venn)$ | venn |
You assign data
and x
, y
, then echartr
automatically processes the data using recharts:::series_scatter
function.
If series
is assigned, a series-specfic scatterplot is shown.
echartr(mtcars, wt, mpg, factor(am, labels=c('Automatic', 'Manual')))
If weight
is assigned and type
is set bubble
, a bubble chart is displayed.
echartr(mtcars, wt, mpg, am, weight=gear, type='bubble')
## Warning in split_indices(.group, .n): '.Random.seed' is not an integer
## vector but of type 'NULL', so ignored
The input param list could be
wt
, mpg
or even as complicated as factor(am, labels=c('Automatic', 'Mannual'))
'wt'
, 'mpg'
~wt
, ~mpg
Data must be a data.frame. The data series and timeline will display in the original order of series
and t
, so you should sort the data.frame before making charts so as to make sure the display order is exactly what you want.
When it comes to timeline (t
), you must be very cautious. All the combination sets of x
, y
, series
, weight
should be exactly equal across all the levels of t
. Otherwise you will find confusious overlap of graphs across timeline.
recharts
supports mixed chart types in some cases, e.g., bar and line.
By now, recharts
only supports the following misure of types: - Cartesian coordinate charts: scatterplot/bubble, bar/column, line/area charts - Polar coordinate charts: funnel, pie/ring charts - Others: force, chord charts
d <- data.table::dcast(mtcars, carb+gear~., mean, value.var='mpg')
names(d)[3] <- 'mean.mpg'
d$carb <- as.character(d$carb)
echartr(d, carb, "mean.mpg", gear, type=c('vbar', 'vbar', 'line')) %>%
setSymbols('emptycircle')
Or mixed subtypes. Refer to ‘subtype’ column in recharts:::validChartTypes
. You can assign combined subtypes using ‘+’, ’_‘or’|‘, e.g., ’stack+smooth’ to simultaneously render the line chart stacked and smooth.
echartr(d, carb, mean.mpg, gear, type='line',
subtype=c('stack + smooth', 'stack + dotted', 'smooth + dashed')) %>%
setSymbols('emptycircle')
The above example shows how to associate type/subtype with series. If you want to associate type/subtype with facets, you need to wrap them in a list. Within each list, the vector of type/subtypes are associated with series, ie, list[[1]], list[[2]], … are associated with facet 1, 2, …, while list[[1]][1], list[[1]][2], … are associated with series 1, 2, …
If facet has 2 levels and series has 3 levels, it means type and subtype should have a structure of list(c(s1,s2,s3), c(s1,s2,s3)). recharts will try to supplement/cut the income params type and subtype to meet the mapping relationship.
Series/facet | facet 1 | facet 2 | … | facet i |
---|---|---|---|---|
series 1 | list[[1]][1] | list[[2]][1] | … | list[[i]][1] |
series 2 | list[[1]][2] | list[[2]][2] | … | list[[i]][2] |
… | … | … | … | … |
series j | list[[1]][j] | list[[2]][j] | … | list[[i]][j] |
d1 <- data.frame(x=rep(LETTERS[1:6], 4), y=abs(rnorm(24)),
f=c(rep('i', 12), rep('ii', 12)),
s=rep(c(rep('I', 6), rep('II', 6)), 2))
echartr(d1, x, y, s, facet=f, type='radar',
subtype=list(c('fill', ''), c('', 'fill')))
You can save the plot as an object and keep modifying the plot using %>%
.
g = echartr(mtcars, wt, mpg, factor(am, labels=c('Automatic', 'Manual')))
The above command made an Echarts object g
containing two series: ‘Automatic’ and ‘Manual’. The data strcuture of g
is:
- x
|-- series
|--- list 1
|---- name: 'Automatic'
|---- data: ...
|---- type: 'scatter'
|--- list 2
|---- name: 'Manual'
|---- data: ...
|---- type: 'scatter'
|--- ...
|-- legend
|-- xAxis
|-- yAxis
|-- grid
|-- tooltip
|-- ...
If you want to customize the definition of the series directly, you can call the low-level function setSeries
.
Let’s set ‘Manual’ series (series index 2) symbolSize 8, symbolRotate 30.
g %>% setSeries(series=2, symbolSize=8, symbolRotate=30)
Markline the average level of the two series.
g %>% addMarkLine(data=data.frame(type='average', name1='Avg'))
Markpoint the maximum of series 1 (‘Automatic’).
g %>% addMarkPoint(series=1, data=data.frame(type='max', name='Max'))
It’s the same as
g %>% addMarkPoint(series='Automatic', data=data.frame(type='max', name='Max'))
Add title (in red) and subtitle (with reference link to https://stat.ethz.ch/R-manual/R-devel/library/datasets/html/mtcars.html) to the chart.
link <- 'https://stat.ethz.ch/R-manual/R-devel/library/datasets/html/mtcars.html'
g %>% setTitle('wt vs mpg', paste0('[Motor Trend](', link, ')'),
textStyle=list(color='red'))
Modify the legend (in lime), and only select series 1 (‘Automatic’) at the beginning.
g %>% setLegend(selected='Automatic', textStyle=list(color='lime'))
Modify toolbox as English, and put it to the upper-right of the chart with vertical display.
Refer to
vecPos()
function to see howpos
is defined.
g %>% setToolbox(lang='en', pos=2)
Add dataZoom (orignally there is not one).
g %>% setDataZoom()
Modify axes to make x- and y-axis cross at zero.
g %>% setXAxis(min=0) %>% setYAxis(min=0)
Apply ‘dark’ theme to the chart. You can also apply “macarons”, “infographic”, “blue”, “dark”, “gray”, “green”, “helianthus”, “macarons2”, “mint”, “red”, “roma”, “sakura”, “shine”, and “vintage”.
Calculable is a special interation in Echarts. In other charts (e.g.,pie), it is quite efficient.
g %>% setTheme('dark', calculable=TRUE)
Set symbolList for series 1 (‘Automatic’) ‘heart’ and that for series 2 (‘Manual’) ‘star6’.
g %>% setSymbols(c('heart', 'star6'))
You can combine all the steps using a pipe chain. If you are familiar with JS, you can embed JS fragments using JS()
for better effects.
g %>% setSeries(series=2, symbolSize=8, symbolRotate=30) %>%
addMarkLine(data=data.frame(type='average', name1='Avg')) %>%
addMarkPoint(series=1, data=data.frame(type='max', name='Max')) %>%
setTitle('wt vs mpg', paste0('[Motor Trend](', link, ')'),
textStyle=list(color='red')) %>%
setLegend(selected='Automatic', textStyle=list(color='lime')) %>%
setToolbox(lang='en', pos=2) %>% setDataZoom() %>%
setTheme('dark', calculable=TRUE) %>% setSymbols(c('heart', 'star6'))
Given that ECharts supports so many types of charts, it may take a while for us to make echartr()
really smart. With that in mind, we also provided a really low-level S3 method defined for lists. Since the main usage of ECharts is that you pass a JavaScript object to the method .setOption()
, and we can construct such an object using a list in R. This low-level echart.list()
method makes it possible for you to create arbitrary charts. Here is a simple example of a Chord diagram taken from http://echarts.baidu.com/doc/example/chord1.html:
chordEx1 = list(
title = list(
text = '测试数据',
subtext = 'From d3.js',
x = 'right',
y = 'bottom'
),
tooltip = list(
trigger = 'item',
formatter = JS('function(params) {
if (params.indicator2) { // is edge
return params.value.weight;
} else {// is node
return params.name
}
}')
),
toolbox = list(
show = TRUE,
feature = list(
restore = list(show = TRUE),
magicType = list(show = TRUE, type = c('force', 'chord')),
saveAsImage = list(show = TRUE)
)
),
legend = list(
x = 'left',
data = c('group1', 'group2', 'group3', 'group4')
),
series = list(
list(
type = 'chord',
sort = 'ascending',
sortSub = 'descending',
showScale = TRUE,
showScaleText = TRUE,
data = list(
list(name = 'group1'),
list(name = 'group2'),
list(name = 'group3'),
list(name = 'group4')
),
itemStyle = list(
normal = list(
label = list(show = FALSE)
)
),
matrix = rbind(
c(11975, 5871, 8916, 2868),
c( 1951, 10048, 2060, 6171),
c( 8010, 16145, 8090, 8045),
c( 1013, 990, 940, 6907)
)
)
)
)
echart(chordEx1)
It is exactly the same as
mat <- as.data.frame(rbind(
c(11975, 5871, 8916, 2868),
c( 1951, 10048, 2060, 6171),
c( 8010, 16145, 8090, 8045),
c( 1013, 990, 940, 6907)
))
names(mat) <- c("group1", "group2", "group3", "group4")
mat$name <- names(mat)
echartr(mat, x=name, y=c(group1, group2, group3, group4), type="chord",
subtype='ribbon + asc + descsub + hidelab + scaletext') %>%
setTitle("测试数据", subtitle="From d3.js", pos=5)
Apparently, all we did was to translate the JavaScript object in the original example into R. Note we translated the function tooltip.fomatter
using the JS()
function in htmlwidgets. All other objects can be mapped naturally to R.
We can also yield an echarts object using echartr
and then modify the object directly as we do to a S3 list, if we are familiar with echarts data structure.
The following is the structure of the object g
we producted by echartr(mtcars, wt, mpg, factor(am, labels=c('Automatic', 'Mannual')))
.
enquote(g)
## quote(list(x = list(series = list(list(name = "Automatic", type = "scatter",
## data = list(list(3.215, 21.4), list(3.44, 18.7), list(3.46,
## 18.1), list(3.57, 14.3), list(3.19, 24.4), list(3.15,
## 22.8), list(3.44, 19.2), list(3.44, 17.8), list(4.07,
## 16.4), list(3.73, 17.3), list(3.78, 15.2), list(5.25,
## 10.4), list(5.424, 10.4), list(5.345, 14.7), list(2.465,
## 21.5), list(3.52, 15.5), list(3.435, 15.2), list(3.84,
## 13.3), list(3.845, 19.2))), list(name = "Manual", type = "scatter",
## data = list(list(2.62, 21), list(2.875, 21), list(2.32, 22.8),
## list(2.2, 32.4), list(1.615, 30.4), list(1.835, 33.9),
## list(1.935, 27.3), list(2.14, 26), list(1.513, 30.4),
## list(3.17, 15.8), list(2.77, 19.7), list(3.57, 15), list(
## 2.78, 21.4)))), legend = list(show = TRUE, data = list(
## "Automatic", "Manual"), x = "left", y = "top", orient = "horizontal"),
## yAxis = list(list(type = "value", show = TRUE, position = "left",
## name = "mpg", nameLocation = "end", boundaryGap = c(0,
## 0), scale = TRUE, axisLine = list(show = TRUE, onZero = FALSE),
## axisTick = list(show = FALSE), axisLabel = list(show = TRUE),
## splitLine = list(show = TRUE), splitArea = list(show = FALSE))),
## xAxis = list(list(type = "value", show = TRUE, position = "bottom",
## name = "wt", nameLocation = "end", boundaryGap = c(0,
## 0), scale = TRUE, axisLine = list(show = TRUE, onZero = FALSE),
## axisTick = list(show = FALSE), axisLabel = list(show = TRUE),
## splitLine = list(show = TRUE), splitArea = list(show = FALSE))),
## tooltip = list(show = TRUE, trigger = "axis", axisPointer = list(
## type = "cross", crossStyle = list(type = "dashed"), lineStyle = list(
## type = "solid", width = 1), shadowStyle = list(color = "rgba(150,150,150,0.3)",
## width = "auto", type = "default")), textStyle = list(
## color = "#fff"), formatter = "function (params) {\n var i;\n var text = params.value[0];\n if (params.seriesName === null || params.seriesName === \"\"){\n if (params.value.length > 1) {\n for (i = 1; i < params.value.length; i++){\n text += \" , \" + params.value[i];\n }\n return text;\n } else {\n return params.name + \" : \" + text;\n }\n } else {\n if (params.value.length > 1) {\n text = params.seriesName + \" :<br/>\" + text;\n for (i = 1; i < params.value.length; i++) {\n text += \" , \" + params.value[i];\n }\n return text;\n } else {\n return params.seriesName + \" :<br/>\"\n + params.name + \" : \" + text;\n }\n }\n }",
## islandFormatter = "{a} < br/>{b} : {c}", enterable = FALSE,
## showDelay = 20, hideDelay = 100, transitionDuration = 0.4,
## backgroundColor = "rgba(0,0,0,0.7)", borderColor = "#333",
## borderWidth = 0, borderRadius = 4), toolbox = list(show = TRUE,
## feature = list(mark = list(show = TRUE), dataZoom = list(
## show = TRUE), dataView = list(show = TRUE, readOnly = FALSE),
## magicType = list(show = FALSE), restore = list(show = TRUE),
## saveAsImage = list(show = TRUE)), x = "right", y = "top",
## orient = "horizontal")), width = NULL, height = NULL,
## sizingPolicy = list(defaultWidth = NULL, defaultHeight = NULL,
## padding = NULL, viewer = list(defaultWidth = NULL, defaultHeight = NULL,
## padding = NULL, fill = TRUE, suppress = FALSE, paneHeight = NULL),
## browser = list(defaultWidth = NULL, defaultHeight = NULL,
## padding = NULL, fill = FALSE), knitr = list(defaultWidth = NULL,
## defaultHeight = NULL, figure = TRUE)), dependencies = NULL,
## elementId = NULL, preRenderHook = NULL, jsHooks = list()))
Echarts is actually of htmlwidgets class. So you can simply call htmlwidgets::saveWidget
function to save the object as HTML.
Refer to renderEchart
function to use recharts
for Shiny.
library(recharts)
library(shiny)
app = shinyApp(
ui = fluidPage(eChartOutput('myChart')),
server = function(input, output) {
chart = echartr(data.frame(x = rnorm(100), y = rnorm(100)), x, y)
output$myChart = renderEChart(chart)
}
)
if (interactive()) print(app)
Normally we do not want R users to specify a long list of options like that. As R users, you are more familiar with (and often work with) data structures like data frames, matrices, tables, and so on. Ideally we hope you can just pass a familiar data object, and we configure ECharts automatically for you whenever possible. We will be happy to know your feedback, and you are welcome to contribute code through Github pull requests.