Giter VIP home page Giter VIP logo

d3tablefilter's Introduction

title author date output vignette
D3TableFilter Intro
Thomas Siegmund
2017-11-17
rmarkdown::html_vignette
%\VignetteIndexEntry{Vignette Title} %\VignetteEngine{knitr::rmarkdown} \usepackage[utf8]{inputenc}

News

2017-11-17 Resizable columns

As the current version of TableFilter does not allow interactive resizing of columns, this functionality has been restored using the jQuery plugin colResizable. . There are many options to configure this behaviour. See below and in the resizing test app for details.

2017-11-05 Switch to D3 version 4.

To allow for compatibility with widgets using different versions of D3, the included D3 libraries have been upgraded to version 4 in an own namespace d3tf. As a result this widget can be combined with any other widget using D3 again, at the cost of some code changes. D3 code used for coloring and styling of table columns need to call d3 functions as d3tf. It may also need to be ported to v.4 syntax. d3.scale.linear for example has to be changed into d3tf.scaleLinear. See Changes in D3 4.0 for more information.

  • TableFilter v0.6.2

2016-11-27 Update of included libraries:

  • TableFilter v0.4.15 This is a major update of TableFilter, resulting in an API change in D3TableFilter. TableFilter extensions now have to be specified as lists - see the feature app for a complete example. Sorting and column operations now also are TableFilter extensions. Interactive column resizing is currently not supported in TableFilter.

  • jquery update to version 1.12.4 to match the version included in Shiny

  • Bootstrap update to match the version included in Shiny

Overview

TableFilter (TableFilter) by Max Guglielmi is a JavaScript library to enhance HTML tables. It it provides a number of useful features:

  • Advanced filtering
    • numeric (> 0)
    • logical (black || white)
    • regular expressions
  • Sorting
  • Pagination
  • Column visibility

The R package D3TableFilter packages the TableFilter JavaScript library as an easy to use widget for Shiny. It can be used in RStudio and in Shiny applications. The package is based on the htmlwidgets library which allows to integrate JavaScript libraries into R and Shiny.

In addition to the impressive feature set of the TableFilter library the D3TableFilter R widget provides some additional functions:

  • Filters can be set within the widget but also via R functions. Filter settings and filter results can be retrieved from the widget for use on the server.

  • Row selection. Single cell selection (radiobutton like) or multiple row selection using the ctrl key is possible. Selection can also be set or reset by the server.

  • Editing. The tableFilter widget can provide simple table editing features. Via a custom shiny input element each editing event in the table gets sent to the shiny app. After server side validation feedback can be given to the user within the widget. Logical columns can be presented as radio boxes or as checkbox input elements. It should be noted though that Max provides an extension ezEditTable which gives more extensive editing capabilities. Since ezEditTable is not free software it is out of the scope of D3TableFilter.

  • Coloring. Similar to conditional formatting in spreadsheet applications text and cell background can be colorized based on cell values. The D3.js visualization library is used to generate smooth colour scales. This allows for a broad range of available scales.

    • linear
    • logarithmic
    • threshold
    • categorical
    • ColorBrewer
    • ...
  • Cell styling and in-cell graphics. Can format text or turn cell values into SVG graphics using D3.js functions.

  • Sparklines. Small graphs in table cells can be generated using the integrated jQuery Sparkline library.

  • Cross-widget interactions (linked selection and filtering) via crosstalk.

Thanks to the shinyapps.io service you can test various features of the D3TableFilter widget in a couple of demo apps online:

Installation

D3TableFilter is not yet on CRAN, but you can easily install it from Github using the devtools package:

install.packages("devtools")
devtools::install_github("ThomasSiegmund/D3TableFilter")

First steps

Generating a table with filtering and sorting options in a Shiny app using the tableFilter library is very simple. First your have to declare a d3tfOutput in your user interface definition. In server.R or the shinyServer you define the corresponding output function. The d3tf function needs only one argument: df, the data.frame or matrix which will be transformed into a html table.

Optionally the tableProps argument can be used to define the look and feel of the table. In the example below, a very simple table is generated.

# --------------------------------------------------------
# Minimal shiny app demonstrating the D3TableFilter widget

library(shiny)
library(htmlwidgets)
library(D3TableFilter)
data(mtcars)

# ui.R
# --------------------------------------------------------
ui <- shinyUI(fluidPage(
  title = 'Basic usage of D3TableFilter in Shiny',
  fluidRow(
    column(width = 12, d3tfOutput('mtcars'))
  )
))

# server.R
# --------------------------------------------------------
server <- shinyServer(function(input, output, session) {
  output$mtcars <- renderD3tf({
    
    # Define table properties. See http://tablefilter.free.fr/doc.php
    # for a complete reference
    tableProps <- list(
      btn_reset = TRUE,
      # alphabetic sorting for the row names column, numeric for all other columns
      col_types = c("string", rep("number", ncol(mtcars)))
    );
    
    d3tf(mtcars,
         tableProps = tableProps,
         extensions = list(
           list(name = "sort")
         ),
         showRowNames = TRUE,
         tableStyle = "table table-bordered");
  })
})


runApp(list(ui=ui,server=server))

An optional parameter for tableFilter, showRowNames enables the display of the row names as first column.

Running this app generates a html table which can be filtered for strings, numbers, numeric expressions and regular expressions. There is a reset button for the filters in the upper right corner, and small help popup behind the question mark also in the upper right. The table can be sorted by mouseclick on the column headers.

Getting and setting filters

