diff --git a/.Rbuildignore b/.Rbuildignore index 2daf97d..6cd37f3 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -1,25 +1,24 @@ ^CRAN-RELEASE$ +^CRAN-SUBMISSION$ ^cran-comments\.md$ +cran-comments.md ^_pkgdown\.yml$ +pkgdown ^docs$ ^.*\.Rproj$ ^\.Rproj\.user$ -cran-comments.md +^\.\.Rcheck$ ^LICENSE\.md$ ^LICENSE ^data-raw$ .travis.yml .vs -pkgdown -vignettes ^\.github$ ^\.vscode$ README.md -^CODE_OF_CONDUCT\.md$ ^README\.Rmd$ +^CODE_OF_CONDUCT\.md$ ^man/figs$ ^\.ccache$ ^tic\.R$ ^codecov\.yml$ -^CRAN-SUBMISSION$ -^\.\.Rcheck$ diff --git a/.gitignore b/.gitignore index 1f09db2..b0ebbcb 100644 --- a/.gitignore +++ b/.gitignore @@ -10,5 +10,6 @@ inst/doc .DS_Store *.Rmd CRAN-RELEASE +CRAN-SUBMISSION cran-comments.md docs/ diff --git a/CRAN-SUBMISSION b/CRAN-SUBMISSION index edb79ba..683c7f5 100644 --- a/CRAN-SUBMISSION +++ b/CRAN-SUBMISSION @@ -1,3 +1,3 @@ -Version: 1.6.0 -Date: 2023-09-20 20:01:03 UTC -SHA: 8731596004c5c6ed3e9fe684ad5dd83e672baac2 +Version: 1.6.2 +Date: 2023-10-15 21:13:46 UTC +SHA: 207e816b3c071b3593cc9bc322ac4e2bea38084f diff --git a/DESCRIPTION b/DESCRIPTION index c137145..86914a0 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: echarty Title: Minimal R/Shiny Interface to JavaScript Library 'ECharts' -Date: 2023-10-05 -Version: 1.6.0.01 +Date: 2023-10-20 +Version: 1.6.2.01 Author: Larry Helgason, with initial code from John Coene's library echarts4r Maintainer: Larry Helgason Description: Deliver the full functionality of 'ECharts' with minimal overhead. 'echarty' users build R lists for 'ECharts' API. Lean set of powerful commands. diff --git a/NEWS.md b/NEWS.md index 75d5256..5d49106 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,11 +1,17 @@ # history of package _echarty_ -## v.1.6.0.01 latest, in development +## v.1.6.2.01 latest, in development +- make crosstalk work with improved ec.clmn +- add _ecStat_ to built-in plugins + +## v.1.6.2 on CRAN + +- allow axis rename (fix) - _ec.data_ grouped boxplots: outliers are custom series - _ec.clmn_ expanded usage of column names -## v.1.6.0 CRAN +## v.1.6.0 - _ec.paxis_ could be chained now - _ec.data_ format='boxplot' with optional outliers diff --git a/R/echarty.R b/R/echarty.R index 673aa4e..5a2a7e7 100644 --- a/R/echarty.R +++ b/R/echarty.R @@ -71,6 +71,7 @@ the$.ecv.colnames <- NULL #' * leaflet - Leaflet maps with customizable tiles, see \href{https://github.com/gnijuohz/echarts-leaflet#readme}{source}\cr #' * world - world map with country boundaries, see \href{https://github.com/apache/echarts/tree/master/test/data/map/js}{source} \cr #' * lottie - support for \href{https://lottiefiles.com}{lotties} \cr +#' * ecStat - statistical tools, see\href{https://github.com/ecomfe/echarts-stat}{echarts-stat}\cr #' * custom - renderers for [ecr.band] and [ecr.ebars] \cr #' Plugins with one-time installation: \cr #' * 3D - 3D charts and WebGL acceleration, see \href{https://github.com/ecomfe/echarts-gl}{source} and \href{https://echarts.apache.org/en/option-gl.html#series}{docs} \cr @@ -97,7 +98,7 @@ the$.ecv.colnames <- NULL #' tooltip= list(show= TRUE), #' series.param= list( #' symbolSize= ec.clmn(4, scale=7), -#' tooltip= list(formatter= ec.clmn('Petal.Width: %@', 4)) +#' tooltip= list(formatter= ec.clmn('Petal.Width: %@', 'Petal.Width')) #' ) #' ) #' @@ -109,6 +110,24 @@ ec.init <- function( df= NULL, preset= TRUE, ctype= 'scatter', ..., series.param= NULL, tl.series= NULL, width= NULL, height= NULL) { + key <- group <- deps <- dfKey <- NULL; isCrosstalk <- FALSE + if (requireNamespace("crosstalk", quietly= TRUE)) { + if (crosstalk::is.SharedData(df)) { + isCrosstalk <- TRUE + key <- as.list(df$key()) + group <- df$groupName() + deps <- crosstalk::crosstalkLibs() + dfKey <- df$key() + df <- df$origData() + } + } + + if (!is.null(df)) { + stopifnot('ec.init: df must be a data.frame'= inherits(df, 'data.frame')) + .setColnm(colnames(df)) + } + #else .setColnm() # do not reset, ec.data could've done it + opts <- list(...) # treacherous R does "partial matching of argument names" (like a bug): # if 'series.param' is before ... and 'series' is added, the latter is ignored! @@ -119,12 +138,12 @@ ec.init <- function( df= NULL, preset= TRUE, ctype= 'scatter', ..., locale <- if (is.null(opts$locale)) 'EN' else toupper(opts$locale) useDirtyRect <- if (is.null(opts$useDirtyRect)) FALSE else opts$useDirtyRect xtKey <- if (is.null(opts$xtKey)) 'XkeyX' else opts$xtKey + if (xtKey=='XkeyX') df$XkeyX <- dfKey # add new column for Xtalk filtering, if needed # remove the above attributes since they are not valid ECharts options opts$ask <- opts$js <- opts$renderer <- opts$locale <- NULL opts$useDirtyRect <- opts$elementId <- opts$xtKey <- NULL noAxis <- c('radar','parallel','map','gauge','pie','funnel','polar', #'graph', 'sunburst','tree','treemap','sankey') - .setColnm() doType <- function(idx, axx) { # get one axis type & name @@ -170,8 +189,19 @@ ec.init <- function( df= NULL, preset= TRUE, ctype= 'scatter', ..., if (is.character(ss$encode$y)) tmp$y <<- c(tmp$y, ss$encode$y[1]) } }) - if (!is.null(tmp$x)) x$opts$xAxis$name <<- trimws(paste(unique(tmp$x), collapse=',')) - if (!is.null(tmp$y)) x$opts$yAxis$name <<- trimws(paste(unique(tmp$y), collapse=',')) + + if (!is.null(tmp$x)) { + if (is.null(x$opts$xAxis$name)) + x$opts$xAxis$name <<- trimws(paste(unique(tmp$x), collapse=',')) + tt <- tmp$x[1] + colX <<- if (is.numeric(tt)) tt else which(colnames(df)==tt)[1] + } + if (!is.null(tmp$y)) { + if (is.null(x$opts$yAxis$name)) + x$opts$yAxis$name <<- trimws(paste(unique(tmp$y), collapse=',')) + tt <- tmp$y[1] + colY <<- if (is.numeric(tt)) tt else which(colnames(df)==tt)[1] + } } xyNamesCS <- function(ser) { # no coordinateSystem = pie,funnel,gauge, sunburst/tree/treemap/sankey (graph) @@ -193,51 +223,6 @@ ec.init <- function( df= NULL, preset= TRUE, ctype= 'scatter', ..., return(list(x=xtem, y=ytem, c=ser$coordinateSystem)) } - # presets are default settings, user can ignore or replace them - if (preset) { - namop <- names(opts) - # list(show=TRUE) or list(list()) is to create an empty object{} in JS - if (!'xAxis' %in% namop) - opts$xAxis <- list(show=TRUE) - if (!'yAxis' %in% namop) - opts$yAxis <- list(show=TRUE) - if (!any(c('series','options') %in% namop)) { - #if (!'world' %in% opts$load) # world will add its own default serie - opts$series <- list(list(type=if (is.null(ctype)) 'scatter' else ctype) ) - } - - if ('series' %in% names(opts)) { - if (is.null(opts$series[[1]]$type)) # set default to user serie if omitted - opts$series[[1]]$type <- if (is.null(ctype)) 'scatter' else ctype - if (opts$series[[1]]$type %in% noAxis) - opts$xAxis <- opts$yAxis <- NULL - } - else if (!is.null(ctype) && (ctype %in% noAxis)) - opts$xAxis <- opts$yAxis <- NULL - if ('polar' %in% namop) { - opts$xAxis <- opts$yAxis <- NULL - if (is.null(opts$polar$radius)) opts$polar$radius = 111 - if (is.null(opts$radiusAxis)) opts$radiusAxis= list(type= 'category') - if (is.null(opts$angleAxis)) opts$angleAxis= list(doit=TRUE) - if (!is.null(series.param)) - series.param = .merlis(series.param, list(coordinateSystem= "polar")) - } - } - - key <- group <- deps <- NULL; isCrosstalk <- FALSE - if (requireNamespace("crosstalk", quietly= TRUE)) { - if (crosstalk::is.SharedData(df)) { - isCrosstalk <- TRUE - key <- as.list(df$key()) - group <- df$groupName() - deps <- crosstalk::crosstalkLibs() - tmp <- df$key() - df <- df$origData() - if (xtKey=='XkeyX') - df$XkeyX <- tmp # add new column for Xtalk filtering, if needed - } - } - # forward widget options using x x <- list( theme = '', @@ -252,15 +237,12 @@ ec.init <- function( df= NULL, preset= TRUE, ctype= 'scatter', ..., crosstalk_group = group ) ) + + # ------------- data.frame ------------------- colX <- 1 # by default 1st column is X, 2nd is Y, 3rd is Z colY <- 2 - - # ------------- data.frame ------------------- if (!is.null(df)) { # if data.frame given, assign to dataset regardless of parameter 'preset' - stopifnot('ec.init: df must be a data.frame'= inherits(df, 'data.frame')) - # add var for ec.clmn - .setColnm(colnames(df)) # skip default group settings on map timeline if (!is.null(tl.series) && paste0(tl.series$type,'')=='map') ctype <- NULL @@ -284,9 +266,8 @@ ec.init <- function( df= NULL, preset= TRUE, ctype= 'scatter', ..., legd$data <- append(legd$data, list(list(name=as.character(nm)))) } if (preset) { - if (is.null(tl.series) && is.null(x$opts$options)) + #if (is.null(tl.series) && is.null(x$opts$options)) x$opts$series <- sers - #if (is.null(x$opts$legend)) overwrite simple legend=(show=T) x$opts$legend <- legd } x$opts$dataset <- append(x$opts$dataset, txfm) @@ -295,7 +276,7 @@ ec.init <- function( df= NULL, preset= TRUE, ctype= 'scatter', ..., x$opts$dataset <- list(list(source = ec.data(df, header=TRUE))) if (preset) { - # grouping by any column, group columns do not become X or Y axis + # group by any column, group columns do not become X or Y axis if (!is.null(grnm)) { # find pos of grp column pos <- which(colnames(df)==grnm) if (!is.null(tl.series) && !is.null(tl.series$groupBy)) @@ -336,10 +317,39 @@ ec.init <- function( df= NULL, preset= TRUE, ctype= 'scatter', ..., } } # colX,colY, visualMap } - + + # presets are default settings, user can ignore or replace them + if (preset) { + namop <- names(x$opts) + # list(show=TRUE) or list(list()) is to create an empty object{} in JS + if (!'xAxis' %in% namop) + x$opts$xAxis <- list(show=TRUE) + if (!'yAxis' %in% namop) + x$opts$yAxis <- list(show=TRUE) + if (!any(c('series','options') %in% namop)) + x$opts$series <- list(list(type=if (is.null(ctype)) 'scatter' else ctype) ) + + if ('series' %in% names(x$opts)) { + if (is.null(x$opts$series[[1]]$type)) # set default to user serie if omitted + x$opts$series[[1]]$type <- if (is.null(ctype)) 'scatter' else ctype + if (x$opts$series[[1]]$type %in% noAxis) + x$opts$xAxis <- x$opts$yAxis <- NULL + } + else if (!is.null(ctype) && (ctype %in% noAxis)) + x$opts$xAxis <- x$opts$yAxis <- NULL + if ('polar' %in% namop) { + x$opts$xAxis <- x$opts$yAxis <- NULL + if (is.null(x$opts$polar$radius)) x$opts$polar$radius = 111 + if (is.null(x$opts$radiusAxis)) x$opts$radiusAxis= list(type= 'category') + if (is.null(x$opts$angleAxis)) x$opts$angleAxis= list(doit=TRUE) + if (!is.null(series.param)) + series.param = .merlis(series.param, list(coordinateSystem= "polar")) + } + } + if (!is.null(x$opts$series) && !is.null(series.param)) { x$opts$series <- .merlis(x$opts$series, series.param) - # TODO: not 'x','y' + # TODO: when names not 'x','y' tmp <- series.param$encode if (!is.null(tmp)) { if (is.numeric(tmp$x)) colX <- tmp$x @@ -352,10 +362,10 @@ ec.init <- function( df= NULL, preset= TRUE, ctype= 'scatter', ..., if (preset) { # TODO: set axis type from series.data # set X,Y axes type & name - x$opts$xAxis <- doType(colX, x$opts$xAxis) - x$opts$yAxis <- doType(colY, x$opts$yAxis) axNamesEnc(x$opts$series) axNamesEnc(list(tl.series)) + x$opts$xAxis <- doType(colX, x$opts$xAxis) + x$opts$yAxis <- doType(colY, x$opts$yAxis) if (!is.null(x$opts$series)) { if (!is.null(x$opts$series[[1]]$type)) { @@ -480,6 +490,12 @@ ec.init <- function( df= NULL, preset= TRUE, ctype= 'scatter', ..., src = c(file = path), script= 'lottie-parser.js') wt$dependencies <- append(wt$dependencies, list(dep)) } + if ('ecStat' %in% load) { + dep <- htmltools::htmlDependency( + name = 'ecStat', version = '1.0.0', + src = c(file = path), script= 'ecStat.min.js') + wt$dependencies <- append(wt$dependencies, list(dep)) + } # Plugins implemented as dynamic load on-demand cdn <- 'https://cdn.jsdelivr.net/npm/' @@ -516,7 +532,7 @@ ec.init <- function( df= NULL, preset= TRUE, ctype= 'scatter', ..., paste0(cdn,'echarts-wordcloud@2.0.0/dist/echarts-wordcloud.min.js'), ask) # load unknown plugins - unk <- load[! load %in% c('leaflet','custom','world','lottie', + unk <- load[! load %in% c('leaflet','custom','world','lottie','ecStat', '3D','liquid','gmodular','wordcloud')] if (length(unk)>0) { for(pg in unk) @@ -713,7 +729,7 @@ ec.upd <- function(wt, ...) { #' @details #' \itemize{ #' \item type='stack': two _stacked_ lines are drawn, one with customizable areaStyle. The upper boundary coordinates are values added on top of the lower boundary coordinates.\cr -#' _xAxis_ is required to be of type 'category'. +#' _xAxis_ is required to be type 'category'. #' \item type='polygon': coordinates of the two boundaries are chained into a polygon and displayed as one. Tooltips do not show upper band values. #' } #' Optional parameter _name_, if given, will show up in legend. Legend will merge all series with the same name into one item. @@ -1189,23 +1205,6 @@ ec.plugjs <- function(wt=NULL, source=NULL, ask=FALSE) { invisible(old) } -if (interactive()) { - if (requireNamespace("shiny", quietly= TRUE)) { - - # for Shiny actions - .onAttach <- function(libname, pkgname) { - shiny::registerInputHandler('echartyParse', function(data, ...) { - jsonlite::fromJSON(jsonlite::toJSON(data, auto_unbox = TRUE)) - }, force = TRUE) - } - - .onLoad <- function(libname, pkgname) { - shiny::registerInputHandler('echartyParse', function(data, ...) { - jsonlite::fromJSON(jsonlite::toJSON(data, auto_unbox = TRUE)) - }, force = TRUE) - } - } -} # ------------- Global Options ----------------- #' #' For info on options and prefixes, see [-- Introduction --]. diff --git a/R/examples.R b/R/examples.R index 3b56676..33e759f 100644 --- a/R/examples.R +++ b/R/examples.R @@ -245,22 +245,36 @@ #' dats <- as.data.frame(EuStockMarkets) |> mutate(day= 1:n()) |> #' # first column ('day') becomes X-axis by default #' dplyr::relocate(day) |> slice_head(n= 100) -#' +#' #' # 1. with unnamed data -#' ec.init(load= 'custom', -#' legend= list(show= TRUE), -#' dataZoom= list(type= 'slider', end= 50), -#' series = append( -#' ecr.band(dats, 'DAX','FTSE', name= 'Ftse-Dax', color= 'lemonchiffon'), -#' list(list(type= 'line', name= 'CAC', color= 'red', symbolSize= 1, -#' data= ec.data(dats |> select(day,CAC), 'values') -#' )) -#' ) +#' bands <- ecr.band(dats, 'DAX','FTSE', name= 'Ftse-Dax', +#' areaStyle= list(color='pink')) +#' ec.init(load= 'custom', +#' tooltip= list(trigger= 'axis'), +#' legend= list(show= TRUE), xAxis= list(type= 'category'), +#' dataZoom= list(type= 'slider', end= 50), +#' series = append( bands, +#' list(list(type= 'line', name= 'CAC', color= 'red', symbolSize= 1, +#' data= ec.data(dats |> select(day,CAC), 'values') +#' )) +#' ) #' ) #' #' # 2. with a dataset #' # dats |> ec.init(load= 'custom', ... #' # + replace data=... with encode= list(x='day', y='CAC') +#' +#' +#' #------ Error Bars on grouped data +#' df <- mtcars |> group_by(cyl,gear) |> summarise(yy= round(mean(mpg),2)) |> +#' mutate(low= round(yy-cyl*runif(1),2), +#' high= round(yy+cyl*runif(1),2)) +#' df |> ec.init(load='custom', ctype='bar', +#' xAxis= list(type='category'), tooltip= list(show=TRUE)) |> +#' ecr.ebars( # name = 'eb', # cannot have own name in grouped series +#' encode= list(x='gear', y=c('yy','low','high')), +#' tooltip = list(formatter=ec.clmn('high %@
low %@', 'high','low'))) +#' #' #' #------ Timeline animation and use of ec.upd for readability #' Orange |> group_by(age) |> ec.init( @@ -317,15 +331,18 @@ #' ) #' #' -#' #------ ECharts feature: custom transform - a regression line +#' #------ ecStat plugin: dataset transform to regression line #' # presets for xAxis,yAxis,dataset and series are used #' data.frame(x= 1:10, y= sample(1:100,10)) |> -#' ec.init(js= 'echarts.registerTransform(ecStat.transform.regression)') |> -#' ec.upd({ -#' dataset[[2]] <- list(transform = list(type= 'ecStat:regression')) -#' series[[2]] <- list( -#' type= 'line', itemStyle=list(color= 'red'), datasetIndex= 1) -#' }) +#' ec.init(load= 'ecStat', +#' js= c('echarts.registerTransform(ecStat.transform.regression)','','')) |> +#' ec.upd({ +#' dataset[[2]] <- list( +#' transform= list(type= 'ecStat:regression', +#' config= list(method= 'polynomial', order= 3))) +#' series[[2]] <- list( +#' type= 'line', itemStyle=list(color= 'red'), datasetIndex= 1) +#' }) #' #' #' #------ ECharts: dataset, transform and sort @@ -389,18 +406,6 @@ #' label= list(rotate='radial') )) #' ) #' -#' -#' #------ Error Bars on grouped data -#' if (interactive()) { -#' df <- mtcars |> group_by(cyl,gear) |> summarise(yy= round(mean(mpg),2)) |> -#' mutate(low= round(yy-cyl*runif(1),2), high= round(yy+cyl*runif(1),2)) |> -#' dplyr::relocate(cyl, .after= last_col()) # move group column as last -#' df |> ec.init(ctype='bar', load='custom', -#' xAxis= list(type='category'), tooltip= list(show=TRUE)) |> -#' ecr.ebars(df, name = 'eb', -#' tooltip = list(formatter=ec.clmn('high %@
low %@', 4,3))) -#' } -#' #' #------ Gauge #' ec.init(preset= FALSE, #' series= list(list( diff --git a/README.md b/README.md index 4ac6c20..b852068 100644 --- a/README.md +++ b/README.md @@ -19,12 +19,11 @@ downloads](https://cranlogs.r-pkg.org/badges/last-day/echarty)](https://cranlogs This package is a thin R wrapper around Javascript library [ECharts](https://echarts.apache.org/en/index.html). -One major command uses R lists to enclose the entire [ECharts API](https://echarts.apache.org/en/option.html). -Users can benefit from ECharts **full functionality** to build +**One** major command(_ec.init_) uses R lists to support the [ECharts API](https://echarts.apache.org/en/option.html). +Benefit from ECharts **full functionality** and build interactive charts in R and Shiny with minimal overhead. -Wider connectivity and deployment potential through [crosstalk -support](https://helgasoft.github.io/echarty/xtalk.html). +Wider connectivity and deployment potential through [crosstalk](https://rpubs.com/echarty/crosstalk).
Compare to echarts4r @@ -36,8 +35,8 @@ test coverage | ![32%](https://coveralls.io/repos/github/JohnCoene/echarts4r/bad lines of code | 1,171,938 [![link](man/figs/external-link-16.png)](https://api.codetabs.com/v1/loc/?github=JohnCoene/echarts4r)| 5,061 [![link](man/figs/external-link-16.png)](https://api.codetabs.com/v1/loc?github=helgasoft/echarty) API design (1)| own commands with parameters | mostly [ECharts option](https://echarts.apache.org/en/option.html) lists number of commands | over [200](https://echarts4r.john-coene.com/reference/) | **one** command + optional utilities -data storage support | series data | **datasets**, series data -crosstalk support | no | **yes** +data storage support | series data | **[datasets](https://echarts.apache.org/en/option.html#dataset)**, series data +[crosstalk](https://rstudio.github.io/crosstalk/) support | no | **yes** utilities | bezier, correlations, histogram, density, loess, flip, nesting, more | extended boxplots, tabsets, layouts, shapefiles, lotties, more This review done Sept 2023 for echarts4R v.0.4.5 and echarty v.1.5.4.03. @@ -45,11 +44,13 @@ This review done Sept 2023 for echarts4R v.0.4.5 and echarty v.1.5.4.03. (1) We encourage users to follow the original ECharts documentation to construct charts with echarty. This differs from echarts4r which uses own commands for most chart options.
+
+Please consider granting a Github star ⭐ to show your support. ## Installation -Latest development build 1.6.0.01 +Latest development build 1.6.2.01 ``` r if (!requireNamespace('remotes')) install.packages('remotes') @@ -83,7 +84,7 @@ iris |> group_by(Species) |> ec.init( timeline= list(autoPlay= TRUE), tl.series= list( - symbolSize= ec.clmn(4, scale=4), + symbolSize= ec.clmn('Petal.Width', scale= 3), encode= list(y= c('Sepal.Width', 'Petal.Length')), markLine= list(data= list(list(type='max'), list(type='min'))) ) @@ -100,7 +101,7 @@ The [**WEBSITE**](https://helgasoft.github.io/echarty) has a gallery with code a
The package has plenty of [**code examples**](https://github.com/helgasoft/echarty/blob/main/R/examples.R) included. Type -**?ec.examples** in the RStudio Console, then copy/paste any code from Help to +**?ec.examples**, then copy/paste any code to see the result. Now you can start building [**beautiful diff --git a/inst/js/dataTool.min.js b/inst/js/dataTool.min.js deleted file mode 100644 index 73776c5..0000000 --- a/inst/js/dataTool.min.js +++ /dev/null @@ -1,22 +0,0 @@ - -/* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -*/ - - -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("echarts")):"function"==typeof define&&define.amd?define(["exports","echarts"],t):t((e=e||self).dataTool={},e.echarts)}(this,function(e,t){"use strict";var r=Array.prototype,i=r.slice,l=r.map,o=function(){}.constructor,r=o?o.prototype:null;function a(e,t,r){if(!e)return[];if(!t)return function(e){for(var t=[],r=1;r mutate(day= 1:n()) |> # first column ('day') becomes X-axis by default dplyr::relocate(day) |> slice_head(n= 100) - + # 1. with unnamed data -ec.init(load= 'custom', - legend= list(show= TRUE), - dataZoom= list(type= 'slider', end= 50), - series = append( - ecr.band(dats, 'DAX','FTSE', name= 'Ftse-Dax', color= 'lemonchiffon'), - list(list(type= 'line', name= 'CAC', color= 'red', symbolSize= 1, - data= ec.data(dats |> select(day,CAC), 'values') - )) - ) +bands <- ecr.band(dats, 'DAX','FTSE', name= 'Ftse-Dax', + areaStyle= list(color='pink')) +ec.init(load= 'custom', + tooltip= list(trigger= 'axis'), + legend= list(show= TRUE), xAxis= list(type= 'category'), + dataZoom= list(type= 'slider', end= 50), + series = append( bands, + list(list(type= 'line', name= 'CAC', color= 'red', symbolSize= 1, + data= ec.data(dats |> select(day,CAC), 'values') + )) + ) ) # 2. with a dataset # dats |> ec.init(load= 'custom', ... # + replace data=... with encode= list(x='day', y='CAC') + +#------ Error Bars on grouped data +df <- mtcars |> group_by(cyl,gear) |> summarise(yy= round(mean(mpg),2)) |> + mutate(low= round(yy-cyl*runif(1),2), + high= round(yy+cyl*runif(1),2)) +df |> ec.init(load='custom', ctype='bar', + xAxis= list(type='category'), tooltip= list(show=TRUE)) |> + ecr.ebars( # name = 'eb', # cannot have own name in grouped series + encode= list(x='gear', y=c('yy','low','high')), + tooltip = list(formatter=ec.clmn('high \%@
low \%@', 'high','low'))) + + #------ Timeline animation and use of ec.upd for readability Orange |> group_by(age) |> ec.init( xAxis= list(type= 'category', name= 'tree'), @@ -321,15 +335,18 @@ ec.init( ) -#------ ECharts feature: custom transform - a regression line +#------ ecStat plugin: dataset transform to regression line # presets for xAxis,yAxis,dataset and series are used data.frame(x= 1:10, y= sample(1:100,10)) |> - ec.init(js= 'echarts.registerTransform(ecStat.transform.regression)') |> - ec.upd({ - dataset[[2]] <- list(transform = list(type= 'ecStat:regression')) - series[[2]] <- list( - type= 'line', itemStyle=list(color= 'red'), datasetIndex= 1) - }) +ec.init(load= 'ecStat', + js= c('echarts.registerTransform(ecStat.transform.regression)','','')) |> +ec.upd({ + dataset[[2]] <- list( + transform= list(type= 'ecStat:regression', + config= list(method= 'polynomial', order= 3))) + series[[2]] <- list( + type= 'line', itemStyle=list(color= 'red'), datasetIndex= 1) +}) #------ ECharts: dataset, transform and sort @@ -393,18 +410,6 @@ ec.init( preset= FALSE, label= list(rotate='radial') )) ) - -#------ Error Bars on grouped data -if (interactive()) { -df <- mtcars |> group_by(cyl,gear) |> summarise(yy= round(mean(mpg),2)) |> - mutate(low= round(yy-cyl*runif(1),2), high= round(yy+cyl*runif(1),2)) |> - dplyr::relocate(cyl, .after= last_col()) # move group column as last -df |> ec.init(ctype='bar', load='custom', - xAxis= list(type='category'), tooltip= list(show=TRUE)) |> - ecr.ebars(df, name = 'eb', - tooltip = list(formatter=ec.clmn('high \%@
low \%@', 4,3))) -} - #------ Gauge ec.init(preset= FALSE, series= list(list( diff --git a/man/ec.init.Rd b/man/ec.init.Rd index 103dca3..851c3f0 100644 --- a/man/ec.init.Rd +++ b/man/ec.init.Rd @@ -87,6 +87,7 @@ Numerical indexes for series,visualMap,etc. are R-counted (1,2...)\cr \item leaflet - Leaflet maps with customizable tiles, see \href{https://github.com/gnijuohz/echarts-leaflet#readme}{source}\cr \item world - world map with country boundaries, see \href{https://github.com/apache/echarts/tree/master/test/data/map/js}{source} \cr \item lottie - support for \href{https://lottiefiles.com}{lotties} \cr +\item ecStat - statistical tools, see\href{https://github.com/ecomfe/echarts-stat}{echarts-stat}\cr \item custom - renderers for \link{ecr.band} and \link{ecr.ebars} \cr Plugins with one-time installation: \cr \item 3D - 3D charts and WebGL acceleration, see \href{https://github.com/ecomfe/echarts-gl}{source} and \href{https://echarts.apache.org/en/option-gl.html#series}{docs} \cr @@ -111,7 +112,7 @@ ec.init( # init with presets tooltip= list(show= TRUE), series.param= list( symbolSize= ec.clmn(4, scale=7), - tooltip= list(formatter= ec.clmn('Petal.Width: \%@', 4)) + tooltip= list(formatter= ec.clmn('Petal.Width: \%@', 'Petal.Width')) ) ) diff --git a/man/ecr.band.Rd b/man/ecr.band.Rd index 56785da..24be786 100644 --- a/man/ecr.band.Rd +++ b/man/ecr.band.Rd @@ -30,7 +30,7 @@ A 'custom' serie with lower and upper boundaries \details{ \itemize{ \item type='stack': two \emph{stacked} lines are drawn, one with customizable areaStyle. The upper boundary coordinates are values added on top of the lower boundary coordinates.\cr -\emph{xAxis} is required to be of type 'category'. +\emph{xAxis} is required to be type 'category'. \item type='polygon': coordinates of the two boundaries are chained into a polygon and displayed as one. Tooltips do not show upper band values. } Optional parameter \emph{name}, if given, will show up in legend. Legend will merge all series with the same name into one item. diff --git a/tests/testthat/test-ec.clmn.R b/tests/testthat/test-ec.clmn.R index c6e6b1a..d5c8faf 100644 --- a/tests/testthat/test-ec.clmn.R +++ b/tests/testthat/test-ec.clmn.R @@ -1,4 +1,5 @@ library(dplyr) + test_that("ec.clmn with sprintf, column indexes and names", { # dataset + column indexes diff --git a/tests/testthat/test-other.R b/tests/testthat/test-other.R index fe8c61b..a944371 100644 --- a/tests/testthat/test-other.R +++ b/tests/testthat/test-other.R @@ -262,9 +262,10 @@ test_that('stops are working in echarty.R', { expect_error(ecr.ebars(ec.init(), 1)) expect_error(ecr.ebars(ec.init(), cars)) expect_silent(ecr.ebars(ec.init(load='custom'), cars, encode=list(x=1,y=c(2,3,4)))) - expect_silent(ec.init(load='liquid')) - expect_silent(ec.init(load='gmodular')) - expect_silent(ec.init(load='wordcloud')) expect_silent(ec.init(load='lottie')) + expect_silent(ec.init(load='ecStat')) + #expect_silent(ec.init(load='liquid')) # Debian throws warnings in CRAN check + #expect_silent(ec.init(load='gmodular')) + #expect_silent(ec.init(load='wordcloud')) }) diff --git a/tests/testthat/test-presets.R b/tests/testthat/test-presets.R index b185739..b011545 100644 --- a/tests/testthat/test-presets.R +++ b/tests/testthat/test-presets.R @@ -36,9 +36,9 @@ test_that("ec.init presets for non-grouped data.frame", { }) test_that("ec.init presets for grouped data.frame", { - p <- df |> dplyr::group_by(symbol) |> ec.init(yAxis= list(scale=TRUE)) + p <- df |> dplyr::group_by(symbol) |> ec.init(yAxis= list(scale=TRUE, name='yaxe')) expect_equal(p$x$opts$xAxis$type, 'category') - expect_true(!is.null(p$x$opts$yAxis)) + expect_equal(p$x$opts$yAxis$name, 'yaxe') expect_equal(length(p$x$opts$dataset[[1]]$source), 11) expect_equal(length(p$x$opts$legend$data), 3) expect_equal(p$x$opts$series[[1]]$type, 'scatter') @@ -49,21 +49,23 @@ test_that("ec.init presets for grouped data.frame", { test_that("ec.init presets for timeline", { dftl <- data.frame( year = unlist(lapply(2018:2021, function(x) {rep(x, 4)})), - quarter = rep(1:4, 4), + quarter = as.factor(rep(1:4, 4)), value = runif(16) ) barTL <- function(data, timeline_var, x_var, bar_var) { bt <- data |> dplyr::group_by(!!dplyr::sym(timeline_var)) |> - ec.init(tl.series = list(type='bar', encode=list(x=x_var, y=bar_var))) + ec.init(tl.series = list(type='bar', encode=list(x=x_var, y=bar_var)), + xAxis= list(name='xval')) bt } - p <- barTL(dftl, timeline_var= "year", bar_var= "quarter", x_var= "value") + p <- barTL(dftl, timeline_var= "year", x_var= "value", bar_var= "quarter") o <- p$x$opts expect_equal(length(o$dataset[[1]]$source), 17) expect_equal(length(o$dataset), 5) expect_equal(length(o$options), 4) expect_equal(o$options[[4]]$title$text, '2021') expect_equal(o$yAxis$name, 'quarter') + expect_equal(o$xAxis$name, 'xval') }) test_that("ec.init presets for timeline groupBy", { @@ -77,7 +79,7 @@ test_that("ec.init presets for timeline groupBy", { ) p <- dat |> group_by(x1) |> ec.init( tl.series= list(encode= list(x= 'x3', y= 'x5'), - symbolSize= ec.clmn(2, scale=30), + symbolSize= ec.clmn('x4', scale=30), groupBy= 'x2') ) p$x$opts$legend <- list(show=TRUE)