Skip to content

Instantly share code, notes, and snippets.

@helgasoft
Last active January 23, 2024 22:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save helgasoft/02b257429e78e138f87aefce14f7aebc to your computer and use it in GitHub Desktop.
Save helgasoft/02b257429e78e138f87aefce14f7aebc to your computer and use it in GitHub Desktop.
Coding Helper for echarty
#'----------- echarty coding helper ------------
#' Please report bugs and ask questions in https://github.com/helgasoft/echarty/issues
#' run in RStudio with command demo(coder), or demo(coder, package='echarty')
stopifnot('session non-interactive'= interactive())
library(shiny)
library(shinyjs)
library(shinybusy)
library(dplyr)
library(echarty)
library(rclipboard) # for clipboard Copy button
suppressWarnings(rm(js, envir=.GlobalEnv)) # clear to avoid conflict with shinyjs
# ----- vars ---------------------
jsCode <- "shinyjs.collect_content = function() {
var text_area = document.getElementById('txt4js');
var text = text_area.value.trim();
if (text=='') return;
//console.log(text);
var out= LZString.compressToBase64(text)
.replace(/\\+/g, '-') // Convert '+' to '-'
.replace(/\\//g, '_') // Convert '/' to '_'
.replace(/=+$/, ''); // Remove ending '='
out = 'https://echarts.apache.org/examples/en/editor.html?src=echarty&code=' + out;
console.log(out);
Shiny.setInputValue('jsLinkOut', out);
}"
bar <- "mtcars |> relocate(hp) |> group_by(cyl) |> ec.init(
series.param= list(type='bar', barMinWidth=3) )"
line2d <- "# set multiple series in 'series' OR add with 'ec.upd()'
df <- state.x77 |> as.data.frame() |> tibble::rownames_to_column('State') |> relocate(State) |> head()
df |> ec.init(legend= list(list()), tooltip= list(trigger='axis'),
yAxis= list( list(name='Income'),
list(name='Population', position='right') ),
series.param= list(type='line', name='Income', areaStyle= list(list()), encode= list(y='Income') )
) |> ec.upd({
series <- append(series,
list(list(type= 'line', name= 'Population', encode= list(y='Population'), yAxisIndex=1)) )
})"
scatGL <- "ggplot2::diamonds |> select(price, carat, cut) |> group_by(cut) |> filter(row_number()<5000) |>
ec.init(load='3D', ctype='scatterGL', dataZoom= list(type='inside'),
series.param= list(progressiveThreshold=3000, large=T))" # |> ec.theme('dark-mushroom')
picbar <- "treeDataURI <- 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAA2CAYAAADUOvnEAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA5tJREFUeNrcWE1oE0EUnp0kbWyUpCiNYEpCFSpIMdpLRTD15s2ePHixnj00N4/GoyfTg2fbiwdvvagHC1UQ66GQUIQKKgn1UAqSSFua38b3prPJZDs7s5ufKn0w7CaZ2W/fe9/73kyMRqNB3Nrj1zdn4RJ6du9T2u1a2iHYSxjP4d41oOHGQwAIwSUHIyh8/RA8XeiXh0kLGFoaXiTecw/hoTG4ZCSAaFkY0+BpsZceLtiAoV2FkepZSDk5EpppczBvpuuQCqx0YnkYcVVoqQYMyeCG+lFdaGkXeVOFNu4aEBalOBk6sbQrQF7gSdK5JXjuHXuYVIVyr0TZ0FjKDeCs6km7JYMUdrWAUVmZUBtmRnVPK+x6nIR2xomH06R35ggwJPeofWphr/W5UjPIxq8B2bKgE8C4HVHWvg+2gZjXj19PkdFztY7bk9TDCH/g6oafDPpaoMvZIRI5WyMB/0Hv++HkpTKE0kM+A+h20cPAfN4GuRyp9G+LMTW+z8rCLI8b46XO9zRcYZTde/j0AZm8WGb3Y2F9KLlE2nqYkjFLJAsDOl/lea0q55mqxXcL7YBc++bsCPMe8mUyU2ZIpnCoblca6TZA/ga2Co8PGg7UGUlEDd0ueptglbrRZLLE7poti6pCaWUo2pu1oaYI1CF9b9cCZPO3F8ikJQ/rPpQT5YETht26ss+uCIL2Y8vHwJGpA96GI5mjOlaKhowUy6BcNcgIhDviTGWCGFaqEuufWz4pgcbCh+w0gEOyOjTlTtYYlIWPYWKEsLDzOs+nhzaO1KEpd+MXpOoTUgKiNyhdy5aSMPNVqxtSsJFgza5EWA4zKtCJ2OGbLn0JSLu8+SL4G86p1Fpr7ABXdGFF/UTD4rfmFYFw4G9VAJ9SM3aF8l3yok4/J6IV9sDVb36ynmtJ2M5+CwxTYBdKNMBaocKGV2nYgkz6r+cHBP30MzAfi4Sy+BebSoPIOi8PW1PpCCvr/KOD4k9Zu0WSH0Y0+SxJ2awp/nlwKtcGyHOJ8vNHtRJzhPlsHr8MogtlVtwUU0tSM1x58upSKbfJnSKUR07GVMKkDNfXpzpv0RTHy3nZMVx5IOWdZIaPabGFvfpwpjnvfmJHXLaEvZUTseu/TeLc+xgAPhEAb/PbjO6PBaOTf6LQRh/dERde23zxLtOXbaKNhfq2L/1fAOPHDUhOpIf5485h7l+GNHHiSYPKE3Myz9sFxoJuAyazvwIMAItferha5LTqAAAAAElFTkSuQmCC';
df <- Orange |> filter(Tree==4) |> mutate(size= circumference/167*100, Tree=NULL)
df |> ec.init(
series.param= series <- list(
type= 'pictorialBar',
symbol = paste0('image://',treeDataURI),
symbolSize= htmlwidgets::JS(ec.clmn('%@%', 'size'))
)
)"
gauge <- "ec.init(series= list(list(type='gauge', data= list(list(name='score',value=44)))))"
themeRiver <- "dd <- data.frame(
x = rep(1:3, each= 2),
value = c(0,1,2,3,2,1),
label = rep(c('d1', 'd2'), 3)
)
ec.init(series= list(list(type='themeRiver', data= ec.data(dd), label= list(list()) )) )"
boxplot <- "ds <- iris |> tidyr::pivot_longer(
cols = !any_of('Species'),
names_to = 'ttype',
values_to = 'result') |>
relocate(ttype,result) |> group_by(Species) |>
ec.data(format='boxplot')
ec.init(
dataset= ds$dataset,
series= ds$series,
yAxis= ds$yAxis, xAxis= ds$xAxis,
legend= list(show= TRUE)
) |> ec.theme('dark-mushroom')"
candlestick <- "df <- as.data.frame(EuStockMarkets) |> head(50) |> mutate(day=1:n())
ec.init(df, series.param= list(
type='candlestick', encode= list(x='day', y=c('CAC','SMI','FTSE','DAX')) )
)"
heatmap <- "# heatmap CS could be geo,2D or calendar. Here is geo:
longitude <- c(-116.7, -120.4, -116.7, -113.5, -115.5, -120.8, -119.5, -113.7, -113.7, -110.7)
latitude <- c(45.3, 42.6, 38.9, 42.1, 35.7, 38.9, 36.2, 39, 41.6, 36.9)
df <- as.data.frame(cbind(longitude, latitude, runif(10,1,10)))
ec.init(df, load='world',
geo= list(center=c(-116, 39), zoom=10, roam=TRUE),
series.param= list(
type= 'heatmap', #'scatter'
pointSize= 10, blurSize= 14, minOpacity= 0.7,
encode= list(lng=1, lat=2, value=3)
),
visualMap= list(top='top', dimension=3)
)"
sankeyData <- "nodedge <- data.frame(
name = c('a','b', 'c', 'd', 'e'),
value = c(5, 6, 2, 8, 13),
source = c('a', 'b', 'c', 'd', 'c'),
target = c('b', 'c', 'd', 'e', 'e')
)
data <- ec.data(nodedge,'names')\n"
sankey <- paste0(sankeyData,"ec.init(
series.param= list( type= 'sankey',
data= data,
edges= data )
)")
graph <- paste0("# graph CS could be view,2D,geo,polar or calendar. Here is 'view':\n",
sankeyData,"ec.init(
series.param= list(
type= 'graph', roam= TRUE, zoom= 4, coordinateSystem='view',
layout= 'force', # try 'circular' too
data= data,
edges= lapply(data, \\(x) { x$lineStyle <- list(width=x$value); x }),
emphasis= list(focus= 'adjacency'),
label= list(show=TRUE),
lineStyle= list(curveness= 0.3) ),
tooltip= list(show=T)
)")
tree <- "# tree,sunburst and treemap are for hierarchical data
# see dedicated website page for more info
hier <- data.frame(
parents = c('a', 'b', 'c', 'c', 'd'),
children = c('b', 'c', 'd', 'e', 'f'),
value = c(5, 6, 2, 8, 13)
)
data <- ec.data(hier, format='treePC') # helper for parents-children
ec.init(
series.param= list(type= 'tree', data= data, label= list(offset= c(0, -12)) )
)"
funnel <- "Orange |> filter(Tree==4) |> mutate(Tree=NULL) |>
ec.init(ctype='funnel', series.param= list(label=list(position='center')))"
gpre <- "geoJson <- jsonlite::read_json('https://echarts.apache.org/examples/data/asset/geo/USA.json')\np <- "
gpost <- "p$x$registerMap <- list(list(mapName= 'usa', geoJSON= geoJson))\np"
gson <- paste(gpre,"ec.init(geo= list(map= 'usa', roam= T),
series.param= list(type='scatter', data=list(c(-117,35,11), c(-99, 38,33))) )\n",gpost)
svg <- "svg <- 'https://echarts.apache.org/examples/data/asset/geo/Veins_Medical_Diagram_clip_art.svg' |>
readLines() |> paste0(collapse='')
p <- ec.init(geo= list(map= 'organs', roam= T),
series.param= list(type='scatter', data= list(c(99, 155), c(111, 111))) )
p$x$registerMap <- list(list(mapName= 'organs', svg= svg))
p$x$on <- list(list(event='click', handler= ec.clmn('(e) => {alert(\"clicked \"+e.name)}') )) \np"
world <- "cns <- data.frame(
country= c('Brazil','China','India'), val= c(33, 66, 99)
)
cns |> ec.init(load= 'world,3D',
series= list(
list(type='map'),
list(type='lines', lineStyle= list(width=4, opacity=1, curveness=0.8),
data= list(list(coords= list(c(-77,33),c(44,38)))) ),
list(type='scatterGL',
data= list(c(-77,33),c(44,38)), itemStyle=list(color='red'))
)
,visualMap= list(seriesIndex=1)
)"
leaflet= "ec.init(load='leaflet', leaflet= list(roam=TRUE, zoom=2),
series= list(
list( type='lines', data= list(list(c(77,53,'a'), c(44,23,55))) ),
list( type='scatter', data= list(c(77,53,'a'), c(44,23,55)) )
)
)"
scat3Dgeo= paste(gpre,"ec.init(load='3D', geo3D=list(map= 'usa', roam= T),
series.param= list(type= 'scatter3D',
data= list(c(-117,32,11), c(-88,38,22)) ,
symbolSize= 33, itemStyle= list(color= 'red')
)
)\n",gpost)
scat3Dcart= "ec.init(load= '3D',
series.param= list(type= 'scatter3D',
data=list(c(-117,32,11), c(44,2,22)),
symbolSize= 40, itemStyle= list(color= 'red')
)
)"
bar3Dgeo= sub('scatter3D','bar3D',scat3Dgeo)
bar3Dcart= sub('scatter3D','bar3D',scat3Dcart)
line3Dcart= sub('scatter3D','line3D',scat3Dcart)
tmp= sub("scatter3D'","lines3D', lineStyle=list(color='red', width=3, opacity=1)\n",scat3Dgeo)
tmp= sub("data= list","data= list(list",tmp)
lines3Dgeo= sub(",22)",",22))", tmp)
surface= "data <- expand.grid(
x = seq(0, 2, by = 0.1),
y = seq(0, 1, by = 0.1)
) |> mutate(z = x * (y ^ 2)) |> select(x,y,z)
ec.init(load= '3D', series.param= list(
type= 'surface', data= ec.data(data,'values')) )"
scatGlobe= "ec.init(load='3D',
globe= list(
baseTexture='https://cdn.jsdelivr.net/gh/ecomfe/echarts-gl@master/test/asset/world.topo.bathy.200401.jpg',
light= list(ambient= list(intensity=0.6)),
shading= 'realistic', viewControl= list(autoRotate=F)),
series.param= list(type= 'scatter3D',
data= list(c(111,55,5), c(-117,33,1), list(name='h2', value= c(-77,11,2))),
symbolSize= 40, itemStyle= list(color= 'red')
), tooltip= list(show=T)
)"
tmp= sub('scatter3D', 'bar3D', scatGlobe)
barGlobe= sub("33,1))","33,15))", tmp)
tmp= sub("bar3D'", "lines3D', lineStyle=list(color='red', width=3, opacity=1)", barGlobe)
tmp= sub("data= list","data= list(list",tmp)
tmp= sub("), list(name='h2', value=", ")), list(c(-117,33,1),", tmp, fixed=T)
linesGlobe= tmp
timeline <- "# The timeline concept represents multiple charts stored in a list called 'options'.
# Data for the 'options' in echarty is a grouped data.frame, each group is one option's data.
# Parameter 'series.param' defines common attributes for the charts. One could also code 'options' manually.
# List 'timeline' customizes the built-in UI control to switch from one chart to another.
mtcars |> group_by(cyl) |> ec.init(
timeline= list(autoPlay= TRUE), tooltip= list(show=T),
series.param= list(encode= list(x='hp', y='mpg'), type='effectScatter')
)"
morph <- "# Morphing is animated transition from one chart ot another. Both charts must have similar data and set attribute 'universalTransition'.
# Transitioning to/from aggregates is also possible, as shown here:
colors <- c('blue','red', 'green')
cyls <- as.character(sort(unique(mtcars$cyl)))
sers <- lapply(mtcars |> group_by(cyl) |> group_split(), \\(x) {
cyl <- as.character(unique(x$cyl))
list(type='scatter', id=cyl, dataGroupId=cyl, name= paste('cyl',cyl),
data= ec.data(x |> select(mpg,hp)), symbolSize= 22,
universalTransition= list(enabled= TRUE))
})
dbar <- ec.data(mtcars |> group_by(cyl) |> summarize(value= mean(hp)) |>
mutate(groupId= as.character(cyl)), 'names')
oscatter <- list(
title= list(subtext='click points to morph'), color= colors, legend=list(show=T),
xAxis= list(scale=TRUE, name='mpg'),
yAxis= list(scale=TRUE, name='hp'),
series= sers
)
obar <- list(
title= list(subtext= 'Average'), color= colors,
xAxis= list(type= 'category', data= paste0('cyl',cyls)),
yAxis= list(show= TRUE),
series= list(list(
type= 'bar', id= 'average', colorBy= 'data',
data= dbar,
universalTransition=list(enabled= TRUE, seriesKey= cyls)
))
)
p <- ec.util(cmd='morph', oscatter, obar)
p$x$on[[1]]$handler <- htmlwidgets::JS(p$x$on[[1]]$handler) # click rqrd
p"
# ---- UI ----------------------------------
ui <- fluidPage(
tags$head(
tags$style(HTML("
.ital { font-style: italic; }
.sml { font-size: smaller; }
label {float:left;}
#rbc-label {margin-right:15px}
#rbt-label {margin-right:15px}
#ero { background-color: lemonchiffon; color: red;
-webkit-user-select: all; user-select: all; }
#lzout {width: 100%; height: 160px; overflow: scroll; }
#info {float: right;}
#doPlot {float: right; margin=left:15px;}
.floc30 {position: fixed; left: 30%; font-size: 16px;}
.floc60 {position: fixed; left: 60%;}
.form-group { margin-bottom: 8px;}
"))
,includeScript('https://cdn.jsdelivr.net/npm/lz-string@1.5.0/libs/lz-string.min.js')
),
useShinyjs(),
extendShinyjs(text= jsCode, functions= 'collect_content'),
rclipboardSetup(),
br(),
fluidRow(
column(11, span(
a(img(src='https://helgasoft.github.io/echarty/img/logo.png', width=40),
href='https://github.com/helgasoft/echarty','echarty')," Coder", class='floc30'),
actionButton("info", label=img(src ="https://img.icons8.com/metro/2x/info.png",
alt='Help', width='30'), inline=T) )
),
fluidRow(
column(12, div( #style = "height:20px;background-color: yellow;",
radioButtons("rbc", "1. Charts",
c("2D with axes" = "axisYes",
"2D no axes" = "axisNo",
"2D map" = "map2d",
'cartesian3D', 'geo3D', 'globe', 'other'
), inline=T)
))),
fluidRow(
column(12, radioButtons("rbt", '2. Type ', c(' '), inline=T) )
),
fluidRow(
column(11, span(
strong('3. R code'), uiOutput("clip", inline=TRUE), # copy-to-clipboard button
uiOutput('hlink', inline=TRUE, class='floc60') ),
actionButton('doPlot', 'Plot', icon=icon('eye'), inline=T)
)
),
fluidRow(column(12,
textAreaInput("rcode", NULL, width= "100%", height='150px',
placeholder= 'choose chart type to see code here'),
ecs.output("plot"),
add_busy_spinner(spin = "fading-circle", margins=c('50%', '50%')),
br(),br(), textOutput("ero"),
conditionalPanel("false", style= "display: none;",
textAreaInput("txt4js", NULL, width= '100px', height='100px', resize='none')
)
))
)
# ---- Server -------------------
server <- function(input, output, session) {
msg <- \(e) { output$ero <- renderText({ paste('err:\n',e$message) }) }
observeEvent(input$rbc, {
ctyp <- switch(input$rbc,
axisYes = c('scatter','bar','line','scatterGL','candlestick','boxplot','heatmap','pictorialBar'),
axisNo = c('gauge','pie','parallel','radar','graph','sankey',
'tree','themeRiver','funnel'),
map2d = c('world','SVG','geoJSON','leaflet'),
cartesian3D = c('scatter3D','bar3D','line3D','surface'),
geo3D = c('scatter3D','bar3D','lines3D'),
globe = c('scatter3D','bar3D','lines3D'),
other= c('timeline','morph'), #connect, ecStat
'TBD...'
)
updateRadioButtons(session, inputId= "rbt", choices= ctyp, selected=character(0), inline=T)
updateTextAreaInput(session, inputId= "rcode", value='')
})
# ---- type -------
observeEvent(input$rbt, {
out <- switch(input$rbt,
scatter= "# scatter type by default
mtcars |> group_by(cyl) |> ec.init()",
bar= bar, line= line2d,
scatterGL= "# scatterGL is for large point datasets, shows up slower
ggplot2::diamonds |> select(price, carat, cut) |> group_by(cut) |> filter(row_number()<1000) |>
ec.init(load='3D', title= list(subtext='subset 5K from 50K records', bottom=10),
dataZoom= list(type='inside'),
series.param= list(type='scatterGL',symbolSize=3)) |>
ec.theme('dark-mushroom')",
pictorialBar= picbar,
boxplot= boxplot,
candlestick= candlestick,
heatmap= heatmap,
parallel= "# group column, if any, should be last
mtcars |> relocate(cyl, .after= last_col()) |> group_by(cyl) |>
ec.init(ctype='parallel')",
radar= "ec.init(
radar= list(indicator= lapply(LETTERS[1:5], \\(x){list(name=x)}),axisName= list(color='black') ),
series.param= list(type='radar', data= list( list(name='r1', value= runif(5, 1, 5)) ) ),
legend= list(show=T)
)",
gauge= gauge,
pie= "cars |> arrange(speed) |> ec.init(ctype='pie',
tooltip= list(formatter= ec.clmn('speed %@, dist %@', 'speed', 'dist'))
,series.param= list(label= list(formatter='{@speed}'))
)",
themeRiver= themeRiver,
sankey= sankey,
graph= graph,
tree= tree,
funnel= funnel,
scatter3D= ifelse(input$rbc=='geo3D', scat3Dgeo, ifelse(input$rbc=='globe', scatGlobe, scat3Dcart)),
bar3D= ifelse(input$rbc=='geo3D', bar3Dgeo, ifelse(input$rbc=='globe', barGlobe, bar3Dcart)),
line3D= line3Dcart,
lines3D= ifelse(input$rbc=='globe', linesGlobe, lines3Dgeo),
surface= surface,
world= world,
geoJSON= gson,
SVG= svg,
leaflet= leaflet,
timeline= timeline,
morph= morph,
NULL
)
if (is.null(out)) out <- 'NA'
updateTextAreaInput(session, 'rcode', value= out)
output$hlink <- renderUI({ span() }) # clear
})
observeEvent(input$doPlot, {
rcody <- isolate(input$rcode)
if (!any(sapply(c('ec.init','ec.util'), grepl, rcody))) {
updateTextAreaInput(session, 'rcode', value= 'select a chart type')
return()
}
output$plot <- ecs.render({
tmp <- NULL
tryCatch({
tmp <- parse(text = rcody)
if (!is.null(tmp)) {
output$ero <- renderText({ "" })
eval(tmp) # display chart
}
}
,error= \(e) {msg(e)}
,warning= \(e) {msg(e)} )
})
# build hyperlink, skip registeMap, load json, etc
if (!endsWith(rcody,'\np') && !grepl('leaflet',rcody)) {
optsStr <- NULL
tmp <- paste(rcody,'|> ec.inspect() |> as.character()')
tryCatch({
tmp <- parse(text= tmp )
optsStr <- paste('option=', eval(tmp))
# remove quotes from functions
tmp <- gregexpr('\\W"function\\((.*?)"', optsStr) # from-to indexes
starts <- `attributes<-`(tmp[[1]],NULL)+1
lens <- attr(tmp[[1]],'match.length') -2
xch <- '\x1F' # '\u279b'
for(i in 1:length(starts)) {
p <- starts[i]; substr(optsStr, p, p) <- xch
p <- p+lens[i]; substr(optsStr, p, p) <- xch
}
optsStr <- gsub(xch, '', optsStr)
}
,error = \(e) {msg(e)}
,warning= \(e) {msg(e)} )
if (is.null(optsStr)) return
# set a reactive var to activate JS compression
updateTextAreaInput(session, 'txt4js', value= optsStr)
}
})
# ----- reactive ------
redit <- eventReactive(input$rcode, {
txt <- input$rcode
txt
})
# Add clipboard button
output$clip <- renderUI({
rclipButton("clipbtn", "Copy", redit(), icon=icon("clipboard"))
})
cprssDone <- reactive({ input$jsLinkOut })
observe({
txto <- cprssDone() # URL string
# if 3D then inject gl=1
if (isolate(input$rbc) %in% c('geo3D','cartesian3D','globe'))
txto <- sub('echarty','echarty&gl=1', txto)
output$hlink <- renderUI({
tags$a(href= txto,
target="_blank",
#style = "color:#FFF;",
icon('external-link'),
title= 'open in ECharts Editor', "ECharts")
})
}) |> bindEvent(cprssDone())
observe({
js$collect_content()
}) |> bindEvent(input$txt4js)
# help info
observeEvent(input$info, {
showModal(modalDialog(
title = "Learn by example",
"The Coder is a tutorial with various live samples, easy to browse and edit. Most of ECharts library features are covered. The goal is to present a user-friendly hands-on introduction to echarty R coding. Usage is:",
tags$ol(
tags$li("Select a ",strong('Category')," to show applicable chart types"),
tags$li("Select a chart ",strong('Type')," to see sample code"),
tags$li(strong('Edit')," R code or copy to clipboard"),
tags$li("Hit button ",strong('Plot')," to display the chart and get an ECharts ",strong('Editor link'))
), "Experiment by setting attributes from ",a(href='https://echarts.apache.org/en/option.html','ECharts API'),", for instance adding a title. ",
br(),"All ECharts attributes should be defined as named lists in R.",
br(), "Code errors are displayed in red. Do not add comments at end of last line.",
br(),h4('Editor link'),
"ECharts has a Javascript(JS) ",a(href='https://echarts.apache.org/examples/en/editor.html?c=line-simple','Editor'),". The Coder tries to translate R to a JS object and export it in the Editor through a link. ",
"The length of the link depends on the length of the R code, and may become too large for the browser to handle.",
br(),"When Coder is unable to translate some complex charts (maps,events), the link will not show up",
br(),"The Editor can load assets (images,json) from domains ",em('apache')," and ",em('jsdelivr')," only, other domains are ignored.",
br(),h4('Resources'),
"Library Echarts has a large collection of ",a(href="https://echarts.apache.org/examples/en/index.html","offical examples"),".",
br(),"More ",em('echarty')," code examples are available at ",a(href="https://www.rdocumentation.org/packages/echarty/versions/1.6.2/topics/--%20Introduction%20--#:~:text=counting%20(for%20now).-,Code%20examples,-Here%20is%20the","other locations"),
br(),"Please report problems and ask questions in ",a(href='https://github.com/helgasoft/echarty/issues', 'Issues'),'.'
))
})
}
shinyApp(ui= ui, server= server, options= list(launch.browser=T))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment