All Projects → jpmorganchase → Regular Table

jpmorganchase / Regular Table

Licence: apache-2.0
A regular <table> library, for async and virtual data models.

Programming Languages

javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to Regular Table

Dash Table
A First-Class Interactive DataTable for Dash
Stars: ✭ 382 (+105.38%)
Mutual labels:  data-visualization, table
Data Visualization
数据可视化
Stars: ✭ 184 (-1.08%)
Mutual labels:  data-visualization
Easycharts
Excel Chart Plugin
Stars: ✭ 170 (-8.6%)
Mutual labels:  data-visualization
Egrid
对 element-ui table 组件的封装
Stars: ✭ 175 (-5.91%)
Mutual labels:  table
Data Science Resources
👨🏽‍🏫You can learn about what data science is and why it's important in today's modern world. Are you interested in data science?🔋
Stars: ✭ 171 (-8.06%)
Mutual labels:  data-visualization
Quill Better Table
Module for better table in Quill, more useful features are supported.
Stars: ✭ 175 (-5.91%)
Mutual labels:  table
Dabestr
Data Analysis with Bootstrap Estimation in R
Stars: ✭ 169 (-9.14%)
Mutual labels:  data-visualization
Superset Ui
Apache Superset UI packages
Stars: ✭ 183 (-1.61%)
Mutual labels:  data-visualization
Fun
操作系统,数据结构,网络,python,go,web
Stars: ✭ 181 (-2.69%)
Mutual labels:  data-visualization
Json2html
🐍 Python module for converting complex JSON to HTML Table representation
Stars: ✭ 173 (-6.99%)
Mutual labels:  table
Tably
Python command-line script for converting .csv data to LaTeX tables
Stars: ✭ 173 (-6.99%)
Mutual labels:  table
Eegrunt
A Collection Python EEG (+ ECG) Analysis Utilities for OpenBCI and Muse
Stars: ✭ 171 (-8.06%)
Mutual labels:  data-visualization
Json table
Flutter package: Json Table Widget to create table from json array
Stars: ✭ 178 (-4.3%)
Mutual labels:  table
Data Science Toolkit
Collection of stats, modeling, and data science tools in Python and R.
Stars: ✭ 169 (-9.14%)
Mutual labels:  data-visualization
Restable
jQuery plugin that makes tables responsive converting them to HTML lists on small viewports.
Stars: ✭ 183 (-1.61%)
Mutual labels:  table
Matplotplusplus
Matplot++: A C++ Graphics Library for Data Visualization 📊🗾
Stars: ✭ 2,433 (+1208.06%)
Mutual labels:  data-visualization
Graphic
A Flutter data visualization library based on Grammar of Graphics.
Stars: ✭ 173 (-6.99%)
Mutual labels:  data-visualization
Angular Handsontable
Angular Data Grid with Spreadsheet Look & Feel. Official Angular wrapper for Handsontable.
Stars: ✭ 175 (-5.91%)
Mutual labels:  table
Vaspy
Manipulating VASP files with Python.
Stars: ✭ 185 (-0.54%)
Mutual labels:  data-visualization
Semiotic
A data visualization framework combining React & D3
Stars: ✭ 2,207 (+1086.56%)
Mutual labels:  data-visualization

regular-table

NPM Version Build Status

A Javascript library for the browser, regular-table exports a custom element named <regular-table>, which renders a regular HTML <table> to a sticky position within a scollable viewport. Only visible cells are rendered and queried from a natively async virtual data model, making regular-table ideal for enormous or remote data sets. Use it to build Data Grids, Spreadsheets, Pivot Tables, File Trees, or anytime you need:

  • Just a regular <table>.
  • Virtually rendered for high-performance.
  • async data model handles slow, remote, enormous, and/or distributed backends.
  • Easy to style, works with any regular CSS for <table>.
  • Small bundle size, no dependencies.

Examples

two_billion_rows canvas_data_model perspective_headers
two_billion_rows canvas_data_model perspective_headers
minesweeper file_browser spreadsheet
minesweeper file_browser spreadsheet

Documentation

What follows functions as a quick-start guide, and will explain the basics of the Virtual Data Models, Styling and Interaction APIs. Complete API docs and documented examples are also available.

Installation

Include via a CDN like JSDelivr:

<script src="https://cdn.jsdelivr.net/npm/regular-table"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/regular-table/dist/css/material.css">

Or, add to your project via yarn:

yarn add regular-table

... then import into your asset bundle.

import "regular-table";
import "regular-table/dist/css/material.css";

<regular-table> Custom Element

regular-table exports no symbols, only the <regular-table> Custom Element which is registered as a module import side-effect. Once loaded, <regular-table> can be used just like any other HTMLElement, using regular browser APIs:

const regularTable = document.createElement("regular-table");
document.body.appendChild(regularTable);

... or from regular HTML:

<regular-table></regular-table>

... or from your library of choice, as long as it supports regular HTML! Here's an example for React/JSX:

const App = () => <regular-table></regular-table>;
ReactDOM.render(<App />, document.getElementById("root"));

.setDataListener() Virtual Data Model

Let's start with with a simple data model, a two dimensional Array. This one is very small at 3 columns x 6 rows, but even for very small data sets, regular-table won't read your entire dataset at once. Instead, we'll need to write a simple virtual data model to access DATA and COLUMN_NAMES indirectly.

const DATA = [
    [0, 1, 2, 3, 4, 5],
    ["A", "B", "C", "D", "E", "F"],
    [true, false, true, false, true, false],
];

When clipped by the scrollable viewport, you may end up with a <table> of just a rectangular region of DATA, rather than the entire set. A simple viewport 2x2 may yield this <table>:

0 A
1 B
{
    "num_rows": 26,
    "num_columns": 3,
    "data": [
        [0, 1],
        ["A", "B"]
    ]
}

Here's a an implementation for this simple virtual data model, the function getDataSlice(). This function is called by your <regular-table> whenever it needs more data, with coordinate arguments, (x0, y0) to (x1, y1). Only this region is needed to render the viewport, so getDataSlice() returns this rectangular slice of DATA. For the window (0, 0) to (2, 2), getDataSlice() would generate an Object as above, containing the data slice, as well as the overall dimensions of DATA itself ( num_rows, num_columns), for sizing the scroll area. To render this virtual data model to a regular HTML <table>, register this data model via the setDataListener() method:

function getDataSlice(x0, y0, x1, y1) {
    return {
        num_rows: (num_rows = DATA[0].length),
        num_columns: DATA.length,
        data: DATA.slice(x0, x1).map((col) => col.slice(y0, y1)),
    };
}

regularTable.setDataListener(getDataSlice);

This will render your regular HTML <table> ! Your DOM will look something like this, depending on the size of your viewport. Notice there are fewer rows and columns in the resulting HTML, e.g. the column Column 3 (boolean) - as you scroll, more data will be fetched from getDataSlice(), and parts of the <table> will redrawn or extended as needed.

<regular-table>

    <table>
        <tbody>
            <tr>
                <td>0</td>
                <td>A</td>
            </tr>
            <tr>
                <td>1</td>
                <td>B</td>
            </tr>
        </tbody>
    </table>

</regular-table>

Column and Row Headers

regular-table can also generate Hierarchial Row and Column Headers, using <th> elements which layout in a fixed position within the virtual table. It can generate Column Headers (within the <thead>), or Row Headers (the first children of each tbody tr), via the column_headers and row_headers properties (respectively) of your data model's Response object. This can be renderered with column_headers, a two dimensional Array which must be of length x1 - x0, one Array for every column in your data window.

Column 1 (number) Column 2 (string)
0 A
1 B
{
    "num_rows": 26,
    "num_columns": 3,
    "data": [
        [0, 1],
        ["A", "B"]
    ],
    "column_headers": [
        ["Column 1 (number)"],
        ["Column 2 (string)"]
    ]
}

Hierarchial/Group Headers

regular-table supports multiple <tr> of <th>, and also uses colspan and rowspan to merge simple consecutive names, which allows description of simple Row and Column Group Hierarchies such as this:

Colgroup 1
Column 1 Column 2
Rowgroup 1 Row 1 0 A
Row 2 1 B
{
    "num_rows": 26,
    "num_columns": 3,
    "data": [
        [0, 1],
        ["A", "B"]
    ],
    "row_headers": [
        ["Rowgroup 1", "Row 1"],
        ["Rowgroup 1", "Row 2"]
    ],
    "column_headers": [
        ["Colgroup 1", "Column 1"],
        ["Colgroup 1", "Column 2"]
    ]
}

Note that in the rendered HTML, for these Row and Column Array, repeated elements in a sequence will be automatically merged via rowspan and colspan attributes. In this example, e.g. "Rowgroup 1" will only output to one <th> node in the resulting <table>.

