timelyportfolio / dataui

data-ui for R
https://timelyportfolio.github.io/dataui/
Other
74 stars 5 forks source link

dui_for_reactable helper preventing flexdashboard from rendering reactable with sparkline #5

Closed ercbk closed 4 years ago

ercbk commented 4 years ago

RMarkdown script and supporting files are here. This is the reactable chunk,


# sparkline column for cases per 100k trend
cases_spark <- function(class = NULL, ...) {
      colDef(
            name = "Cases per 100K Trend",
            cell = dui_for_reactable(
                  dui_sparkline(
                        data = htmlwidgets::JS("cellInfo.value.cases_list"),
                        valueAccessor = htmlwidgets::JS("(d) => d.cases[0]"),
                        renderTooltip = htmlwidgets::JS(
                              htmltools::HTML(
                                    "function (_ref) {
                   var datum = _ref.datum;
                   return React.createElement(
                       'div',
                       {style: {margin: 0, padding: 0}},
                       datum.date && React.createElement(
                         'div',
                         {style: {
                           backgroundColor: 'black', color: 'white',
                           padding: '4px 0px', margin: 0, textAlign: 'center'
                         }},
                         // good reference https://observablehq.com/@mbostock/date-formatting
                         //   for built-in JavaScript formatting
                         //   but need to convert string to Date with new Date()
                         new Date(datum.date).toLocaleString(undefined, {
                          'month': 'numeric',
                          'day': '2-digit'
                        })
                       ),
                       React.createElement(
                         'div',
                         {style: {fontWeight: 'bold', fontSize: '1.2em', padding: '6px 0'}},
                         datum.y ? datum.y.toLocaleString(undefined, {maximumFractionDigits: 0}) : '--'
                       )
                   );
                  }"
                              )),
                        components = list(
                              dui_sparklineseries(
                                    showLine = FALSE,
                                    showArea = TRUE,
                                    fill = htmlwidgets::JS("cellInfo.original.cases_color"),
                                    fillOpacity = 0.6                              ),
                              dui_sparkpointseries(
                                    points = list("max"),
                                    fill = htmlwidgets::JS("cellInfo.original.cases_color"),
                                    stroke = htmlwidgets::JS("cellInfo.original.cases_color"),
                                    renderLabel = htmlwidgets::JS("(d) => d.toFixed(0)"),
                                    labelPosition = "left",
                                    size = 3
                              )
                        )
                  )
            )
      )
}

posrate_spark <- function(class = NULL, ...){
      colDef(
            name = "Positive Test Rate Trend",
            cell = function(value, index) {
                  if(is.null(value)) return(dui_sparkline())
                  dui_sparkline(
                        data = value[[1]],
                        valueAccessor = htmlwidgets::JS("(d) => d.posRate"),
                        renderTooltip = htmlwidgets::JS(
                           htmltools::HTML(
                              "function (_ref) {
                                 var datum = _ref.datum;
                                 return React.createElement(
                                     'div',
                                     {style: {margin: 0, padding: 0}},
                                    datum.endDate && React.createElement(
                                       'div',
                                       {style: {
                                         backgroundColor: 'black', color: 'white',
                                         padding: '4px 0px', margin: 0, textAlign: 'center'
                                       }},
                                       new Date(datum.endDate).toLocaleString(undefined, {
                                         'month': 'numeric',
                                         'day': '2-digit'
                                       })
                                    ),
                                    React.createElement(
                                       'div',
                                       {style: {fontWeight: 'bold', fontSize: '1.2em', padding: '6px 0'}},
                                       datum.y ? datum.y.toLocaleString(undefined, {maximumFractionDigits: 0, style: 'percent'}) : '--'
                                    )
                                 );
                              }"
                           )
                        ),
                        components = list(
                              # dui_sparkpatternlines(
                              #    id = "band_pattern_misc",
                              #    height = 4,
                              #    width = 4,
                              #    stroke = posrate_col[index],
                              #    strokeWidth = 1,
                              #    orientation = list('diagonal')
                              # ),
                              # dui_sparkbandline(
                              #    band = list( from = list( y = 0 ), to = list( y = 0.05 ) ),
                              #    fill = "url(#band_pattern_misc)"
                              # ),
                              dui_sparklineseries(
                                    stroke = posrate_col[index]
                              )
                        )
                  )
            }
      )
}

