Хобрук: Ваш путь к мастерству в программировании

R Highcharter: динамическая многоуровневая детализация в Shiny

Я пытаюсь создать многоуровневый график детализации, используя highcharter с динамическими данными в shiny. Я могу сделать это, используя только код R с набором input, но когда я помещаю его в блестящее приложение и пытаюсь динамически подмножить данные, это терпит неудачу.

Ниже приведен код, который работает в R (только переход от фермы к овцам):

library(shinyjs)
library(tidyr)
library(data.table)
library(highcharter)
library(dplyr)

x <- c("Farm","Farm","Farm","City","City","City","Ocean","Ocean")
y <- c("Sheep","Sheep","Cow","Car","Bus","Bus","Boat","Boat")
z <- c("Bill","Tracy","Sandy","Bob","Carl","Newt","Fig","Tony")
a <- c(1,1,1,1,1,1,1,1)

dat <- data.frame(x,y,z,a)

input <- "Farm"
input2 <- "Sheep"


    #First Tier
    datSum <- dat %>%
      group_by(x) %>%
      summarize(Quantity = sum(a)
      )
    datSum <- arrange(datSum,desc(Quantity))
    Lvl1dfStatus <- tibble(name = datSum$x, y = datSum$Quantity, drilldown = tolower(name))

    #Second Tier
    datSum2 <- dat[dat$x == input,]

    datSum2 <- datSum2 %>%
      group_by(y) %>%
      summarize(Quantity = sum(a)
      )
    datSum2 <- arrange(datSum2,desc(Quantity))
    Lvl2dfStatus <- tibble(name = datSum2$y,y = datSum2$Quantity, drilldown = tolower(name))

    #Third Tier
    datSum2 <- dat[dat$x == input,]
    datSum3 <- datSum2[datSum2$y == input2,]

    datSum3 <- datSum3 %>%
      group_by(z) %>%
      summarize(Quantity = sum(a)
      )
    datSum3 <- arrange(datSum3,desc(Quantity))
    Lvl3dfStatus <- tibble(name = datSum3$z,y = datSum3$Quantity)

    #Graph
    ClickedTest <- JS("function(event) {Shiny.onInputChange('ClickedInput', event.point.name);}")

    highchart() %>%
      hc_xAxis(type = "category") %>%
      hc_add_series(Lvl1dfStatus, "column", hcaes(x = name, y = y), color = "#E4551F") %>%
      hc_plotOptions(column = list(stacking = "normal",
                                   events = list(click = ClickedTest))) %>%
      hc_drilldown(
        allowPointDrilldown = TRUE,
        series = list(
          list(id = tolower(input), type = "column", data = list_parse(Lvl2dfStatus)),
          list(id = tolower(input2), type = "column", data = list_parse2(Lvl3dfStatus))
        )
      )

Ниже приведен код, который дает сбой в Shiny при изменении input на динамический:

library (shinyjs)
library (tidyr)
library (data.table)
library (highcharter)
library (dplyr)
library (shinydashboard)
library (shiny)

x <- c("Farm","Farm","Farm","City","City","City","Ocean","Ocean")
y <- c("Sheep","Sheep","Cow","Car","Bus","Bus","Boat","Boat")
z <- c("Bill","Tracy","Sandy","Bob","Carl","Newt","Fig","Tony")
a <- c(1,1,1,1,1,1,1,1)

dat <- data.frame(x,y,z,a)

# input <- "Farm"
# input2 <- "Sheep"

header <- dashboardHeader()
body <- dashboardBody(

  highchartOutput("Test"),
  verbatimTextOutput("trial")

)
sidebar <- dashboardSidebar()

ui <- dashboardPage(header, sidebar, body)

