datastorm-open / rAmCharts

API for Amcharts
48 stars 17 forks source link

rAmcharts Package Documentation Queries #45

Closed debsush closed 8 years ago

debsush commented 8 years ago

Your package manual/documentation rAmcharts.pdf provides below language

"chartScrollbarSettings ChartScrollbar. If you change a property after the chart is initialized, you should call stockChart.validateNow() method in order for it to work. If there is no default value specified, default value of ChartScrollbar class will be used"

I would like to see the validateNow() method being triggered in an example. Usage of validateNow() and validateData() methods is probably the most important part of the package that I am missing today as I enter the final stages of my webapp development.

I have implemented it within an amChart "event" [panelRemoved event] using addListener.

The below works perfectly - I had two panels in my chart. I tried to change the chart type of the first panel stockGraph from line to column using the validateNow() method when user tries to close the second panel. I simple wanted to see if validateNow() method works and it does.

addListener('panelRemoved', 'function(event){ event.chart.panels[0].stockGraphs[0].type = "column"; event.chart.validateNow(); }')

But I really need to be able to call this method anytime based on R events and not just amCharts events. When I say R events, I am referring to say the click of an actionbutton within ui.R. Does the below work for you?

ui.R

actionbutton("samplebtn", label="Click Me"),

amChartsOutput("pic", type = NULL, width = "100%", height = "400px")

server.R

output$pic<-renderAmCharts({

stockChart<<-pipeR::pipeline( amSerialChart(dataDateFormat = 'YYYY',categoryField = 'year', startDuration = 0), setDataProvider(data.frame(year = 1990:2015, value = runif(length(1990:2015), -1, 1))), addValueAxes(axisAlpha = 0, position = 'left'), addGraph(id = 'g1', type = 'column', valueField = 'value', fillAlphas = 1), setCategoryAxis(minPeriod = 'YYYY', parseDates = TRUE), addListener('init', paste('function(event) {', 'setTimeout(function() {', ' event.chart.allLabels = [{', ' x: event.chart.marginLeftReal + 20,', ' y: event.chart.marginTopReal + 20,', ' text: "Watermark label",', ' size: 20,', ' color: "green",', ' alpha: 1', ' }];', ' event.chart.validateNow()', '}, 100)}')) )

return(plot(chart)) })

shinyjs::onclick("samplebtn", stockChart.validateNow())

Or you could Use

observeEvent(input$samplebtn,{

Change some chart property here

..... .....

Now validate the chart

stockChart.validateNow() })

Thank you for your cooperation and I am willing to bring ideas to the table,if needed, to implement it.

Thank you as always SD

bthieurmel commented 8 years ago

Hi, Your problem is how to access to an existing chart within shiny and javascript function. As you can see here (http://stackoverflow.com/questions/28384411/get-an-instance-of-amchart-using-id), amCharts have AmCharts.charts array with all amCharts graphics, and so we can get a chart by his id.

To simplify this, and have a simply functionnality, I've just add getAmChart() javascript function to get and then modify a chart. So now, you can use all the methods you want ! Here is a simple example with two graphics :

require(shiny)
require(rAmCharts)
require(shinyjs)

jsCode <- "shinyjs.changeType = function(params){
  var chart = getAmChart(params[1]);
  chart.graphs[0].type = params[0];
  chart.validateNow();
}"

server <- function(input, output) {
  output$myplot1 <- renderAmCharts({
    ##Data
    data('data_bar')
    ##Plot
    graph <- pipeR::pipeline(
      amSerialChart(categoryField = 'country'),
      setDataProvider(data_bar),
      addGraph(balloonText = '<b>[[category]]: [[value]]</b>', type = "line", valueField = 'visits')
    )
    graph
  })

  output$myplot2 <- renderAmCharts({
    ##Data
    data('data_bar')
    ##Plot
    graph <- pipeR::pipeline(
      amSerialChart(categoryField = 'country'),
      setDataProvider(data_bar),
      addGraph(balloonText = '<b>[[category]]: [[value]]</b>', type = "column", valueField = 'visits')
    )
    graph
  })

  observeEvent(input$type1, {
    js$changeType(input$type1, "myplot1")
  })

  observeEvent(input$type2, {
    js$changeType(input$type2, "myplot2")
  })

}