reactable(
      data = react_dat,
      borderless = TRUE,
      style = list(fontSize = "18px"),
      defaultPageSize = 5,
      defaultSortOrder = "desc",
      defaultSorted = "cases_100k",
      defaultColDef = colDef(
            align = "center",
            headerStyle = "align-self: flex-end; font-weight:normal;"
      ),
      rowStyle = list(
            alignItems = "center",
            # add back border here
            borderBottom = "1px solid lightgray"
      ),
      highlight = TRUE,
      columns = list(
            cases_color = colDef(show = FALSE),
            # pos_color = colDef(show = FALSE),
            msa = colDef(
                  name = "Metropolitan Statistical Area"
            ),
            cases_100k = colDef(
                  name = "Cases per 100K",
            ),
            pos_rate = colDef(
                  name = "Positive Test Rate",
                  na = "–",
                  format = colFormat(percent = TRUE, digits = 1)
            ),
            # casesList = cases_spark(),
            # posList = posrate_spark(),
            casesList = colDef(show = FALSE),
            posList = colDef(show = FALSE)
      )
) %>% 
      dui_add_reactable_dep()

I have two sparkline columns in my reactable. casesList uses the dui_for_reactable helper and posList (currently) does not. The dui_add_reactable_dep does seem to be necessary whether the dui_for_reactable function is used or not. The chunk inside the Rmd does render with both sparkline columns. The rendering problem only happens when the Rmd is knitted.

With posList and dui_add_reactable_dep dash-pos-duidep

With caseList and dui_add_reactable_dep dash-cases-duidep

current session info ```r - Session info --------------------------------------------------------------------------- setting value version R version 3.6.2 (2019-12-12) os Windows 10 x64 system x86_64, mingw32 ui RStudio language (EN) collate English_United States.1252 ctype English_United States.1252 tz America/New_York date 2020-07-23 - Packages ------------------------------------------------------------------------------- package * version date lib source assertthat 0.2.1 2019-03-21 [1] CRAN (R 3.6.2) cli 2.0.2 2020-02-28 [1] CRAN (R 3.6.3) crayon 1.3.4 2017-09-16 [1] CRAN (R 3.6.2) crosstalk 1.1.0.1 2020-03-13 [1] CRAN (R 3.6.3) digest 0.6.25 2020-02-23 [1] CRAN (R 3.6.2) dplyr * 1.0.0 2020-05-29 [1] CRAN (R 3.6.3) ellipsis 0.3.0 2019-09-20 [1] CRAN (R 3.6.2) evaluate 0.14 2019-05-28 [1] CRAN (R 3.6.1) fansi 0.4.1 2020-01-08 [1] CRAN (R 3.6.2) flexdashboard 0.5.1.1 2018-06-29 [1] CRAN (R 3.6.1) generics 0.0.2 2018-11-29 [1] CRAN (R 3.6.2) glue 1.4.1 2020-05-13 [1] CRAN (R 3.6.3) hms 0.5.3 2020-01-08 [1] CRAN (R 3.6.2) htmltools 0.5.0 2020-06-16 [1] CRAN (R 3.6.3) htmlwidgets 1.5.1 2019-10-08 [1] CRAN (R 3.6.1) jsonlite 1.7.0 2020-06-25 [1] CRAN (R 3.6.3) knitr 1.28 2020-02-06 [1] CRAN (R 3.6.2) leaflet 2.0.3 2019-11-16 [1] CRAN (R 3.6.3) lifecycle 0.2.0 2020-03-06 [1] CRAN (R 3.6.3) magrittr 1.5 2014-11-22 [1] CRAN (R 3.6.2) pacman 0.5.1 2019-03-11 [1] CRAN (R 3.6.2) pillar 1.4.3 2019-12-20 [1] CRAN (R 3.6.2) pkgconfig 2.0.3 2019-09-22 [1] CRAN (R 3.6.2) purrr 0.3.3 2019-10-18 [1] CRAN (R 3.6.2) R6 2.4.1 2019-11-12 [1] CRAN (R 3.6.2) Rcpp 1.0.4.6 2020-04-09 [1] CRAN (R 3.6.3) readr 1.3.1 2018-12-21 [1] CRAN (R 3.6.2) renv 0.9.3-30 2020-02-22 [1] Github (rstudio/renv@916923a) rlang 0.4.7 2020-07-09 [1] CRAN (R 3.6.3) rmarkdown 2.1 2020-01-20 [1] CRAN (R 3.6.2) rstudioapi 0.11 2020-02-07 [1] CRAN (R 3.6.2) sessioninfo 1.1.1 2018-11-05 [1] CRAN (R 3.6.2) tibble 3.0.0 2020-03-30 [1] CRAN (R 3.6.2) tidyselect 1.1.0 2020-05-11 [1] CRAN (R 3.6.3) vctrs 0.3.2 2020-07-15 [1] CRAN (R 3.6.2) withr 2.1.2 2018-03-15 [1] CRAN (R 3.6.1) xfun 0.12 2020-01-13 [1] CRAN (R 3.6.2) yaml 2.2.1 2020-02-01 [1] CRAN (R 3.6.2) [1] C:/Users/tbats/Documents/R/Projects/Indiana-COVIDcast-Dashboard/renv/library/R-3.6/x86_64-w64-mingw32 [2] C:/Users/tbats/AppData/Local/Temp/Rtmp88qPaq/renv-system-library ```