server <- function(input, output, session) {

Lvl1ClickHardCoded <- ""

  output$Test <- renderHighchart({

      #First Tier
      datSum <- dat %>%
        group_by(x) %>%
        summarize(Quantity = sum(a)
        )
      datSum <- arrange(datSum,desc(Quantity))
      Lvl1dfStatus <- tibble(name = datSum$x, y = datSum$Quantity, drilldown = tolower(name))

      #Second Tier
      rowcheck <- dat[dat$x == input$ClickedInput,]
      if (nrow(rowcheck)!=0){

        datSum2 <- dat[dat$x == input$ClickedInput,]
        datSum2 <- datSum2 %>%
          group_by(y) %>%
          summarize(Quantity = sum(a)
          )
        datSum2 <- arrange(datSum2,desc(Quantity))
        Lvl2dfStatus <- tibble(name = datSum2$y,y = datSum2$Quantity, drilldown = tolower(name))

        Lvl1ClickHardCoded <<- input$ClickedInput
        Lvl1id <<- tolower(input$ClickedInput)
      } 
      else{
        Lvl2dfStatus <- data.table(Group.1=numeric(), x=numeric())
        Lvl2dfStatus <- tibble(name = Lvl2dfStatus$Group.1,y = Lvl2dfStatus$x)
        Lvl1id <- ""
      }

      #Third Tier
      rowcheck <- dat[dat$x == Lvl1ClickHardCoded,]
      rowcheck <- rowcheck[rowcheck$y == input$ClickedInput,]
      if (nrow(rowcheck)!=0){
        datSum2 <- dat[dat$x == Lvl1ClickHardCoded,]
        datSum3 <- datSum2[datSum2$y == input$ClickedInput,]

        datSum3 <- datSum3 %>%
          group_by(z) %>%
          summarize(Quantity = sum(a)
          )
        datSum3 <- arrange(datSum3,desc(Quantity))
        Lvl3dfStatus <- tibble(name = datSum3$z,y = datSum3$Quantity)

        Lvl2id <<- tolower(input$ClickedInput)
      } 
      else{
        Lvl3dfStatus <- data.table(Group.1=numeric(), x=numeric())
        Lvl3dfStatus <- tibble(name = Lvl3dfStatus$Group.1,y = Lvl3dfStatus$x)
        Lvl2id <- ""
      }

      #Graph
      ClickedTest <- JS("function(event) {Shiny.onInputChange('ClickedInput', event.point.name);}")

      highchart() %>%
        hc_xAxis(type = "category") %>%
        hc_add_series(Lvl1dfStatus, "column", hcaes(x = name, y = y), color = "#E4551F") %>%
        hc_plotOptions(column = list(stacking = "normal",
                                     events = list(click = ClickedTest))) %>%
        hc_drilldown(
          allowPointDrilldown = TRUE,
          series = list(
            list(id = Lvl1id, type = "column", data = list_parse(Lvl2dfStatus)),
            list(id = Lvl2id, type = "column", data = list_parse2(Lvl3dfStatus))
          )
        )
  })

  output$trial <- renderText({input$ClickedInput})

}


shinyApp(ui, server)

  • получил лишнюю запятую, строка 22 в Shiny. highchartOutput("Test"),. Удалите его, а также добавьте библиотеку (dplyr) вверху. 13.03.2019
  • Даже не понял, спасибо! 13.03.2019
  • Пожалуйста, уточните: хотите ли вы использовать функцию детализации Highcharts или хотите заменить ее на R, самостоятельно установив обработчик кликов? 14.03.2019
  • Я хотел бы использовать функцию детализации Highcharts, если смогу заставить ее работать в приведенном выше примере. 14.03.2019

Ответы:


1

Ваш подход был введен в заблуждение функцией щелчка. Это совершенно не нужно, так как (как видно из неблестящего примера) Highcharts имеет свои собственные механизмы для обнаружения последовательных кликов и может самостоятельно находить и отображать детализацию.

Вы пытаетесь поймать событие щелчка, и функция построения диаграммы Highcharts каждый раз перерисовывается (сбрасывая любую детализацию), поэтому вы вообще не можете видеть какие-либо события детализации.

Решение состоит в том, чтобы просто скопировать ваш рабочий пример Highcharts в функцию renderHighchart. Вы сразу увидите, что выпадающие списки «Ферма» и «Овцы» работают.

Я предполагаю, что вы запутались, используя термины «вход» для имен подуровней, поскольку они вообще не являются входными данными (в блестящем смысле). Чтобы обеспечить правильную работу детализации, необходимо предварительно определить наборы детализации при создании диаграммы Highcharts. Таким образом, вы заранее сообщаете плагину, какие детализированные значения будут использоваться, и Highchart выполняет детализацию только на основе указанных вами идентификаторов.

Я отредактировал ваш код так, что все возможные развертки создаются в цикле, и все работает:

library (shinyjs)
library (tidyr)
library (data.table)
library (highcharter)
library (dplyr)
library (shinydashboard)
library (shiny)

x <- c("Farm","Farm","Farm","City","City","City","Ocean","Ocean")
y <- c("Sheep","Sheep","Cow","Car","Bus","Bus","Boat","Boat")
z <- c("Bill","Tracy","Sandy","Bob","Carl","Newt","Fig","Tony")
a <- c(1,1,1,1,1,1,1,1)

dat <- data.frame(x,y,z,a)

header <- dashboardHeader()
body <- dashboardBody(

  highchartOutput("Working"),
  verbatimTextOutput("trial")

)
sidebar <- dashboardSidebar()

ui <- dashboardPage(header, sidebar, body)