async Data Models

With an async data model, it's easy to serve getDataSlice() remotely from node.js or re-implement the JSON response protocol in any language. Just return a Promise() from, or use an async function as an argument to, setDataListener(). Your <regular-table> won't render until the Promise is resolved, nor will it call your data model function again until the current call is resolved or rejected. The following async example uses a Web Worker, but the same principle applies to Web Sockets, readFile() or any other asynchronous source. Returning a Promise blocks rendering until the Web Worker replies:

// Browser

let callback;

worker.addEventListener("message", (event) => {
    callback(event.data);
});

regularTable.setDataListener((...viewport) => {
    return new Promise(function (resolve) {
        callback = resolve;
        worker.postMessage(viewport);
    });
});
// Web Worker

self.addEventListener("message", async (event) => {
    const response = await getDataSlice.apply(null, event.data);
    self.postMessage(response);
});

.addStyleListener() and getMeta() Styling

regular-table can be styled trivially with just regular CSS for <table>.

// Zebra striping!
regular-table tr:nth-child(even) td {
    background: rgba(0,0,0,0.2);
}

However, CSS alone cannot select on properties of your data - if you scroll this example, the 2nd row will always be the striped one. Some other data-reliant style examples include:

  • Styling a specific column in the virtual data set, as <td> may represent a different column based on horizontal scroll position.
  • Styling cells by value, +/-, heatmaps, categories, etc.
  • Styling cells based on data within-or-outside of the virtual viewport, grouping depth, grouping categories, etc.

To make CSS that is virtual-data-model-aware, you'll need to use addStyleListener(), which invokes a callback whenever the <table> is re-rendered, such as through API invocations of draw() and user-initiated events such as scrolling. Within this optionally async callback, you can select <td>, <th>, etc. elements via regular DOM API methods like querySelectorAll().

// Only select row_headers!
table.addStyleListener(() => {
    for (const th of table.querySelectorAll("tbody th")) {
        style_th(th);
    }
});

Once you've selected the <td> and <th> you want to paint, getMeta() will return a MetaData record of information about the HTMLElement's virtual position. This example uses meta.x, the position in data-space, to make virtual-scroll-aware zebra striping.

function style_th(th) {
    const meta = table.getMeta(th);
    th.classList.toggle("zebra-striped", meta.x % 2 === 0);
}
.zebra-striped {
    background-color: rgba(0,0,0,0.2);
}

.invalidate()

To prevent DOM renders, <regular-table> conserves DOM calls like offsetWidth to an internal cache. When a <td> or <th>'s width is modified within a callback to .addStyleListener(), you must indicate to <regular-table> that its dimensions have changed in order to invalidate this cache, or you may not end up with enough rendered columns to fill the screen!

A call to invalidate() that does not need new columns only imparts a small runtime overhead to re-calculate virtual width per async draw iteration, but should be used conservatively if possible. Calling invalidate() outside of a callback to .addStyleListener() will throw an Error.

table.addStyleListener(() => {
    for (const th of table.querySelectorAll("tbody th")) {
        th.style.maxWidth = "20px";
    }
    table.invalidate();
});

.addEventListener() Interaction

<regular-table> is a normal HTMLElement! Use the regular-table API in concert with regular DOM API methods that work on other HTMLElement to create advanced functionality, such as this example of virtual row select:

const selected_rows = [];

table.addEventListener("mousedown", (event) => {
    const meta = table.getMeta(event.target);
    if (meta && meta.y >= 0) {
        selected_rows.push(meta.y);
        table.draw();
    }
});

table.addStyleListener(() => {
    for (const td of table.querySelectorAll("td")) {
        const meta = table.getMeta(td);
        td.classList.toggle("row-selected", selected_rows.includes(meta.y));
    }
});

Advanced examples can be found in the examples directory, and in the bl.ocks example gallery.

Pivots, Filters, Sorts, and Column Expressions with perspective

regular-table is natively compatible with perspective, a WebAssembly streaming visualization engine. By using a persective.Table as a Virtual Data Nodel, it becomes simple to achieve user-driven row and column pivots, filters, sorts, and column expressions, as well as charts and persistent layouts, from high-frequency updating data.

Development

First install dev_dependencies:

yarn

Build the library

yarn build

Run the test suite

yarn test

Start the example server at http://localhost:8080/examples/

yarn start
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].