timelyportfolio commented 4 years ago

@ercbk would it be possible to look at developer tools in Chrome or Firefox (usually CTRL + Shift + J or F12) and let me know if you see any errors in the JavaScript console?

ercbk commented 4 years ago

@timelyportfolio That was weird. I opened the dashboard in Chrome, inspected, and couldn't find any errors or anything. Then, I decided to change the size of the inspect window which shrank the dashboard window, and the reactable with casesList sparkline appeared. Expanded it back out to full screen and it stayed. Did the same inside the RStudio viewer and the same thing happened.

timelyportfolio commented 4 years ago

@ercbk flexdashboard does a lot of things behind the scenes that can make the outcome very unpredictable. This appears to be a sizing/resizing issue and not a dataui issue.

For reference, the dui_add_reactable_dep() should only be necessary when using dui_for_reactable.

ercbk commented 4 years ago

Hmmph. Loading doesn't seem to be a problem if you go to the dashboard directly
https://ercbk.github.io/Indiana-COVIDcast-Dashboard/#dashboard
But if you start on the Home/About page and then to the dashboard, it doesn't load initially and requires a refresh.
https://ercbk.github.io/Indiana-COVIDcast-Dashboard/
I was worried, but this shouldn't be much of a problem. The only home page link that I've posted is on the github page and I can change that. Should be rare that anyone comes across it.

timelyportfolio commented 4 years ago

@ercbk we can force trigger a resize on tab change. I'll try to demo in a little bit.

timelyportfolio commented 4 years ago

@ercbk I think the issue might be the below error preventing the reactable rendering, or the reactable is not rendering because the tab is hidden.

image

Regardless of the reason, I think we can fix the reactable not-rendering-problem by adding the following JavaScript maybe around line. This will only re-render found htmlwidgets that have not yet been rendered (see staticRender code).

<script>
  $(document).on('shown.bs.tab',function() { HTMLWidgets. staticRender() })
</script>
ercbk commented 4 years ago

Yep, that seems to have done the trick. Thank you