Skip to content

Commit

Permalink
build 02
Browse files Browse the repository at this point in the history
  • Loading branch information
helgasoft committed Dec 20, 2023
1 parent 390bcca commit a8c6eeb
Show file tree
Hide file tree
Showing 14 changed files with 181 additions and 92 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ CRAN-RELEASE
CRAN-SUBMISSION
cran-comments.md
docs/
cleanup.bat
4 changes: 2 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Package: echarty
Title: Minimal R/Shiny Interface to JavaScript Library 'ECharts'
Date: 2023-12-14
Version: 1.6.2.01
Date: 2023-12-19
Version: 1.6.2.02
Author: Larry Helgason, with initial code from John Coene's library echarts4r
Maintainer: Larry Helgason <[email protected]>
Description: Deliver the full functionality of 'ECharts' with minimal overhead. 'echarty' users build R lists for 'ECharts' API. Lean set of powerful commands.
Expand Down
12 changes: 9 additions & 3 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
# history of package _echarty_

## v.1.6.2.01 latest, in development
## v.1.6.2.02 latest, in development

- make crosstalk work with improved ec.clmn
- added coder.R demo
- correct gridIndex numbering for xAxis/yAxis
- deprecate _tl.series_, replace with _timeline_ and _series.param_

## v.1.6.2.01

- make crosstalk work with improved _ec.clmn_
- add _ecStat_ to built-in plugins
- removed _dataTool.min.js_ from dependencies (yaml)
- dataset,geo,polar,etc. indexes in series now with R-counting
- built with R v.4.3.2
- add default _coordinateSystem_ for 3D charts
- fix _datasetIndex_ for timeline 3D series
- add _encode_ default, improve _ec.init_ docs
- _tl.series_ type 'map': add support 'dimension' for visualMap and fix 'legend' bug
- _tl.series_ type 'map': add support 'dimension' for visualMap, fix 'legend' & 'title' bugs
- removed width/height from 'tabset', handled by _ec.init_
- _ecr.band_ replaced default type from 'stack' to 'polygon'

Expand Down
136 changes: 81 additions & 55 deletions R/echarty.R
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ the <- new.env(parent = emptyenv())
the$.ecv.colnames <- NULL
noAxis <- c('radar','parallel','themeRiver','map','gauge','pie','funnel','polar',
'sunburst','tree','treemap','sankey','lines')
noCoord <- c('polar','radar','singleAxis','parallelAxis')
noCoord <- c('polar','radar','singleAxis','parallelAxis','calendar')
# using list(show=TRUE) or list(list()) is to create empty object{} in JS

#' Initialize command
Expand All @@ -30,17 +30,11 @@ noCoord <- c('polar','radar','singleAxis','parallelAxis')
#' @param ctype Chart type, default is 'scatter'.
#' @param preset Boolean (default TRUE). Build preset attributes like dataset, series, xAxis, yAxis, etc.
#' @param series.param Additional attributes for preset series, default is NULL.\cr
#' This parameter is for regular (non-timeline) series only.\cr
#' One can also define the complete series with _series= list(list(...),...)_.
#' @param tl.series List defines \href{https://echarts.apache.org/en/option.html#series}{options series} for timeline.\cr
#' Default is NULL. Similar to _series.param_ but for timeline series.\cr
#' A grouped _df_ must be present, each group providing data for one options series.
#' Timeline \href{https://echarts.apache.org/en/option.html#timeline.data}{data} and \href{https://echarts.apache.org/en/option.html#options}{options} will be preset for the chart.\cr
#' Another preset is _encode(x=1,y=2,z=3)_, which are the first 3 columns of _df_. Parameter _z_ is ignored in 2D. See Details below.\cr
#' Optional attribute _groupBy_, a _df_ column name, can create series groups inside each timeline option.\cr
#' _tl.series_ cannot be used for hierarchical charts like graph,tree,treemap,sankey. Chart options/timeline have to be built directly, see \href{https://helgasoft.github.io/echarty/uc4.html}{example}.
#' Can be used for non-timeline and timeline series (instead of _tl.series_). A single list defines one series type only.\cr
#' One could also define all series directly with _series=list(list(...),list...)_ instead.
#' @param tl.series Deprecated, use _timeline_ and _series.param_ instead.\cr
#' @param ... Optional widget attributes. See Details. \cr
#' @param width,height A valid CSS unit (like \code{'100\%'},
#' @param width,height Optional valid CSS unit (like \code{'100\%'},
#' \code{'500px'}, \code{'auto'}) or a number, which will be coerced to a
#' string and have \code{'px'} appended.
#'
Expand Down Expand Up @@ -87,6 +81,14 @@ noCoord <- c('polar','radar','singleAxis','parallelAxis')
#' Optional parameter _xtKey_: unique ID column name of data frame _df_. Must be same as _key_ parameter used in _SharedData$new()_. If missing, a new column _XkeyX_ will be appended to df.\cr
#' Enabling _crosstalk_ will also generate an additional dataset called _Xtalk_ and bind the **first series** to it.\cr
#'
#' **Timeline**:\cr
#' Defined by _series.param_ for the \href{https://echarts.apache.org/en/option.html#series}{options series} and a _timeline_ list for the \href{https://echarts.apache.org/en/option.html#timeline}{actual control}.
#' A grouped _df_ is required, each group providing data for one option serie.
#' Timeline \href{https://echarts.apache.org/en/option.html#timeline.data}{data} and \href{https://echarts.apache.org/en/option.html#options}{options} will be preset for the chart.\cr
#' Another preset is _encode(x=1,y=2,z=3)_, which are the first 3 columns of _df_. Parameter _z_ is ignored in 2D. See Details below.\cr
#' Optional attribute _groupBy_, a _df_ column name, can create series groups inside each timeline option.\cr
#' Timeline cannot be used for hierarchical charts like graph,tree,treemap,sankey. Chart options/timeline have to be built directly, see \href{https://helgasoft.github.io/echarty/uc4.html}{example}.
#'
#' **\href{https://echarts.apache.org/en/option.html#series-line.encode}{Encode}** \cr
#' A series attribute to define which columns to use for the axes, depending on chart type and coordinate system: \cr
#' * set _x_ and _y_ for coordinateSystem _cartesian2d_
Expand All @@ -112,6 +114,11 @@ noCoord <- c('polar','radar','singleAxis','parallelAxis')
#' )
#' )
#'
#' data.frame(n=1:5) |> dplyr::group_by(n) |> ec.init(
#' timeline= list(show=TRUE, autoPlay=TRUE),
#' series.param= list(type='gauge', max=5)
#' )
#'
#' @importFrom htmlwidgets createWidget sizingPolicy getDependency JS shinyWidgetOutput shinyRenderWidget
#' @import dplyr
#'
Expand Down Expand Up @@ -246,6 +253,8 @@ ec.init <- function( df= NULL, preset= TRUE, ctype= 'scatter', ...,
}
if (!is.null(opt1$geo) && ser$type %in% c('scatter','scatterGL','lines'))
ser$coordinateSystem <- 'geo'
if (!is.null(opt1$calendar) && ser$type %in% c('heatmap','scatter','effectScatter'))
ser$coordinateSystem <- 'calendar'
if (!is.null(opt1$leaflet)) ser$coordinateSystem <- 'leaflet'
#if (!is.null(opt1$radar)) series?$type <- 'radar'
if (ser$type == 'parallel') {
Expand Down Expand Up @@ -308,9 +317,6 @@ ec.init <- function( df= NULL, preset= TRUE, ctype= 'scatter', ...,
grnm <- NULL
if (!is.null(df)) {
# if data.frame given, build dataset regardless of 'preset' or 'dataset'

# skip default group settings on map timeline
#if (!is.null(tl.series) && paste0(tl.series$type,'')=='map') ctype <- NULL

# grouping uses transform
if (!is.null(ctype) && dplyr::is.grouped_df(df)) {
Expand Down Expand Up @@ -350,7 +356,15 @@ ec.init <- function( df= NULL, preset= TRUE, ctype= 'scatter', ...,
allp <- replace(allp, pos, FALSE)
colX <- which(allp==TRUE)[1] # first two==TRUE are X,Y
colY <- which(allp==TRUE)[2]
stopifnot('ec.init: df must have at least 3 columns when grouping by one'= !is.na(colY))
if (is.na(colY)) colY <- length(colnames(df))
# if (is.na(colY))
# # map data can have only 2 columns and group by one of them
# if (ctype=='map' ||
# (!is.null(tl.series) && tl.series$type=='map') ||
# (!is.null(series.param) && series.param$type=='map'))
# colY <- 2
#
# stopifnot('ec.init: df must have at least 3 columns when grouping by one'= !is.na(colY))
}

tmp <- doVMap(x)
Expand All @@ -366,11 +380,12 @@ ec.init <- function( df= NULL, preset= TRUE, ctype= 'scatter', ...,
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 (!any(c('series','options') %in% namop) && !is.null(ctype))
x$opts$series <- list(list(type= ctype))

if (!is.null(ctype)) {
if (!any(c('series','options') %in% namop))
x$opts$series <- list(list(type= ctype))
if (!is.null(tl.series) && is.null(tl.series$type))
tl.series$type <- ctype
}
if ('series' %in% names(x$opts)) {
# set default to user serie if omitted
if (is.null(x$opts$series[[1]]$type) && !is.null(ctype))
Expand Down Expand Up @@ -609,8 +624,12 @@ ec.init <- function( df= NULL, preset= TRUE, ctype= 'scatter', ...,


# ------------- timeline -----------------
if (is.null(tl.series)) return(wt)
if (is.null(tl.series) && is.null(opt1$timeline)) return(wt)
# timeline is evaluated last
if (is.null(tl.series) &&
!is.null(opt1$timeline) &&
!is.null(series.param))
tl.series <- series.param

if (is.null(df) || !is.grouped_df(df))
stop('ec.init: tl.series requires a grouped data.frame df')
Expand Down Expand Up @@ -659,7 +678,7 @@ ec.init <- function( df= NULL, preset= TRUE, ctype= 'scatter', ...,
# replace only source, transforms stay
wt$x$opts$dataset[[1]] <- list(source= ec.data(df, header=TRUE))
}
stopifnot("tl.series: bad second parameter name for encode"= !is.null(unlist(tl.series$encode[ytem])))
stopifnot("timeline: bad second parameter name for encode"= !is.null(unlist(tl.series$encode[ytem])))

# dataset is already in, now loop group column(s)
#gvar <- df |> group_vars() |> first() |> as.character() # convert if factor
Expand Down Expand Up @@ -688,7 +707,7 @@ ec.init <- function( df= NULL, preset= TRUE, ctype= 'scatter', ...,
wt$x$opts$options <- .merlis(optl, wt$x$opts$options)

if (!is.null(tl.series$groupBy)) {
stopifnot('ec.init: tl.series groupBy column missing in df'= tl.series$groupBy %in% colnames(df))
stopifnot('ec.init: timeline `groupBy` column missing in df'= tl.series$groupBy %in% colnames(df))
#gvar <- df |> group_vars() |> first() |> as.character() # convert if factor
tgrp <- tl.series$groupBy
# define additional filter transformations and option series based on groupBy
Expand Down Expand Up @@ -783,10 +802,11 @@ ec.upd <- function(wt, ...) {
#'
#' @details
#' \itemize{
#' \item type='polygon': coordinates of the two boundaries are chained into one polygon. Tooltips do not show upper band values.
#' \item type='polygon': coordinates of the two boundaries are chained into one polygon. Tooltips do not show upper band values.\cr
#' _xAxis type_ could be 'category' or 'value'.\cr
#' Set fill color with attribute _color_.\cr
#' \item type='stack': two _stacked_ lines are drawn, the lower with customizable areaStyle.\cr
#' _xAxis_ should be type 'category'! Tooltips could include upper band values.\cr
#' _xAxis type_ should be 'category'! Tooltips could include upper band values.\cr
#' Set fill color with attribute _areaStyle$color_.\cr
#' }
#' Optional parameter _name_, if given, will show up in legend. Legend merges all series with same name into one item.
Expand Down Expand Up @@ -1205,44 +1225,50 @@ ec.plugjs <- function(wt=NULL, source=NULL, ask=FALSE) {
# wt
# }

.r2jsEncode <- function(ss) {
# convert from R to JS numbering
.renumber <- function(opa) {

if (any(names(ss)=='encode')) {
for(i in 1:length(ss$encode)) {
if (!is.numeric(ss$encode[[i]])) next
ss$encode[[i]] <- ss$encode[[i]] -1
r2jsEncode <- function(ss) {

if (any(names(ss)=='encode')) {
for(i in 1:length(ss$encode)) {
if (!is.numeric(ss$encode[[i]])) next
ss$encode[[i]] <- ss$encode[[i]] -1
}
}
if (!ss$type %in% noAxis) {
if (!is.null(ss$xAxisIndex)) ss$xAxisIndex <- ss$xAxisIndex -1
if (!is.null(ss$yAxisIndex)) ss$yAxisIndex <- ss$yAxisIndex -1
}
if (!is.null(ss$datasetIndex)) ss$datasetIndex <- ss$datasetIndex -1
if (!is.null(ss$geoIndex)) ss$geoIndex <- ss$geoIndex -1
if (!is.null(ss$polarIndex)) ss$polarIndex <- ss$polarIndex -1
if (!is.null(ss$calendarIndex)) ss$calendarIndex <- ss$calendarIndex -1
if (!is.null(ss$radarIndex)) ss$radarIndex <- ss$radarIndex -1
ss
}
if (!ss$type %in% noAxis) {
if (!is.null(ss$xAxisIndex)) ss$xAxisIndex <- ss$xAxisIndex -1
if (!is.null(ss$yAxisIndex)) ss$yAxisIndex <- ss$yAxisIndex -1
}
if (!is.null(ss$datasetIndex)) ss$datasetIndex <- ss$datasetIndex -1
if (!is.null(ss$geoIndex)) ss$geoIndex <- ss$geoIndex -1
if (!is.null(ss$polarIndex)) ss$polarIndex <- ss$polarIndex -1
if (!is.null(ss$calendarIndex)) ss$calendarIndex <- ss$calendarIndex -1
if (!is.null(ss$radarIndex)) ss$radarIndex <- ss$radarIndex -1
ss
}

# convert from R to JS numbering
.renumber <- function(opa) {

if (!is.null(opa$series))
opa$series <- lapply(opa$series, .r2jsEncode)
opa$series <- lapply(opa$series, r2jsEncode)

tmp <- opa$visualMap
if (!is.null(tmp)) {
decVmap <- function(x) {
if (!is.null(x$dimension) && is.numeric(x$dimension)) x$dimension <- x$dimension -1
if (!is.null(x$seriesIndex)) x$seriesIndex <- x$seriesIndex -1
x
decr <- function(x) {
if (!is.null(x$dimension) && is.numeric(x$dimension)) x$dimension <- x$dimension -1
if (!is.null(x$seriesIndex)) x$seriesIndex <- x$seriesIndex -1 # vMap
if (!is.null(x$gridIndex)) x$gridIndex <- x$gridIndex -1 # x/y Axis
x
}
decType <- \(typ) { # handle single or multiple items
item <- opa[[typ]]
if (!is.null(item)) {
if (all(sapply(item, is.list)))
opa[[typ]] <<- lapply(item, decr)
else
opa[[typ]] <<- decr(item)
}
if (all(sapply(tmp, is.list)))
opa$visualMap <- lapply(tmp, decVmap)
else
opa$visualMap <- decVmap(tmp)
}
decType('xAxis')
decType('yAxis')
decType('visualMap')
opa
}

Expand Down
3 changes: 2 additions & 1 deletion R/util.R
Original file line number Diff line number Diff line change
Expand Up @@ -566,7 +566,7 @@ body { padding: 10px; }
#' Additional grouping is supported on a column after the second. Groups will show in the legend, if enabled.\cr
#' Returns a `list(dataset, series, xAxis, yAxis)` to set params in [ec.init].
#' Make sure there is enough data for computation, 4+ values per boxplot.\cr
#' `format='treeTT'` expects data.frame _df_ columns _pathString,value,(optional itemStyle)_ for \link[data.tree]{FromDataFrameTable}.\cr
#' `format='treeTT'` expects data.frame _df_ columns _pathString,value,(optional itemStyle)_ for \link[data.tree]{FromDataFrameTable}.\cr
#' It will add column 'pct' with value percentage for each node. See Details.
#' @seealso some live \href{https://rpubs.com/echarty/data-models}{code samples}
#'
Expand Down Expand Up @@ -898,6 +898,7 @@ ec.data <- function(df, format='dataset', header=FALSE, ...) {
#' * \emph{%R@} rounded number, like '12345'.\cr
#' * \emph{%R2@} rounded number, two digits after decimal point.\cr
#' * \emph{%M@} marker in serie's color.\cr
#' Notice that tooltip _formatter_ will work for _trigger='item'_, but not for _trigger='axis'_ when there are multiple value sets.
#'
#' @examples
#' tmp <- data.frame(Species = as.vector(unique(iris$Species)),
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ Please consider granting a Github star ⭐ to show your support.
## Installation

<!-- [![Github version](https://img.shields.io/github/v/release/helgasoft/echarty?label=github)](https://github.com/helgasoft/echarty/releases) <sup>.02</sup> -->
Latest development build <strong>1.6.2.01</strong>
Latest development build <strong>1.6.2.02</strong>

``` r
if (!requireNamespace('remotes')) install.packages('remotes')
Expand Down
1 change: 1 addition & 0 deletions demo/00Index
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
eshiny echarty and Shiny integration showcase
js2r Translation assistant - ECharty javaScript to R
coder Edit and plot charts with R code scaffolding
9 changes: 9 additions & 0 deletions demo/coder.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#' Learn from echarty examples
#' Additional information is available by clicking the "Info" button inside.
#' From RStudio run 'demo(coder)' after loading package 'echarty'

devAskNewPage(ask = FALSE)
if (interactive()) {
library(shiny)
shiny::runGist('https://gist.github.com/helgasoft/02b257429e78e138f87aefce14f7aebc')
}
1 change: 1 addition & 0 deletions man/ec.clmn.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 17 additions & 10 deletions man/ec.init.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit a8c6eeb

Please sign in to comment.