ui <- fluidPage(
  useShinyjs(),
  extendShinyjs(text = jsCode),
  sidebarLayout(
    sidebarPanel(
      selectInput("type1", "Type of graph 1 :", c("line", "column")),
      selectInput("type2", "Type of graph 2 :", c("column", "line"))
    ),
    mainPanel(amChartsOutput("myplot1"), amChartsOutput("myplot2"))
  )
)

shinyApp(ui = ui, server = server)
debsush commented 8 years ago

Excellent. Much appreciate. This is great.

Similarly is there a way by which I can use a R data frame within the addListner JS function. I am referencing this example and would like to replicate it in R Shiny http://www.amcharts.com/tips/change-the-data-set-dynamically-based-on-zoom-on-stock-chart/

I am struggling to replicate the above example for months and would greatly appreciate an implementation of the same from your end

Example outlined

output$plotter<-renderAmCharts({

##Data
    data('data_bar') # Dataset 1#
   data('data_bar1') #Dataset 2#
    ##Plot
    graph <- pipeR::pipeline(
      amSerialChart(categoryField = 'country'),
      setDataProvider(data_bar),
      addGraph(balloonText = '<b>[[category]]: [[value]]</b>', type = "column", valueField = 'visits')%>>%
addListener('zoomed', paste('function(event) { 
var startdt = event.chart.startDate;
var enddt = event.chart.endDate;
var timeDiff = Math.abs(end.getTime() - start.getTime());
var diffDays = Math.ceil(timeDiff / (1000 * 3600 * 24));
if (diffDays < 365) {
chart.mainDataSet.dataProvider = data_bar; /* this is where I need to either access R data frame or run a R function that pulls the data.  I guess we would need to convert R data frame to JSON*/
chart.validateNow(false, true);
}) 
)
    graph
})
bthieurmel commented 8 years ago

You can use the same way as passing some basic input like the type, with good data transformation :

debsush commented 8 years ago

I will give this a try today. Sounds interesting

debsush commented 8 years ago

Hi,

The above example you gave using shinyjs did not work on my system. When I change the chart type, it does not change the chart. Is this because while we are changing thhe chart configuration using JS, but it is not getting re-rendered within renderAmCharts and hence yielding no results. Can you check if it is working at your end.

If the above example is working at your end, can you provide me your session info

Thank you SD

bthieurmel commented 8 years ago

The example works for me, using last shiny and shinyjs CRAN version, and last rAmCharts github developpment version

debsush commented 8 years ago

I will try that

debsush commented 8 years ago

The example with SerialChart works but the one with AmStockChart below does not. Please help me understand the issue

#paste("shinyjs.changeType = function(params){var chart = getAmChart(params[1]);chart.graphs[0].type = ",df,";chart.validateNow();}",sep="")

require(shiny)
require(rAmCharts)
require(shinyjs)

jsCode <- "shinyjs.changeType = function(params){
var chart = getAmChart(params[1]);
chart.graphs[0].type = params[0];
chart.validateNow();
}"