server <- function(input, output, session) {

  output$Working <- renderHighchart({
    #First Tier #Copied
    datSum <- dat %>%
      group_by(x) %>%
      summarize(Quantity = sum(a)
      )
    datSum <- arrange(datSum,desc(Quantity))
    Lvl1dfStatus <- tibble(name = datSum$x, y = datSum$Quantity, drilldown = tolower(name))

    #Second Tier # Generalized to not use one single input
    # Note: I am creating a list of Drilldown Definitions here.

    Level_2_Drilldowns <- lapply(unique(dat$x), function(x_level) {
      # x_level is what you called 'input' earlier.
      datSum2 <- dat[dat$x == x_level,]

      datSum2 <- datSum2 %>%
        group_by(y) %>%
        summarize(Quantity = sum(a)
        )
      datSum2 <- arrange(datSum2,desc(Quantity))

      # Note: The "drilldown" variable has to be unique, this is why we use level 1 plus level 2 names.
      Lvl2dfStatus <- tibble(name = datSum2$y,y = datSum2$Quantity, drilldown = tolower(paste(x_level, name, sep = "_")))

      list(id = tolower(x_level), type = "column", data = list_parse(Lvl2dfStatus))
    })


    #Third Tier # Generalized through all of level 2
    # Note: Again creating a list of Drilldown Definitions here.
    Level_3_Drilldowns <- lapply(unique(dat$x), function(x_level) {

      datSum2 <- dat[dat$x == x_level,]

      lapply(unique(datSum2$y), function(y_level) {

        datSum3 <- datSum2[datSum2$y == y_level,]

        datSum3 <- datSum3 %>%
          group_by(z) %>%
          summarize(Quantity = sum(a)
          )
        datSum3 <- arrange(datSum3,desc(Quantity))

        Lvl3dfStatus <- tibble(name = datSum3$z,y = datSum3$Quantity)

        # Note: The id must match the one we specified above as "drilldown"
        list(id = tolower(paste(x_level, y_level, sep = "_")), type = "column", data = list_parse2(Lvl3dfStatus))
      })
    }) %>% unlist(recursive = FALSE)

    highchart() %>%
      hc_xAxis(type = "category") %>%
      hc_add_series(Lvl1dfStatus, "column", hcaes(x = name, y = y), color = "#E4551F") %>%
      hc_plotOptions(column = list(stacking = "normal")) %>%
      hc_drilldown(
        allowPointDrilldown = TRUE,
        series = c(Level_2_Drilldowns, Level_3_Drilldowns)
      )
  })

  output$trial <- renderText({input$ClickedInput})

}


shinyApp(ui, server)

Если по какой-то причине вам не нужно заранее собирать все детализированные данные, есть API для добавления детализированных данных на лету. Попробуйте поискать Highcharts и «addSeriesAsDrilldown». Однако я не уверен, что это доступно за пределами JavaScript.

14.03.2019
  • Спасибо, это работает! Я хотел бы, чтобы он добавлял детализацию на лету, так как мое реальное блестящее приложение будет иметь сотни возможных детализаций, и мне не нужно все ненужное вычислительное время. Я задам отдельный вопрос и отмечу ваш ответ как правильный, поскольку вы выполнили то, что было задано! Большое спасибо! 14.03.2019
  • Stackoverflow .com/questions/55168485/ на новый вопрос 14.03.2019
  • Новые материалы

    Создание кнопочного меню с использованием HTML, CSS и JavaScript
    Вы будете создавать кнопочное меню, которое имеет состояние наведения, а также позволяет вам выбирать кнопку при нажатии на нее. Финальный проект можно увидеть в этом Codepen . Шаг 1..

    Внедрите OAuth в свои веб-приложения для повышения безопасности
    OAuth — это широко распространенный стандарт авторизации, который позволяет приложениям получать доступ к ресурсам от имени пользователя, не раскрывая его пароль. Это позволяет пользователям..

    Классы в JavaScript
    class является образцом java Script Object. Конструкция «class» позволяет определять классы на основе прототипов с чистым, красивым синтаксисом. // define class Human class Human {..

    Как свинг-трейдеры могут использовать ИИ для больших выигрышей
    По мере того как все больше и больше профессиональных трейдеров и активных розничных трейдеров узнают о возможностях, которые предоставляет искусственный интеллект и машинное обучение для улучшения..

    Как построить любой стол
    Я разработчик программного обеспечения. Я люблю делать вещи и всегда любил. Для меня программирование всегда было способом создавать вещи, используя только компьютер и мое воображение...

    Обзор: Машинное обучение: классификация
    Только что закончил третий курс курса 4 часть специализации по машинному обучению . Как и второй курс, он был посвящен низкоуровневой работе алгоритмов машинного обучения. Что касается..

    Разработка расширений Qlik Sense с qExt
    Использование современных инструментов веб-разработки для разработки крутых расширений Вы когда-нибудь хотели кнопку для установки переменной в приложении Qlik Sense? Когда-нибудь просили..