As an app developer you may want to know which filters a user has set, e.g. to provide statistics on the filtered rows or to allow for an export of the filtered data. If activated using filterInput = TRUE as argument to d3tf there is for each table an input called outputid + "_filter" which provides a list of

  • the filters entered by the user
  • an index of the table rows visible after filtering

This variation of the above app prints the current filter settings and the valid rows after filtering:

# --------------------------------------------------------
# Minimal shiny app demonstrating the D3TableFilter widget
# server.R
# --------------------------------------------------------
library(shiny)
library(htmlwidgets)
library(D3TableFilter)

data(mtcars);

shinyServer(function(input, output, session) {
  output$mtcars <- renderD3tf({
    
    # Define table properties. See http://tablefilter.free.fr/doc.php
    # for a complete reference
    tableProps <- list(
      btn_reset = TRUE,
      # alphabetic sorting for the row names column, numeric for all other columns
      col_types = c("string", rep("number", ncol(mtcars)))
    );
    
    observe({
      if(is.null(input$mtcars_filter)) return(NULL);
      
      filterSettings <-input$mtcars_filter$filterSettings;
      tmp <- lapply(filterSettings,
                  function(x) data.frame(Column = x$column,
                                         Filter = x$value, stringsAsFactors = FALSE));
      filters <- do.call("rbind", tmp);
      
      print("Active filters:")
      print(filters)
      
      rowIndex <- unlist(input$mtcars_filter$validRows);
      print("Valid rows:")
      print(mtcars[rowIndex, ]);
      
    })
    
    d3tf(mtcars,
         tableProps = tableProps,
         extensions = list(
           list(name = "sort")
         ),
         showRowNames = TRUE,
         filterInput = TRUE,
         tableStyle = "table table-bordered");
  })
})

TableFilter has a cookie based mechanism to restore filter settings after page reload (remember_grid_values = TRUE in tableProps). Alternatively you could restore filter settings by using the initialFilters argument.

d3tf(mtcars, showRowNames = TRUE, initialFilters = list(col_0 = "Merc", col_1 = ">20"));

Filters can be set programmatically at run time using the setFilter() function. There is also a clearFilters function to reset all filter inputs in a table. The examples/interaction Shiny app demonstrates these functions.

Customizing the table

The Table Filter JavaScript library provides a huge number of configuration options which define the appearance and behaviour of the table. It can for example do client side paging. It can provide a control to hide selected columns. It can provide checkbox and lists controls for filtering and many more. A complete discussion of the features of Table Filter is beyond the scope of this document. Please see TableFilter for examples and documentation. In the examples/feature directory of this package is a Shiny app demonstrating quite a few TableFilter features in a single table. It shows sorting, filtering, pagination, rows counter, column visibility, and a table footer with column statistics.

TableFilter extensions

Some of the TableFilter functions are beeing provided as separate modules, in particular

  • Sorting
  • ColsVisibility: Visibility of columns can be adjusted by configuration or interactively
  • FiltersRowVisibility: Interactively show or hide the filter row.

To activate these extensions simply define them as a list in the extensions parameter, e.g.

    extensions <-  list(
        list(name = "sort"),
        list( name = "colsVisibility",
              at_start =  c(8, 9, 10, 11),
              text = 'Hide columns: ',
              enable_tick_all =  TRUE
             ),
        list( name = "filtersVisibility",
              visible_at_start =  TRUE)
      );

This takes care of enabling and configuration of the extensions.

Sorting

On click on column headers TableFilter sorts the table. It can sorted by string, various number formats number, eu, us, different date formats dmydate, mdydate, ymddate, ddmmmyyyy', and by 'ipaddress'. Sorting of specific columns can be defined in the tableProps argument:

  tableProps <- list(
      # sort first column by character, second by US number format,
      # third column by date format 08/05/2010 
      col_types = c("string", "number", "mdydate") 
  )

Additionally the sort extension has to be loaded:

  extensions <- list(
           list(name = "sort")
         )
  
    d3tf(x,
         tableProps = tableProps,
         extensions = extensions
         )

The TableFilter documentation has some more details about sorting. D3TableFilter extends the list of sort types by the Mixed type. This function is based on the mixedorder function from the gtools package. It allows to sort character strings containing numbers in a logical order. See the examples/mixedsort Shiny app for an example.

Interactive table resizing

In previous versions TableFilter had a pluging for column resizing using mouse interaction. Currently this is not supported in TableFilter. D3TableFilter now includes the jQuery colResizable plugin to support this feature.

Bootstrap styling

TableFilter comes with its own CSS based default styling which is compact and efficient, but can look a little bit out of place within Bootstrap styled Shiny apps. Per default D3TableFilter applies the basic Bootstrap table class (table). This behaviour can be modified using the tableStyle argument. Bootstrap provides the classes table, table-striped, table-bordered, and table-condensed. These classes can be combined, e.g. tableStyle = "table table-striped table-bordered". tableStyle = NULL reverts to the original TableFilter CSS.

Table Footer

TableFilter provides functions for statistical summaries in a table footer (see col_operation in the TableFilter documentation. D3TableFilter supports this by providing the footData argument to d3tf. It allows to attach one or more rows to a table to be used as footer. The TableFilter col_operation functions need cells with unique id to display their results. D3TableFilter supports this by supplying a unique id for each cell in a footer. The cell at the first footer row, second column in a table "mtcars" would get the id frow_0_fcol_1_tbl_mtcars. See the examples/feature Shiny app for an example.

Alternatively to these values calculated by JavaScript the data for a table footer can be supplied directly from R via the footData argument. These can be updated dynamically using the setFootCellValue function. An example for this can be found in the examples/interaction Shiny app. Here the footer row shows column mean or column median values depending on a select input:

  # update summary row. calculate mean/median of displayed row for cols 1:3
  observe({
    for (col in c(1, 2, 3)) {
      if(input$summaryRow == "mean") {
        setFootCellValue(session, tbl = "mtcars", row = 1, col = 0, value = "Mean");
        value = round(mean(revals$mtcars[revals$rowIndex, col]), 1);
      } else {
        setFootCellValue(session, tbl = "mtcars", row = 1, col = 0, value = "Median");
        value = round(median(revals$mtcars[revals$rowIndex, col]), 1);
      }
      setFootCellValue(session, tbl = "mtcars", row = 1, col = col, value = value);
    }
  })

Editing

Using the edit argument to d3tf the whole table (edit = TRUE) or selected columns (edit = c("col_1", "col_3")) can set to be editable. Table columns with logical values can be transformed into radio buttons or checkboxes for easy editing. It is also possible to enable or disable editing of columns dynamically:

# enable editing of the first two columns of the "mtcars" table
enableEdit(session, "mtcars", c("col_1", "col_2"))

# disable editing of the first two columns of the "mtcars" table
disableEdit(session, "mtcars", c("col_1", "col_2"))

An editable table provides an input element named like the corresponding output element + "_edit". For performance reasons not the complete edited table is sent back from the browser to the server, but single edit events. The _edit input element receives for each edit element in the corresponding table a list of row (row), column (col) and new value (val).

Within a Shiny app here an observe function should take care of validation and processing of these data. D3TableFilter provides two functions to send validation feedback to the user (confirmEdit, rejectEdit). They allow to give visual feedback by means of a brief text colour transition. They also allow to revert the edit in case of a validation failure or to rewrite the value in case of a confirm.

Rewriting a validated edit may seem unneccessary at first, but it could help in case of difficult network conditions. Depending on the environment there is no guarantee that edit events in the browser get processed in the correct order on the server. If a user starts to edit a cell, waits briefly, and then continues to edit the same cell two edits could be sent back to the server. There is no guarantee that the second edit arrives after the first one on the server. Thus in D3TableFilter each edited cell gets tagged with a unique attribute and which is checked when the server sends a reject or confirm message. Only a confirm or reject message corresponding to the latest edit of a cell will find a matching id in the table.

  # For a output object "mtcars" D3TableFilter generates an input "mtcars_edit".
  #
  # This observer does a simple input validation and sends a confirm or reject message
  # after each edit.
  observe({
    if(is.null(input$mtcars_edit)) return(NULL);
     edit <- input$mtcars_edit;
    
    isolate({
      # need isolate, otherwise this observer would run twice
      # for each edit
      id <- edit$id;
      row <- as.integer(edit$row);
      col <- as.integer(edit$col);
      val <- edit$val;
      
      # validate input 
      if(col == 0) {
        # rownames
        oldval <- rownames(revals$mtcars)[row];
        # rownames can not start with a digit
        if(grepl('^\\d', val)) {
          rejectEdit(session, tbl = "mtcars", row = row, col = col,  id = id, value = oldval);
          return(NULL);
        }
      } else if (col %in% c(1, 2, 3)){
        # numeric columns
        if(is.na(suppressWarnings(as.numeric(val)))) {
          oldval <- revals$mtcars[row, col];
          # reset to the old value
          # input will turn red briefly, than fade to previous color while
          # text returns to previous value
          rejectEdit(session, tbl = "mtcars", row = row, col = col, id = id, value = oldval);
          return(NULL);
        } 
      }
      
      # accept edits
      if(col == 0) {
        rownames(revals$mtcars)[row] <- val;
      } else if (col %in% c(1, 2, 3)) {
        revals$mtcars[row, col] <- as.numeric(val);
        val = round(as.numeric(val), 1)
      }
      # confirm edits
      confirmEdit(session, tbl = "mtcars", row = row, col = col, id = id, value = val);
     })
   })

Cell values can also be updated dynamically by the server without resending the whole table using the setCellValue() function. If a table uses coloring or inline graphics, these elements can react on edit events with smooth visual transitions. See examples/interaction for a Shiny app demonstrating this features.

Row selection

A D3TableFilter table can act as a simple input element for row selection. The selectableRows argument to the d3tf function makes single or multiple rows selectable. Using the selectableRowsClass argument you can use a choice of Bootstrap classes to modify the look of selected rows. A new input element (named like the corresponding output element + "_edit") will provide a vector of indices of selected rows. To pre-select rows when generating a new table, the "rowStyles" argument to d3tf() can be used. At run time rows can be (de-)selected using the setRowClass() function.

Technically selectableRows can be combined with other D3TableFilter features. From a user point of view it may be confusing though to have selected rows which are hidden by the filtering function. Thus it may be a good idea to switch off filtering in this case using enableTf = FALSE. An example for a table with selectable rows is on the second tab of the examples/interaction Shiny app:

Coloring

Color can greatly enhance the perception especially of numerical values in tables. One of the driving forces in the development of D3TableFilter was the need for smooth, heatmap-like colors in tables. The D3.js library provides powerful mechanisms to map data to colors. I has support for simple linear color scales, but also logarithmic scales and ordinal scales (including the famous ColorBrewer scales). D3TableFilter allows to make use of this for cell backgrounds as well as for the text color. D3TableFilter tries to provide the full D3.js tool set for colour scales, at the cost of exposing R programmers to the D3 javascript code. The following code sniplet for example could be used to colour cell the second column (col_1) in a table. Given a range of cell values between 0 and 200 (.domain([0, 200])) the cell background would be colored in white to blue (.range(["white", "blue"])) according to the cells numeric value. To enable compatibiltiy wiht widgets using other versions of D3, the bundled package has it's own namespace (d3tf).

    bgColScales <- list(
       col_1 = JS('function colorScale(tbl, i){
        var color = d3tf.scale.linear()
                      .domain([0, 200])
                      .range(["white", "blue"]);
        return color(i);
      }')
      )

In this example the background color may get to dark to read the cell text. One solution obviously is to use a lighter background color. Another option is to modify the text color accordingly. The next code sniplet achives this by using a threshold function (d3tf.scale.threshold()) to switch the text color from black to white on a dark background.

   fgColScales <- list(
      col_1 = JS('function colorScale(tbl, i){
        var color = d3tf.scale.threshold()
        .domain([130, 130, 200.1])
        .range(["black", "black", "white"]);
        return color(i);
      }')
      )

The result in shown in the second column in the table below.

Color perception is a complex issue. If you wish for a perceptionally correct mapping of numerical data to colour a linear scale as shown above is not the best solution. D3.js provides Lab and HCL color scales for this purpose. They make sure the perceived difference between two colors is propotional to the distance of the mapped values. The next code sniplet maps the same data as above to a white-blue palette in HCL space. The results is shown in the third column in the figure above.

    bgColScales <- list(
       col_2 = JS('function colorScale(tbl, i){
        var color = d3tf.scale.linear()
        .domain([0, 200])
        .range(["white", "blue"])
        .interpolate(d3tf.interpolateHcl);
        return color(i);
      }')
      )

As a shortcut you can define linear hcl scales as automatic. The data range (domain in D3 parlance) is determined automatically in this case.

    bgColScales <- list(
     col_0 = "auto:white:green"
    )

Examples for different color scales can found in the examples/colour Shiny app.

D3 cell styling

While the TableFilter library provides many features to modify the appearance of various table elements using CSS, it does not support directly the styling and formatting of text in table cells. You can not, for example, generate right aligned numeric columns using TableFilter alone. D3TableFilter allows this, similar to the color mapping, by use of D3. The cellFunctions and footCellFunctions argument to d3tf() apply D3 JavaScript code to columns in the table body or footer. The code below will make the first column (col_0) in a table footer right aligned classed("text-right", true), bold .style("font-weight", "bold")and formatted with one decimal point d3tf.format(".1f"). D3 has formatters for numbers and dates.

    # apply D3.js functions to footer columns,
    # e.g. to format them or to turn cell values into scaled SVG graphics
    footCellFunctions <- list(
      col_0 = JS('function makeGraph(selection){
                // text formatting function
                var textformat = d3tf.format(".1f");
                // make cell text right aligned
                selection.classed("text-right", true)
                         .style("font-weight", "bold")
                         .text(function(d) { return textformat(d.value); });
            }')
    );

While the example is an serious application of D3 to generate good looking an correctly formatted tables, the following section is on the border of eye candy (or maybe a little bit beyond).

The cellFunctions argument can be used not only to format numbers, but to turn them into SVG graphics within a cell. The following code replaces numbers in the third column (col_2) into SVG filled circles. The area of the circles is scaled proportional to the numeric values. Finally the numbers are shown centered inside the circles.

    cellFunctions <- list(
      col_2 = JS('function makeGraph(selection){
      
        // find out wich table and column
        var regex = /(col_\\d+)/;
        var col = regex.exec(this[0][0].className)[0];
        var regex = /tbl_(\\S+)/;
        var tbl = regex.exec(this[0][0].className)[1];
  
        // create a scaling function
        var domain = colExtent(tbl, col);
        var rScale = d3tf.scale.sqrt()
                       .domain(domain)
                       .range([8, 14]);

        // column has been initialized before, update function
        if(tbl + "_" + col + "_init" in window) {
            var sel = selection.selectAll("svg")
                     .selectAll("circle")
                     .transition().duration(500)
                     .attr("r", function(d) { return rScale(d.value)});
                     return(null);
        }

        // remove text. will be added later within the svg
        selection.text(null)

        // create svg element
        var svg = selection.append("svg")
              .attr("width", 28)
              .attr("height", 28);
              
        // create a circle with a radius ("r") scaled to the 
        // value of the cell ("d.value")
        var circle = svg.append("g")
              .append("circle").attr("class", "circle")
              .attr("cx", 14)
              .attr("cy", 14)
              .style("fill", "orange")
              .attr("stroke","none")
              .attr("r", domain[0])
              .transition().duration(400)
              .attr("r", function(d) { return rScale(d.value); }); 

        // place the text within the circle
        var text = svg.append("g")
              .append("text").attr("class", "text")
              .style("fill", "black")
              .attr("x", 14)
              .attr("y", 14)
              .attr("dy", ".35em")
              .attr("text-anchor", "middle")
              .text(function (d) { return d.value; });
        window[tbl + "_" + col + "_init"] = true;

      }')
    )

Surprisingly sorting and filtering based on the numbers still works as before. The examples/interaction Shiny app demonstrates this.

The examples/interaction Shiny app also shows a second variation of in-cell graphics, a horizontal bar chart. Here the text is not replaced, but overlayed to the graphic and can be edited. Enjoy smooth D3 transitions of the bar charts while editing the numbers!

    # apply D3.js functions to a column,
    # e.g. to turn cell values into scaled SVG graphics
    cellFunctions <- list(
      col_3 = JS('function makeGraph(selection){

        // find out wich table and column
        var regex = /(col_\\d+)/;
        var col = regex.exec(this[0][0].className)[0];
        var regex = /tbl_(\\S+)/;
        var tbl = regex.exec(this[0][0].className)[1];
        var innerWidth = 117;
        var innerHeight = 14;
        
        // create a scaling function
        var max = colMax(tbl, col);
        var min = colMin(tbl, col);
        var wScale = d3tf.scale.linear()
                       .domain([0, max])
                       .range([0, innerWidth]);

        // text formatting function
        var textformat = d3tf.format(".1f");

        // column has been initialized before, update function
        if(tbl + "_" + col + "_init" in window) {
            var sel = selection.selectAll("svg")
                     .selectAll("rect")
                     .transition().duration(500)
                     .attr("width", function(d) { return wScale(d.value)});
            var txt = selection
                        .selectAll("text")
                        .text(function(d) { return textformat(d.value); });
           return(null);
        }
        
        // can remove padding here, but still cant position text and box independently
        this.style("padding", "5px 5px 5px 5px");

        // remove text. will be added back later
        selection.text(null);

        var svg = selection.append("svg")
              .style("position",  "absolute")
              .attr("width", innerWidth)
              .attr("height", innerHeight);

        var box = svg.append("rect")
                     .style("fill", "lightblue")
                     .attr("stroke","none")
                     .attr("height", innerHeight)
                     .attr("width", min)
                     .transition().duration(500)
                     .attr("width", function(d) { return wScale(d.value); });

        // format number and add text back
        var textdiv = selection.append("div");
                          textdiv.style("position",  "relative")
                                 .attr("align", "right");

        textdiv.append("text")
                 .text(function(d) { return textformat(d.value); });
        window[tbl + "_" + col + "_init"] = true;
      }')
    );

Sparklines

Defined by Edward Tufte as data-intense, design-simple, word-sized graphs, sparklines can convey a high amount of information in very little space. The jQuery Sparklines library allows to generate beautiful sparlines in a web page with little effort. D3TableFilter includes jQuery Sparklines. Sparkline expects a comma separated series of numbers as input values, e.g. "1,3,5,7,11". To turn a column of such values into a column of small line charts in D3TableFilter, is as simple as to generate a sparklines configuration and to hand this over to the d3tf function:

    # define four different sparklines for four columns
    sparklines = list(col_0 = list(  type = "line",
                                     width = "120px",
                                     height = "24px",
                                     lineColor = "black",
                                     fillColor = FALSE,
                                     spotColor = "#F8766D",
                                     minSpotColor = "#00BFC4",
                                     maxSpotColor = "#00BFC4",
                                     spotRadius = 2,
                                     normalRangeMax = 15,
                                     normalRangeMin = -15,
                                     normalRangeColor = "#E7E8EA"
                                   ),
                      col_1 = list(  type = "bar",
                                     barColor = "#00BFC4",
                                     negBarColor = "#F8766D",
                                     width = "120px",
                                     height = "24px"
                                   ),
                      col_2 = list(  type = "box",
                                     width = "120px",
                                     height = "24px"
                                  ),
                      col_3 = list(type = "tristate",
                                     posBarColor = "#00BA38",
                                     negBarColor = "#F8766D",
                                     width = "120px",
                                     height = "24px"
                                   )
                      )
                      
d3tf(tbl, sparklines = sparklines);

jQuery Sparklines provides several different types of graphs (line graphs, bar graphs, pie charts, tristate graphs, boxplots...) and many configuration options. Examples of some different graph types can found in the examples/sparklines Shiny app in this package. For a complete documentation of sparkline options see the jQuery Sparklines documentation.

d3tablefilter's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

d3tablefilter's Issues

Scrollbar

I'm not sure how to manipulate the aesthetics of the table. I have a really large dataset with lots of rows and columns. I'd like to put it into a smaller panel and have a table X & Y scroll bar. Imagine putting a large table into a shinydashboard "box".

Currently the d3tfOutput height/width is ignored if the table can't fit entirely. Instead it would be nice if the table was compressed into the desired form-factor and a scroll bar was added so that the entire table can be viewed.

I've tried a lot of different approaches, but no matter what my table is just too large and the user has to use the web-page scroll bars to explore the table. Makes for a very ugly application that doesn't play well with other elements.

Any advice?

Filtered table not rendering

I've installed D3TableFilter from the Github .zip, and have been able to launch the very first table example using mtcars in RStudio, as listed in the Github documentation.

However, when I type filter criteria into the boxes above any of the columns, the table does not update to render the filtered version. Am I missing a step in visualising the filtered output, or should the table update automatically?

paging_length doesn't work

Hi, Great package.

For some reason, the paging_length doesn't work. Following is a minimal example. You can also use the example "performance" provided in the examples coming with the package.

library(shiny)
library(htmlwidgets)
library(D3TableFilter)

data(mtcars);

ui <- fluidPage(
title = 'Basic usage of D3TableFilter in Shiny',
fluidRow(
column(width = 12, d3tfOutput('mtcars', height = "auto"))
)
)

server <- shinyServer(function(input, output, session) {
output$mtcars <- renderD3tf({

# Define table properties. See http://tablefilter.free.fr/doc.php
# for a complete reference
tableProps <- list(
  btn_reset = TRUE,
  paging = TRUE,
  paging_length = 5,
  results_per_page = JS("['Rows per page', [5, 20]]"),
    # alphabetic sorting for the row names column, numeric for all other columns
    col_types = c("string", rep("number", ncol(mtcars)))
);

d3tf(mtcars,
     tableProps = tableProps,
     extensions = list(
      list(name = "sort")
     ),
     showRowNames = TRUE,
     tableStyle = "table table-bordered");

})
})

runApp(list(ui = ui, server = server))

Accessing row data in Shiny

Firstly loving this package, the filters and edit-ability are much better than other table packages I have come across.

Secondly this is more of a question than an issue. I apologise if the answer is obvious or that I've missed it in the documentation, I'm fairly new to both this package and using shiny.

How would I go about accessing the information of a D3Table in Shiny?

For example if you were to use the DT package in shiny you could get info as follows:
in ui: dataTableOutput("x")
in server: input$x_rows_selected
This would return the row number, which you could use as an input for a function.

Similarly you can do the same with input$x_cell_clicked for the info within a specific cell.

So my question is is there an equivalent for this package as I am creating an app where once a row is selected the Row number is taken and entered into a function to create another table.

Thank you for the help.

ctrl + click doesn't work for mac systems

ctrl + click doesn't have allow for the same functionality on Mac as on window. I attempted this on the multiple row selection. cmd + click would be the alternative option for a mac but that doesn't seem to work.

add prebuilt `d3` layouts &| formatters &| behaviors

Certainly something that can be considered a future enhancement, but I think it would be really nice for less-JS knowledgeable R users to still be able to incorporate d3 into their widgets. Would it be possible to add some functions for some generalized d3 functionality that can be called on the R side.

Also, it would be really neat to allow sparklines from d3 or even sparkline from @ramnathv.

colVisibility extension not showing

I copied code from the tutorial into R and can't get the colVisibility filter to show up at all. I used this code to enable the extension:

library(shiny)
library(htmlwidgets)
library(D3TableFilter)

data(mtcars);

shinyServer(function(input, output, session) {
  output$mtcars <- renderD3tf({
    
    # Define table properties. See http://tablefilter.free.fr/doc.php
    # for a complete reference
    tableProps <- list(
      btn_reset = TRUE,
      # alphabetic sorting for the row names column, numeric for all other columns
      col_types = c("string", rep("number", ncol(mtcars)))
    );
    
    extensions <-  list(
      list(name = "sort"),
      list( name = "colsVisibility",
            at_start =  c(1,2,3,4,5),
            text = 'Hide columns: ',
            enable_tick_all =  TRUE
      ),
      list( name = "filtersVisibility",
            visible_at_start =  TRUE)
    );
    
    d3tf(mtcars,
         tableProps = tableProps,
         extensions = extensions,
         edit = TRUE,
         showRowNames = TRUE,
         tableStyle = "table table-bordered");
  })
})

I do not get the "Display columns" column filter at the top right. The code also doesn't seem to hide the columns (1,2,3,4,5) at start.

Pre-select of Rows

Hi Thomas,

Thank you again for your help with my previous question, really helped me out with my project.
I have another question regarding the 'pre-selection' of rows in a table.
I have managed to implement what I believe to be the correct method as rows are pre-selected when the table is generated. However I don't know how to/ seem to be able to work out how to make sure the first row of the table is selected.

Below is the code I have to render my table, using the rowStyles as suggested by documentaion for pre-selection of rows.

d3tf(y, tableProps = tableProps, edit = FALSE, selectableRows = 'single', extensions = extensions, rowStyles = c(rep("", 1), rep("info", 1)));

However this seems to pre-select the second row.
as shown:
d3tf row select

I'm sure this is another easy fix but again I haven't been able to find/ work out a solution based on the documentation. Any help with this would be greatly appreciated.

Thank you again for your help and for this great package!

No way to reset editions

Hi Thomas,

I find no way to reset editions from previous data when I change the data to use in the table. I would like to put again input$mtcars_edit=NULL every time I load new data to be used in the table of the interface.

I have tried to reset the input through shinyjs or to play with attr, but it doesn't work.

Is there any way to solve this problem? It is necessary to find a solution to be able to publish a shiny application using your package.

Kind regards,

Daniel

custom_slc_options

Is this customization from HTML table filter available for D3TableFilter?

Fixed Table Headers

Hello guys, I appreciate very much your work with D3. I would like to know if there is a way to lock or fix the header in a table?
Thank you so much,
David Valencia

Adapting examples/interaction

Hi, I absolutely love this package and the examples are also very helpful. Thank you for the great work.

I have a quick question regarding the examples/interaction where you generate an orange circle scaled to the cell value. Well, is there a way to apply the col_2 = JS('function makeGraph(... to multiple columns? The way I do it right now is to define col_3 = JS('function makeGraph(..., col_4=JS('function makeGraphy(... Instead of duplicating the codes after col_2 =, col_3 =, col_4 = etc, I wonder how to apply the same to all the columns at one go?

Any advice is greatly appreciated.

This example generates an orange circle scaled to the cell value.

# The number is part of the svg graphic, but still allows for sorting and filtering.
  cellFunctions <- list(
  col_2 = JS('function makeGraph(selection, tbl, col){

does not work in `static` mode

Maybe I'm confused, but I thought d3tf should work in both static and shiny modes. static currently does not work since jQuery is not available in this line.

I did confirm that static sort of works when the jQuery depedency is added. Here is an example. Of course, you'll want to add jQuery in the yaml if you want to pursue this.

library(D3TableFilter)
library(htmltools)
library(magrittr)

tagList(d3tf(mtcars,
     tableProps = tableProps,
     showRowNames = TRUE,
     tableStyle = "table table-bordered"
)) %>%
  attachDependencies(
    htmlDependency(
      name = "jquery"
      ,version = "1.11.2"
      ,src = c(href = "http://code.jquery.com/")
        ,script = "jquery-1.11.2.min.js"
    )
  ) %>%
  htmltools::html_print()

Please sort of disregard if static is not an option. However, I would strongly encourage that a widget work in all contexts.

Accessing user edits to D3 table

I am trying to understand the code in the filter example that is provided on the interaction shiny app, but I am still having trouble understanding how to access user edits to my d3tf Output.

I have a simple table that users can edit. I would like to be able to do calculations on the entered data, but I am not sure how to save the edits to the table from the server side of the R code. My table meals2() is the reactive dataframe that is being edited in the ui.R. My problem is that the code below does not show anything in the ui.R when I display output$filteredmeals3. (My first step towards using the edits as a calculation is to actually see the edits in a new table.)

Any help would be appreciated.

My server.R has

revals <- reactiveValues();
meals3=(reactive({
      meals3<-meals()
      meals3
  }))

revals$meals3 <- meals3;
revals$rowIndex <- 1:nrow(meals3);

observe({
  if(is.null(input$meals2_edit)) return(NULL);
  edit <- input$meals2_edit;



  isolate({
    # need isolate, otherwise this observer would run twice
    # for each edit
    id <- edit$id;
    row <- as.integer(edit$row);
    col <- as.integer(edit$col);
    val <- edit$val;

    # validate input 
    if(col == 0) {
      # rownames
      oldval <- rownames(revals$meals3)[row];
      # rownames can not start with a digit
      if(grepl('^\\d', val)) {
        rejectEdit(session, tbl = "meals3", row = row, col = col,  id = id, value = oldval);
        return(NULL);
      }
    } else if (col %in% c(1, 2, 3)){
      # numeric columns
      if(is.na(suppressWarnings(as.numeric(val)))) {
        oldval <- revals$meals3[row, col];
        # reset to the old value
        # input will turn red briefly, than fade to previous color while
        # text returns to previous value
        rejectEdit(session, tbl = "meals3", row = row, col = col, id = id, value = oldval);
        return(NULL);
      } 
    }

    # accept edits
    if(col == 0) {
      rownames(revals$meals3)[row] <- val;
    } else if (col %in% c(1, 2, 3)) {
      revals$meals3[row, col] <- as.numeric(val);
      val = round(as.numeric(val), 1)
    }
    # confirm edits
    confirmEdit(session, tbl = "meals3", row = row, col = col, id = id, value = val);
  })
})

output$filteredmeals3 <- renderTable({
  if(is.null(revals$rowIndex)) return(invisible());    
  if(is.null(revals$meals3)) return(invisible());
  revals$meals3[revals$rowIndex, ];
});

I get the following error
Error in 1:nrow(meals3) : argument of length 0

I can make edits to my table that is rendered by d3tf(meal2(),...) but I can't get the second edited table to display.

input$outputID_select inside a Shiny Module

Hello!
First of all, a word to say thank you for this awesome package @ThomasSiegmund , I'm now using it for my projects.

But I'm having some troubles with the tables generated by d3tablefilter (_select, _edit, _filter) when they are inside a Shiny module (even when I call them from inside the module).
I think it has to do with the namespace function and the output ID (since the final name is "input$" + "outputID" + "_table"...

Here is a reproducible example where the _select table is not updated when a new row is selected.
Do you have any ideas how to make it work ?

# d3tabModule.R

d3tabUI <- function(id) {
  ns <- NS(id)
  
  tagList(
    column(d3tfOutput(ns('mtcars')), width = 8),
    column(tableOutput(ns("mtcarsSelect")), width = 4)
  )
}

d3tab <- function(input, output, session, data) {
  
  output$mtcars <- renderD3tf({
    
    tableProps <- list(
      btn_reset = TRUE,
      rows_counter = TRUE,  
      rows_counter_text = "Rows: ",
      sort = TRUE,
      on_keyup = TRUE,  
      on_keyup_delay = 800,
      sort_config = list(
        sort_types = c("Number", "Number")
      ),
      filters_row_index = 1,
      rows_always_visible = list(nrow(mtcars) + 2),
      col_operation = list( 
        id = list("frow_0_fcol_1_tbl_mtcars","frow_0_fcol_2_tbl_mtcars"),    
        col = list(1,2),    
        operation = list("mean","mean"),
        write_method = list("innerhtml",'innerhtml'),  
        exclude_row = list(nrow(mtcars) + 2),  
        decimal_precision = list(1, 1)
      )
    );
    
    footData <- data.frame(Rownames = "Mean", mpg = 0, cyl = 0);
    
    d3tf(mtcars[ , 1:2],
         enableTf = TRUE,
         tableProps = tableProps,
         showRowNames = TRUE, 
         selectableRows = "multi",
         selectableRowsClass = "info",
         tableStyle = "table table-bordered table-condensed",
         rowStyles = c(rep("", 7), rep("info", 7)),
         filterInput = TRUE,
         footData = footData,
         height = 500);
  })
  
  # for a output object "mtcars" tableFilter generates an input
  # "mtcars_edit". 
  output$mtcarsSelect <- renderTable({
    if(is.null(input$mtcars_select)) return(NULL);
    mtcars[input$mtcars_select, 1:2];
  })
  
}
# app.R

library(shiny)
library(htmlwidgets)
library(D3TableFilter)

source("d3tabModule.R")


ui <- fluidPage(
  d3tabUI("d3tab")
)


server <- function(input, output) {
  callModule(d3tab, "d3tab", data(mtcars))
}


shinyApp(ui = ui, server = server)

Thank you,
cheers.

R 3.4.3 Compatibility?

It seems that the package is currently not compatible with R 3.4.3?

> install.packages("D3TableFilter")
Warning message:
packageD3TableFilteris not available (for R version 3.4.3)

Scrolling?

It seems the original table allows for an object: fixed_headers which allows for scrolling, has this been passed to this package? For very wide tables, I need to be able to scroll the page, but the html page that is born does not have scroll-bars enabled.

Fixed Header for the D3 table

Hi Thomas,

 I would like to first thank you for this amazing package. It is the only table I can find that allows edits. The advanced filters are also very handy.  However, is there a way to fix the header for the table or separate the table into multiple pages like the DT::datatables?

Thanks!
Allen

use `runApp( list( ui = ui, server = server) )` for examples

For the examples, especially those in the documentation, using this Shiny format might make it easier for a user to try or explore. Here is an example with the basic app.

# --------------------------------------------------------
# Minimal shiny app demonstrating the D3TableFilter widget

library(shiny)
library(htmlwidgets)
library(D3TableFilter)
data(mtcars)

# ui.R
# --------------------------------------------------------
ui <- shinyUI(fluidPage(
  title = 'Basic usage of D3TableFilter in Shiny',
  fluidRow(
    column(width = 12, d3tfOutput('mtcars'))
  )
))

# server.R
# --------------------------------------------------------
server <- shinyServer(function(input, output, session) {
  output$mtcars <- renderD3tf({

    # Define table properties. See http://tablefilter.free.fr/doc.php
    # for a complete reference
    tableProps <- list(
      btn_reset = TRUE,
      sort = TRUE,
      sort_config = list(
        # alphabetic sorting for the row names column, numeric for all other columns
        sort_types = c("String", rep("Number", ncol(mtcars)))
      )
    );

    d3tf(mtcars,
         tableProps = tableProps,
         showRowNames = TRUE,
         tableStyle = "table table-bordered");
  })
})


runApp(list(ui=ui,server=server))

Setting Column Width / Resizing Issue

Test.zip
This is a reproducible (at least on my end) example of what I was referring to in a previously closed issue. Two things are going on here on my data set (and not on the mtcars dataset) that are unusual, so I've attached the RDS file needed to be used in the following example code:

library(shiny)
library(htmlwidgets)
library(D3TableFilter)
data(Test)

# ui.R
# --------------------------------------------------------
ui <- fluidPage(
  titlePanel('Test app'),
  sidebarLayout(
    sidebarPanel(
      wellPanel(HTML(paste("D3TableFilter test app<br>Package version",
                           sessionInfo()$otherPkgs$D3TableFilter$Version)))
    ),
    mainPanel(
      br(),
      d3tfOutput('Test')
    )
  ))

# server.R
# --------------------------------------------------------
server <- shinyServer(function(input, output, session) {
  
  output$Test <- renderD3tf({
    
    # Define table properties. See http://tablefilter.free.fr/doc.php
    # for a complete reference
    tableProps <- list(
      btn_reset = TRUE,
      # alphabetic sorting for the row names column, numeric for all other columns
      #col_types = c("string", rep("number", ncol(WIPData))),
      alternate_rows = TRUE,
      col_0= 'select',col_1= 'select',col_2= 'select',
      col_widths = c('100px', '100px', '100px', '100px', '100px','100px', '100px', '100px', '100px', '100px','100px', '100px', '100px', '100px',
                     '700px','100px', '400px', '100px', '100px', '100px', '100px')
    );
    
    extensions <-  list(
      list( name = "colsVisibility",
            #at_start =  c(1,2,3,4,5),
            text = 'Hide Columns: ',
            enable_tick_all =  TRUE
      ),
      list(name = "sort"),
      list( name = "filtersVisibility",
            visible_at_start =  TRUE)
    );
    
    
    #colsResizableOpts <- list(resizeMode = "flex",
    #                          liveDrag = TRUE)
    colsResizableOpts <- list(resizeMode = "overflow",
                              liveDrag = TRUE,
                              postbackSafe = TRUE,
                              partialRefresh = TRUE,
                              removePadding = FALSE
    )
    d3tf(Test,
         tableProps = tableProps,
         extensions = extensions,
         edit = TRUE,
         tableStyle = "table table-bordered",
         colsResizable = TRUE,
         colsResizableOptions = colsResizableOpts);
  })
  
})

runApp(list(ui=ui,server=server))
  1. Column resizing does not work when launching the Rshiny application via browser, but does seems to work when launching it locally in R-Studio. This seems to be a dataset specific issue, because it does work when I use mtcars dataset.

  2. When launching in browser and trying to adjust column width of one of the larger columns (Column_Name = "Test15") it seems to be reacting oddly, and not following what I expect to happen from a resize option = "overflow". When resizing Column15 all other columns seems to scale as well, instead of just column 15 independently.

Column Editing

Not necessarily an issue as much as a suggestion/annoyance.

When editing a column and pausing briefly, the edit is confirmed (brief green flash) and the cursor is reset to the entry-point of the cell. It makes more sense to leave the cursor at its current position so that the user can continue to edit at that location.

If you pause mid-sentence during an edit you have to re-click your last cursor location to continue editing in the same spot.

Hide columns by default and have dropdown cells

Hello Thomas.

I've been using you D3TableFilter in one of my personal projects and it's really great.

I've trying to implement two features but, alas, without success.

The features I would like to implement are:

  1. I would like to implement is to hide certain columns by default (I know the filter has the ability to do this after launching the Shiny app)

  2. have some columns have a limited input (to prevent errors of writing) and so have a dropdown list to choose from the predefined inputs.

I am familiar with R but I'm learning JS and HTML as I go along.

Could you provide me with an example or point to documentation where I can implement this?

Thank you.
Best Regards,

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.