Skip to content

Instantly share code, notes, and snippets.

@helgasoft
Last active March 9, 2024 07:14
Show Gist options
  • Save helgasoft/819035e853d9889ba02cb69ecc587f34 to your computer and use it in GitHub Desktop.
Save helgasoft/819035e853d9889ba02cb69ecc587f34 to your computer and use it in GitHub Desktop.
Echarty Translate Assistant - JavaScript data to R
library(shiny)
library(stringr)
library(echarty)
library(rclipboard) # for clipboard Copy button
library(formatR)
if (FALSE) { # notes
#' problem plot with Chinese chars:
#' text='<U+6F0F><U+6597><U+56FE>' > Sys.getlocale()
#' Sys.setlocale(category = "LC_ALL", locale = "")
#' Sys.setlocale(category = "LC_ALL", locale = "chs")
#' as.character(parse(text='subtext: 纯属虚构',encoding = 'UTF-8'))
#' https://github.com/tidyverse/stringr/issues/295
#' Yeah, this is an underlying issue with R — when you create names using a call to c(), the names are converted to symbols, which are always encoded in the native encoding (which on windows will not be UTF-8). Unfortunately I don't think there's anything stringr can do about this.
#' Go to Control Panel --> Region and Language --> Administrative --> Change system locale --> Chinese
#' https://github.com/rstudio/shiny/issues/1053#issuecomment-167011937 !!!
#' SOLVED: use Sys.setlocale(,'Chinese') !!
#'
#' TODO
#' JS code box to select all by 1click:
#' works for textOutput, verbatimT(pre): https://codersblock.com/blog/using-css-to-control-text-selection/
#' dont translate {:} if inside formatter string : save in vector, replace w @_index_@, finally replace back all in loop
#' formatter='{c}: {a}' https://echarts.apache.org/examples/en/editor.html?c=pie-nest
#' https://echarts.apache.org/examples/en/editor.html?c=line-marker
#' itemNameFormatter: 'exp {value}' https://echarts.apache.org/examples/en/editor.html?c=boxplot-light-velocity
#' itemNameFormatter: function (params) { https://echarts.apache.org/examples/en/editor.html?c=boxplot-light-velocity2
#' ok except formatter in https://echarts.apache.org/examples/en/editor.html?c=gauge-stage
#' formatter=htmlwidgets::JS("function (param) {...} in https://echarts.apache.org/examples/en/editor.html?c=sunburst-label-rotate
#' both formatters in https://echarts.apache.org/examples/en/editor.html?c=pictorialBar-body-fill
#' color=htmlwidgets::JS("new echarts.graphic.LinearGradient https://echarts.apache.org/examples/en/editor.html?c=area-stack-gradient
#' explain comma error in series = "argument N is empty" (can parser catch?) ex: https://echarts.apache.org/examples/en/editor.html?c=pie-simple
#' extra ".revert()" in https://echarts.apache.org/examples/en/editor.html?c=radar-aqi
}
ui = fluidPage(
tags$style(type='text/css', "
#ero { background-color: lemonchiffon; color: red;
-webkit-user-select: all; user-select: all; }
"),
#tags$script("window.onload = function() { document.getElementById('jscode').tabIndex='0'; }"),
fluidRow(
column(10, titlePanel( h3(span(tags$a(href='https://github.com/helgasoft/echarty','Echarty')," Translate Assistant - Javascript data to R"), align = "center"))),
column(2, actionButton("info", label=tags$img(src ="https://img.icons8.com/metro/2x/info.png", alt='Help', width= '30')) )
),
rclipboardSetup(),
div( tabindex="0", strong('1. Javascript code'),span('from'),
tags$a(href="https://echarts.apache.org/examples/en/", "examples"),span(', or '),
tags$a(href="https://www.makeapie.com/", "makeapie"),span(', or other source'),
textAreaInput("jscode", NULL, width='100%', height='150px',
placeholder='paste Echarts JS code here, like option = { ... };')
),
fluidRow(
column(3, div( strong('R code'), uiOutput("clip", inline=TRUE))), # copy-to-clipboard button
column(6, actionButton("doTranslate", "2. Translate"), align = "center"),
column(3, checkboxInput('chkCN', "CN chars", FALSE), align = "right")
),
textAreaInput("rcode", NULL, width = "1000px", height='150px',
placeholder='hit button Translate to see code here'),
column(12, actionButton("doPlot", "3. Plot in R"), align = "center"),
br(),br(), textOutput("ero"),
ecs.output("plot")
)
server <- function(input, output, session){
proc <- function(jscode) {
tmp <- enc2utf8(jscode)
tmp <- gsub("/\\*(.*)\\*/", '', tmp) # kill JS multiline comments
{
lines <- lapply(strsplit(tmp, '\n', fixed=TRUE), trimws)
lines <- unlist(lines)
# remove comments to end-of-line if not https:// path://
lines <- gsub("(?<!:)//(.*)$", '', lines, perl=TRUE)
tmp <- paste(lines, collapse='')
}
tmp <- str_replace_all(tmp, fixed('var '), '' )
tmp <- str_replace_all(tmp, fixed('= {'), '=list(' )
tmp <- str_replace_all(tmp, fixed(': ['), '=list(' )
tmp <- str_replace_all(tmp, fixed(':['), '=list(' )
tmp <- str_replace_all(tmp, fixed(': {'), '=list(' )
tmp <- str_replace_all(tmp, fixed(':{'), '=list(' )
tmp <- str_replace_all(tmp, fixed(': '), '=' )
tmp <- gsub(":(?!//)", '=', tmp, perl=TRUE) # exclude https:// path://
tmp <- str_replace_all(tmp, fixed('{'), 'list(' )
tmp <- str_replace_all(tmp, fixed('}'), ')' )
tmp <- str_replace_all(tmp, fixed('['), 'list(' ) # was 'c('
tmp <- str_replace_all(tmp, fixed(']'), ')' )
tmp <- str_replace_all(tmp, fixed('true'), 'TRUE' )
tmp <- str_replace_all(tmp, fixed('false'), 'FALSE' )
tmp <- str_replace_all(tmp, fixed('null'), 'NULL' )
# tmp <- str_replace_all(tmp, fixed(';'), '; p' )
tmp <- str_replace_all(tmp, fixed('option ='), '\n p <- ec.init(); p$x$opts <- ' )
# post-fix
tmp <- str_replace_all(tmp, fixed('https=#'), 'https://' )
# tmp <- str_replace_all(tmp, fixed('list(c(list'), 'list(list(list')
tmp <- str_replace_all(tmp, fixed('=list()'), "=list(ey='')") # for [] or {}
tmp <- gsub(';', '\n', tmp, fixed=TRUE)
# some rudimentary code wrapping
kwords <- c('dataset','series','visualMap','dataZoom','tooltip','legend')
for(i in 1:length(kwords)) { kw <- paste0(kwords[i],'=')
tmp <- gsub(kw, paste('\n',kw), tmp, fixed=TRUE) }
tmp <- paste(tmp,'\n p')
enc2utf8(tmp)
}
observeEvent(input$doTranslate, {
output$ero <- renderText({ '' })
output$plot <- ecs.render({ NULL })
tmp <- proc(input$jscode)
tryCatch({
tmp <- tidy_source(text=tmp, indent=2)
tmp <- paste(tmp$text.tidy, collapse = '\n')
}
,error = function(e) {
output$ero <- renderText({ paste('error:\n',e$message) }) }
)
updateTextAreaInput(session, 'rcode', value=tmp)
})
observeEvent(input$doPlot, {
output$plot <- ecs.render({
tmp <- NULL
tryCatch(
tmp <- parse(text = isolate(input$rcode))
,error = function(e) {
output$ero <- renderText({ paste('ERROR:\n',e$message) }) }
)
if (!is.null(tmp)) {
output$ero <- renderText({ "" })
eval(tmp) # display chart
}
})
})
observeEvent(input$chkCN, {
if (input$chkCN) Sys.setlocale(,'Chinese')
else Sys.setlocale(,)
})
redit <- eventReactive(input$rcode, {
txt <- input$rcode
txt
})
# Add clipboard button
output$clip <- renderUI({
rclipButton("clipbtn", "Copy", redit(), icon=icon("clipboard"))
})
# help info
observeEvent(input$info, {
showModal(modalDialog(
title = "Learn by example",
tags$div("Javascript library Echarts has lots of great ",tags$a(href="https://echarts.apache.org/examples/en/", "examples"),
". The goal here is to facilitate the translation of their ",strong('data')," to R, especially the ",strong('option')," object.",
"Option components represent the chart. In Echarty's R examples ",tags$em('option')," is implemented as ",strong('p$x$opts'),
". Javascript commands and functions will ",strong('not')," translate properly.",
br(), "So here are the steps:",
br(), "1. Open an ",tags$a(href="https://echarts.apache.org/examples/en/editor.html?c=parallel-simple", "example")," and ",strong('copy')," the entire code from the left side",
br(), "2. ",strong('Paste')," the text in box ",tags$em('Javascript code')," here",
br(), "3. Hit button Translate and some text will appear under ",tags$em('R code'),
br(), "4. Edit the R code and/or copy to clipboard (optional)",
br(), "5. Hit button ",tags$em('Plot in R')," to show a chart, or code errors",
br(),
br(),"If your locale is English, checkbox ",strong("CN chars")," will show Chinese characters in plots. Check the box ",strong('before')," Translate. Uncheck to reset locale back to English.",
br(),"Most examples will not translate 100%, but here are some that did - ",
tags$a(href="https://echarts.apache.org/examples/en/editor.html?c=line-simple", "line"),",",
tags$a(href="https://echarts.apache.org/examples/en/editor.html?c=parallel-simple", "parallel"),",",
tags$a(href="https://echarts.apache.org/examples/en/editor.html?c=radar", "radar"),",",
tags$a(href="https://echarts.apache.org/examples/en/editor.html?c=sunburst-simple", "sunburst"),",",
tags$a(href="https://echarts.apache.org/examples/en/editor.html?c=sunburst-visualMap", "sunburst-vMap"),",",
tags$a(href="https://echarts.apache.org/examples/en/editor.html?c=sunburst-drink", "drink"),",",
tags$a(href="https://echarts.apache.org/examples/en/editor.html?c=sankey-vertical", "sankey"),",",
tags$a(href="https://echarts.apache.org/examples/en/editor.html?c=sankey-itemstyle", "itemstyle"),",",
tags$a(href="https://echarts.apache.org/examples/en/editor.html?c=funnel", "funnel"),",",
tags$a(href="https://echarts.apache.org/examples/en/editor.html?c=bar-stack", "bar-stack"),",",
tags$a(href="https://echarts.apache.org/examples/en/editor.html?c=dataset-encode0", "dataset-encode"),",",
tags$a(href="https://echarts.apache.org/examples/en/editor.html?c=pie-roseType-simple", "pie-roseType"),",",
tags$a(href="https://echarts.apache.org/examples/en/editor.html?c=themeRiver-basic", "themeRiver")," - try them out!",
br(),tags$a(href="https://www.makeapie.com/", "Makeapie")," examples in general have more executable code and are harder to translate."
)
))
})
}
shinyApp(ui, server)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment