1010lenv <- new.env(parent = emptyenv())
1111lenv $ coNames <- ' '
1212# assign('aa', 11, envir=.ecv.colnames); get('aa', envir=.ecv.colnames)
13- noAxisXY <- c(' radar' ,' parallel' ,' themeRiver' ,' map' ,' gauge' ,' pie' ,' funnel' ,' polar' ,
13+ noAxisXY <- c(' radar' ,' parallel' ,' themeRiver' ,' map' ,' gauge' ,' pie' ,' funnel' ,' polar' ,' chord ' ,
1414 ' sunburst' ,' tree' ,' treemap' ,' sankey' ,' lines' , ' liquidFill' ,' wordCloud' ) # series
1515noCoord <- c(' polar' ,' radar' ,' singleAxis' ,' parallelAxis' ,' calendar' )
1616# using list(show=TRUE) or list(list()) is to create empty object{} in JS
@@ -24,11 +24,10 @@ noCoord <- c('polar','radar','singleAxis','parallelAxis','calendar')
2424# ' Best practice is to have the grouping column placed last. Grouping column cannot be used as axis.\cr
2525# ' Timeline requires a _grouped data.frame_ to build its \href{https://echarts.apache.org/en/option.html#options}{options}.\cr
2626# ' If grouping is on multiple columns, only the first one is used to determine settings.
27- # ' REM @param ctype Chart type, default is 'scatter'. Could be set in _series.param_ instead.
2827# ' @param preset Boolean (default TRUE). Build preset attributes like dataset, series, xAxis, yAxis, etc.\cr
2928# ' When preset is FALSE, these attributes need to be set explicitly.\cr
3029# ' @param series.param Additional attributes for single preset series, default is NULL.\cr
31- # ' Defines a **single** series for both non-timeline and timeline charts. \cr
30+ # ' Defines a **single** series for both non-timeline and timeline charts. Default type is 'scatter'. \cr
3231# ' **Multiple** series need to be defined directly with _series=list(list(type=...),list(type=...))_ or added with [ec.upd].
3332# ' @param tl.series Deprecated, use _timeline_ and _series.param_ instead.\cr
3433# ' @param ... Optional widget attributes. See Details. \cr
@@ -153,7 +152,7 @@ ec.init <- function( df= NULL, preset= TRUE, ..., #ctype= 'scatter',
153152 opt1 <- list (... )
154153 lenv $ coNames <- ' '
155154 # treacherous R does "partial matching of argument names" (like a bug):
156- # if 'series.param' is before ... and 'series' is added, the latter is ignored!
155+ # if 'series.param' is before ' ...' and 'series' is added, the latter is ignored!
157156 elementId <- opt1 $ elementId ; js <- opt1 $ js
158157 ask <- if (is.null(opt1 $ ask )) FALSE else opt1 $ ask
159158 ctype <- if (is.null(opt1 $ ctype )) ' scatter' else opt1 $ ctype
@@ -277,7 +276,6 @@ ec.init <- function( df= NULL, preset= TRUE, ..., #ctype= 'scatter',
277276 if (! is.null(df )) {
278277 stopifnot(' ec.init: df should be data.frame or SharedData' =
279278 inherits(df , c(" SharedData" , " data.frame" )))
280- lenv $ coNames <- colnames(df ) # must execute before first ec.clmn
281279
282280 ct.key <- ct.group <- ct.dfKey <- NULL
283281 if (requireNamespace(" crosstalk" , quietly = TRUE )) {
@@ -295,6 +293,11 @@ ec.init <- function( df= NULL, preset= TRUE, ..., #ctype= 'scatter',
295293 crosstalk_key = ct.key ,
296294 crosstalk_group = ct.group
297295 )
296+ stopifnot(' ec.init: df is empty' = length(colnames(df )) > 0 )
297+ # silently auto-add extra column for some charts and for colX/colY
298+ if (length(colnames(df )) == 1 && ! is.grouped_df(df ))
299+ df <- df | > mutate(duplicate = 1 : nrow(df ))
300+ lenv $ coNames <- colnames(df ) # must execute before first ec.clmn
298301 # if data.frame given, build dataset regardless of 'preset' or 'dataset'
299302
300303 # column-to-style with encode, replaces dataset column names, then creates series.data
@@ -315,8 +318,8 @@ ec.init <- function( df= NULL, preset= TRUE, ..., #ctype= 'scatter',
315318 df $ value <- list (list (rep(' ' , length(vv ))))
316319 for (i in 1 : nrow(df )) {
317320 tmp <- list ()
318- for (k in 1 : length (vv )) tmp <- c(tmp , unlist(df [i ,vv [k ]], use.names = F ))
319- df [i ,]$ value <- list (tmp ) # list(list(unlist(df[i,vv[1]], use.names=F), unlist(df[i,vv[2]], use.names=F)))
321+ for (k in seq_along (vv )) tmp <- c(tmp , unlist(df [i ,vv [k ]], use.names = F ))
322+ df [i ,]$ value <- list (tmp )
320323 }
321324 # TODO: remove vv columns from df or not?
322325 sedval <- series.param $ encode $ data $ value # save for axes
@@ -487,7 +490,7 @@ ec.init <- function( df= NULL, preset= TRUE, ..., #ctype= 'scatter',
487490 if (! is.null(series.param )) {
488491 x $ opts $ series <- .merlis(x $ opts $ series , series.param )
489492 }
490- axad <- 1 ;
493+ axad <- 1 ; isSname <- FALSE
491494 x $ opts $ series <- lapply(x $ opts $ series , function (ss ) {
492495 tmp <- xyNamesCS(ss )
493496 if (! is.null(tmp $ c )) ss $ coordinateSystem <- tmp $ c
@@ -505,6 +508,7 @@ ec.init <- function( df= NULL, preset= TRUE, ..., #ctype= 'scatter',
505508 }
506509 # else don't overwrite user's encode
507510 }
511+ if (! is.null(ss $ name )) isSname <<- TRUE
508512
509513 # renderItem helper only for our custom functions ri*
510514 # new ECharts custom series, like segmentedDoughnut, want a character string
@@ -518,6 +522,7 @@ ec.init <- function( df= NULL, preset= TRUE, ..., #ctype= 'scatter',
518522 if (! ' yAxis' %in% namop ) x $ opts $ yAxis <- list (show = TRUE )
519523 }
520524 if (dbg ) cat(' \n axad=' ,axad )
525+ if ((! ' legend' %in% namop ) && isSname ) cat(" \n Note: Some series have names, could add legend with 'legend= list(show=T)'" )
521526
522527 # reading from encode set above # TODO: when names not 'x','y' ?
523528 tmp <- series.param $ encode
@@ -620,7 +625,7 @@ ec.init <- function( df= NULL, preset= TRUE, ..., #ctype= 'scatter',
620625
621626 if (dbg ) cat(' \n colp=' ,unlist(colp ),' ctyp=' ,unlist(ctyp ))
622627 } # end isAxes
623-
628+
624629 } # end preset
625630
626631 x $ opts <- .renumber(x $ opts )
@@ -810,9 +815,10 @@ ec.init <- function( df= NULL, preset= TRUE, ..., #ctype= 'scatter',
810815 nops <- names(opt1 ) # add defaults 3D
811816 for (x in c(' xAxis3D' ,' yAxis3D' ,' zAxis3D' ,' grid3D' )) {
812817 a2d <- sub(' 3D' ,' ' ,x )
813- if (! (x %in% nops ))
818+ if (! (x %in% nops )) {
814819 wt $ x $ opts [[x ]] <- if (! is.null(wt $ x $ opts [[a2d ]])) wt $ x $ opts [[a2d ]]
815820 else list (show = TRUE )
821+ }
816822 }
817823 }
818824 wt $ x $ opts $ xAxis <- wt $ x $ opts $ yAxis <- NULL
@@ -870,7 +876,7 @@ ec.init <- function( df= NULL, preset= TRUE, ..., #ctype= 'scatter',
870876 tmp <- xyNamesCS(tl.series )
871877 xtem <- tmp $ x ; ytem <- tmp $ y
872878 if (! is.null(tmp $ c )) tl.series $ coordinateSystem <- tmp $ c
873- if (dbg ) cat(' \n timeline: x=' ,xtem ,' y=' ,ytem ,' cs=' ,tmp $ c )
879+ if (dbg ) cat(' \n timeline: x=' ,xtem ,' y=' ,ytem ,' cs=' ,tmp $ c , ' encode= ' ,unlist( tl.series $ encode ) )
874880
875881 if (any(c(' geo' ,' leaflet' ) %in% tl.series $ coordinateSystem )) {
876882 klo <- ' lng' ; kla <- ' lat'
@@ -940,7 +946,7 @@ ec.init <- function( df= NULL, preset= TRUE, ..., #ctype= 'scatter',
940946 # define additional filter transforms and option series based on groupBy
941947 dsf <- optm <- list () # new filters and options
942948 filterIdx <- 0
943- for (ii in 1 : length (unlist(unique(df [[grnm ]]))) ) { # unlist(unique(
949+ for (ii in seq_along (unlist(unique(df [[grnm ]]))) ) { # unlist(unique(
944950 snames <- c()
945951 for (x2 in unlist(unique(df [tgrpBy ]), use.names = FALSE ) ) {
946952 dst <- opt1 $ dataset [[ii + 1 ]] # skip source-dataset 1st
@@ -997,7 +1003,7 @@ ec.init <- function( df= NULL, preset= TRUE, ..., #ctype= 'scatter',
9971003# ' mutate(lwr= y-runif(30, 1, 3), upr= y+runif(30, 2, 4))
9981004# ' band.df <- df |> group_by(cat) |> group_split()
9991005# ' sband <- list()
1000- # ' for(ii in 1:length (band.df)) # build all bands
1006+ # ' for(ii in seq_along (band.df)) # build all bands
10011007# ' sband <- append(sband,
10021008# ' ecr.band(band.df[[ii]], 'lwr', 'upr', type='stack', smooth=FALSE,
10031009# ' name= unique(band.df[[ii]]$cat), areaStyle= list(color=c('blue','green','yellow')[ii]))
@@ -1434,7 +1440,8 @@ ec.plugjs <- function(wt=NULL, source=NULL, ask=FALSE) {
14341440
14351441 if (ask == ' loadRemote' && startsWith(source , ' http' )) {
14361442 name <- regmatches(source , regexpr(" custom-series/(.*?)/dist" , source , perl = TRUE ))
1437- name <- gsub(" custom-series/|/dist" , " " , name )
1443+ if (length(name )> 0 ) name <- gsub(" custom-series/|/dist" , " " , name )
1444+ else name <- fname
14381445 dep <- htmltools :: htmlDependency(
14391446 name = name , version = ' 1.1.1' ,
14401447 src = list (href = dirname(source )), script = fname
@@ -1479,54 +1486,47 @@ ec.plugjs <- function(wt=NULL, source=NULL, ask=FALSE) {
14791486
14801487# convert from R to JS numbering
14811488.renumber <- function (opa ) {
1482- doEncode <- function (el ) {
1483- for (i in 1 : length(el $ encode )) {
1489+ decro <- function (x , params ) { # decrement all elements of x
1490+ for (el in params ) {
1491+ if (! is.null(x [[el ]])) {
1492+ stopifnot(' Some index is not numeric' = is.numeric(x [[el ]]))
1493+ x [[el ]] <- x [[el ]] - 1
1494+ }
1495+ }
1496+ x
1497+ }
1498+ doEncode <- function (el ) { # for tooltip, seriesName, itemId, itemName, itemGroupId, itemChildGroupId
1499+ for (i in seq_along(el $ encode )) {
14841500 if (! is.numeric(el $ encode [[i ]])) next
14851501 el $ encode [[i ]] <- el $ encode [[i ]] - 1
14861502 }
14871503 el
14881504 }
1489- r2jsEncode <- function (ss ) {
1490-
1505+ r2js <- function (ss ) {
14911506 if (any(names(ss )== ' encode' ) && length(ss $ encode )> 0 ) ss <- doEncode(ss )
1492-
1493- # if (!is.null(ss$type) && !ss$type %in% noAxisXY) {
1494- if (! is.null(ss $ xAxisIndex )) ss $ xAxisIndex <- ss $ xAxisIndex - 1
1495- if (! is.null(ss $ yAxisIndex )) ss $ yAxisIndex <- ss $ yAxisIndex - 1
1496- # }
1497- if (! is.null(ss $ datasetIndex )) ss $ datasetIndex <- ss $ datasetIndex - 1
1498- if (! is.null(ss $ geoIndex )) ss $ geoIndex <- ss $ geoIndex - 1
1499- if (! is.null(ss $ polarIndex )) ss $ polarIndex <- ss $ polarIndex - 1
1500- if (! is.null(ss $ calendarIndex )) ss $ calendarIndex <- ss $ calendarIndex - 1
1501- if (! is.null(ss $ radarIndex )) ss $ radarIndex <- ss $ radarIndex - 1
1502- ss
1507+ decro(ss , c(' xAxisIndex' ,' yAxisIndex' ,' singleAxisIndex' ,' datasetIndex' ,' geoIndex' ,' polarIndex' ,' calendarIndex' ,' radarIndex' ))
15031508 }
15041509
1505- if (! is.null(opa $ series )) opa $ series <- lapply(opa $ series , r2jsEncode )
1510+ if (! is.null(opa $ series )) opa $ series <- lapply(opa $ series , r2js )
15061511 if (! is.null(opa $ dataZoom )) {
1507- if (all(sapply(opa $ dataZoom , is.list ))) opa $ dataZoom <- lapply(opa $ dataZoom , r2jsEncode )
1508- else opa $ dataZoom <- r2jsEncode (opa $ dataZoom )
1512+ if (all(sapply(opa $ dataZoom , is.list ))) opa $ dataZoom <- lapply(opa $ dataZoom , r2js )
1513+ else opa $ dataZoom <- r2js (opa $ dataZoom )
15091514 }
15101515
1511- decro <- function (x ) {
1512- if (! is.null(x $ dimension ) && is.numeric(x $ dimension )) x $ dimension <- x $ dimension - 1
1513- if (! is.null(x $ seriesIndex )) x $ seriesIndex <- x $ seriesIndex - 1 # vMap
1514- if (! is.null(x $ gridIndex )) x $ gridIndex <- x $ gridIndex - 1 # x/y Axis
1515- x
1516- }
15171516 decType <- \(typ ) { # handle single or multiple items
1518- item <- opa [[typ ]]
1517+ item <- opa [[typ ]]; pars <- c( ' gridIndex ' , ' calendarIndex ' , ' dimension ' , ' seriesIndex ' , ' categories ' )
15191518 if (! is.null(item )) {
15201519 if (all(sapply(item , is.list )))
1521- opa [[typ ]] <<- lapply(item , decro )
1522- else
1523- opa [[typ ]] <<- decro(item )
1520+ opa [[typ ]] <<- lapply(item , decro , pars ) # ...
1521+ else # last 3 are vMap
1522+ opa [[typ ]] <<- decro(item , pars )
15241523 }
15251524 }
15261525 decType(' xAxis' )
15271526 decType(' yAxis' )
15281527 decType(' visualMap' )
1529- opa
1528+ # some top elements may have matrixIndex
1529+ opa <- lapply(opa , \(xx ) { if (any(names(xx )== ' matrixIndex' )) xx $ matrixIndex <- xx $ matrixIndex - 1 ; xx })
15301530}
15311531
15321532# merge named lists: list OR list.of.lists like series
0 commit comments