server <- function(input, output) {
  output$myplot1 <- renderAmCharts({
    ##Data
    data('data_bar')
    ##Plot
    graph <- pipeR::pipeline(
      amSerialChart(categoryField = 'country'),
      setDataProvider(data_bar),
      addGraph(balloonText = '<b>[[category]]: [[value]]</b>', type = "line", valueField = 'visits')
    )
    graph
  })

  output$myplot2 <- renderAmCharts({
#     ##Data
#     data('data_bar')
#     ##Plot
#     graph <- pipeR::pipeline(
#       amSerialChart(categoryField = 'country'),
#       setDataProvider(data_bar),
#       addGraph(balloonText = '<b>[[category]]: [[value]]</b>', type = "column", valueField = 'visits')
#     )
    ## Data
    times <- as.POSIXct(seq(-60 * 60 * 24 * 50 + 1, 0, by = 3600), origin = Sys.time(), tz = 'UTC')
    times <- round(times,'hours')
    times <- data.frame(times)
    times$Mesure <- 1:length(times$times) + rep(cos(seq(-pi,pi,length.out = 100)), 12) * 500 + runif(length(times$times)) * 200

    mycategoryBalloonDateFormat <- list(list(period = 'YYYY', format = 'YYYY'),
                                        list(period='MM', format = 'YYYY-MM'), 
                                        list(period = 'WW', format = 'YYYY-MM-DD'),
                                        list(period='DD', format = 'YYYY-MM-DD'), 
                                        list(period = 'hh', format = 'YYYY-MM-DD JJ:NN'),
                                        list(period='mm', format = 'YYYY-MM-DD JJ:NN'), 
                                        list(period = 'ss', format = 'YYYY-MM-DD JJ:NN:ss'),
                                        list(period='fff', format = 'YYYY-MM-DD JJ:NN:ss'))
    ## Plot
    graph<-pipeR::pipeline(
      amStockChart(dataDateFormat = 'YYYY-MM-DD JJ:NN:ss') ,
      addDataSet(pipeR::pipeline(
        dataSet(title = 'first data set', categoryField = 'times') ,
        setDataProvider(times,keepNA=FALSE),
        addFieldMapping(fromField = 'Mesure', toField = 'Mesure'))),
      addPanel(pipeR::pipeline(
        stockPanel(showCategoryAxis = TRUE, title = 'Value') ,
        addStockGraph(id = 'g1',connect=FALSE, valueField = 'Mesure', comparable = TRUE,periodValue = 'Average',type='column',
                      compareField = 'Mesure', balloonText = 'Value : <b>[[value]] Unit</b>', precision = 0,
                      compareGraphBalloonText = '[[title]] =<b>[[value]]</b>'))),
      setChartScrollbarSettings(graph = 'g1'),
      setChartCursorSettings( valueBalloonsEnabled = TRUE, fullWidth = TRUE,
                              cursorAlpha = 0.1, valueLineBalloonEnabled = TRUE,
                              valueLineEnabled = TRUE, valueLineAlpha = 0.5,
                              categoryBalloonDateFormats = mycategoryBalloonDateFormat),
      setPeriodSelector(pipeR::pipeline( periodSelector( position = 'bottom' ,inputFieldsEnabled=FALSE) ,
                                         addPeriod( period = 'DD', selected = TRUE, count = 1, label = '1 day') ,
                                         addPeriod( period = 'WW', count = 1, label = '1 week' ) ,
                                         addPeriod( period = 'MAX', label = 'All' ))),
      setCategoryAxesSettings(parseDates = TRUE, minPeriod = '1hh',
                              groupToPeriods = c('hh','3hh', '12hh','1DD'),maxSeries = 50),
      setPanelsSettings(recalculateToPercents = 'never', creditsPosition='top-left')
    )
    graph
  })

  observeEvent(input$type1, {
    js$changeType(input$type1, "myplot1")
  })

  observeEvent(input$type2, {
    js$changeType(input$type2, "myplot2")
  })

}

ui <- fluidPage(
  useShinyjs(),
  extendShinyjs(text = jsCode),
  sidebarLayout(
    sidebarPanel(
      selectInput("type1", "Type of graph 1 :", c("line", "column")),
      selectInput("type2", "Type of graph 2 :", c("column", "line"))
    ),
    mainPanel(amChartsOutput("myplot1"), amChartsOutput("myplot2"))
  )
)

shinyApp(ui = ui, server = server)
bthieurmel commented 8 years ago

Hi,

First, issue on github is for bug/update for the R package, not for ask another question (problem in javascript, error in R code, ....)

In your case, the javascript code is wrong. serial and stock don't have the same structure. So you have to look at the amChart API or use some things as console.info in javascript to do what you want and view object in web console for example.

I`ve corrected your case today but please post real issue in the futur.

#paste("shinyjs.changeType = function(params){var chart = getAmChart(params[1]);chart.graphs[0].type = ",df,";chart.validateNow();}",sep="")

require(shiny)
require(rAmCharts)
require(shinyjs)

jsCode <- "shinyjs.changeType = function(params){
var chart = getAmChart(params[1]);
console.info(chart);
if(chart !== undefined){
  if(chart.type === 'serial'){
    chart.graphs[0].type = params[0];
  } else if(chart.type === 'stock') {
    chart.panels[0].graphs[0].type = params[0];
  }
  chart.validateNow();
}
}"

server <- function(input, output) {
  output$myplot1 <- renderAmCharts({
    ##Data
    data('data_bar')
    ##Plot
    graph <- pipeR::pipeline(
      amSerialChart(categoryField = 'country'),
      setDataProvider(data_bar),
      addGraph(balloonText = '<b>[[category]]: [[value]]</b>', type = "line", valueField = 'visits')
    )
    graph
  })

  output$myplot2 <- renderAmCharts({
    #     ##Data
    #     data('data_bar')
    #     ##Plot
    #     graph <- pipeR::pipeline(
    #       amSerialChart(categoryField = 'country'),
    #       setDataProvider(data_bar),
    #       addGraph(balloonText = '<b>[[category]]: [[value]]</b>', type = "column", valueField = 'visits')
    #     )
    ## Data
    times <- as.POSIXct(seq(-60 * 60 * 24 * 50 + 1, 0, by = 3600), origin = Sys.time(), tz = 'UTC')
    times <- round(times,'hours')
    times <- data.frame(times)
    times$Mesure <- 1:length(times$times) + rep(cos(seq(-pi,pi,length.out = 100)), 12) * 500 + runif(length(times$times)) * 200

    mycategoryBalloonDateFormat <- list(list(period = 'YYYY', format = 'YYYY'),
                                        list(period='MM', format = 'YYYY-MM'), 
                                        list(period = 'WW', format = 'YYYY-MM-DD'),
                                        list(period='DD', format = 'YYYY-MM-DD'), 
                                        list(period = 'hh', format = 'YYYY-MM-DD JJ:NN'),
                                        list(period='mm', format = 'YYYY-MM-DD JJ:NN'), 
                                        list(period = 'ss', format = 'YYYY-MM-DD JJ:NN:ss'),
                                        list(period='fff', format = 'YYYY-MM-DD JJ:NN:ss'))
    ## Plot
    graph<-pipeR::pipeline(
      amStockChart(dataDateFormat = 'YYYY-MM-DD JJ:NN:ss') ,
      addDataSet(pipeR::pipeline(
        dataSet(title = 'first data set', categoryField = 'times') ,
        setDataProvider(times,keepNA=FALSE),
        addFieldMapping(fromField = 'Mesure', toField = 'Mesure'))),
      addPanel(pipeR::pipeline(
        stockPanel(showCategoryAxis = TRUE, title = 'Value') ,
        addStockGraph(id = 'g1',connect=FALSE, valueField = 'Mesure', comparable = TRUE,periodValue = 'Average',type='column',
                      compareField = 'Mesure', balloonText = 'Value : <b>[[value]] Unit</b>', precision = 0,
                      compareGraphBalloonText = '[[title]] =<b>[[value]]</b>'))),
      setChartScrollbarSettings(graph = 'g1'),
      setChartCursorSettings( valueBalloonsEnabled = TRUE, fullWidth = TRUE,
                              cursorAlpha = 0.1, valueLineBalloonEnabled = TRUE,
                              valueLineEnabled = TRUE, valueLineAlpha = 0.5,
                              categoryBalloonDateFormats = mycategoryBalloonDateFormat),
      setPeriodSelector(pipeR::pipeline( periodSelector( position = 'bottom' ,inputFieldsEnabled=FALSE) ,
                                         addPeriod( period = 'DD', selected = TRUE, count = 1, label = '1 day') ,
                                         addPeriod( period = 'WW', count = 1, label = '1 week' ) ,
                                         addPeriod( period = 'MAX', label = 'All' ))),
      setCategoryAxesSettings(parseDates = TRUE, minPeriod = '1hh',
                              groupToPeriods = c('hh','3hh', '12hh','1DD'),maxSeries = 50),
      setPanelsSettings(recalculateToPercents = 'never', creditsPosition='top-left')
    )
    graph
  })

  observeEvent(input$type1, {
    js$changeType(input$type1, "myplot1")
  })

  observeEvent(input$type2, {
    js$changeType(input$type2, "myplot2")
  })

}

ui <- fluidPage(
  useShinyjs(),
  extendShinyjs(text = jsCode),
  sidebarLayout(
    sidebarPanel(
      selectInput("type1", "Type of graph 1 :", c("line", "column")),
      selectInput("type2", "Type of graph 2 :", c("column", "line"))
    ),
    mainPanel(amChartsOutput("myplot1"), amChartsOutput("myplot2"))
  )
)

shinyApp(ui = ui, server = server)

Cheers

debsush commented 8 years ago

Apologies. I will take care of it going forward. Thank you as always.