Nutmeg Pumpkin Macchiato

    lineupjs
    TypeScript icon, indicating that this package has built-in type declarations

    4.7.0 • Public • Published

    LineUp.js: Visual Analysis of Multi-Attribute Rankings

    License NPM version Github Actions

    LineUp is an interactive technique designed to create, visualize and explore rankings of items based on a set of heterogeneous attributes.

    Key Features

    • scalable (~1M rows)
    • heterogenous attribute types (string, numerical, categorical, boolean, date)
    • composite column types (weighted sum, min, max, mean, median, impose, nested, ...)
    • array (multi value) and map column types (strings, stringMap, numbers, numberMap, ...)
    • filtering capabilities
    • hierarchical sorting (sort by more than one sorting criteria)
    • hierarchical grouping (split rows in multiple separate groups)
    • group aggregations (show a whole group as a single group row)
    • numerous visualizations for summaries, cells, and group aggregations
    • side panel for easy filtering and column management
    • React, Angular, Vue.js, Polymer, RShiny, Juypter, ObservableHQ, and Power BI wrapper
    • Demo Application with CSV import and export capabilities
    • API Documentation based on generated TypeDoc documenation

    Usage

    Installation

    npm install lineupjs
    <link href="https://unpkg.com/lineupjs/build/LineUpJS.css" rel="stylesheet" />
    <script src="https://unpkg.com/lineupjs/build/LineUpJS.js"></script>

    Minimal Usage Example

    // generate some data
    const arr = [];
    const cats = ['c1', 'c2', 'c3'];
    for (let i = 0; i < 100; ++i) {
      arr.push({
        a: Math.random() * 10,
        d: 'Row ' + i,
        cat: cats[Math.floor(Math.random() * 3)],
        cat2: cats[Math.floor(Math.random() * 3)],
      });
    }
    const lineup = LineUpJS.asLineUp(document.body, arr);

    CodePen

    Minimal Result

    Advanced Usage Example

    // arr from before
    const builder = LineUpJS.builder(arr);
    
    // manually define columns
    builder
      .column(LineUpJS.buildStringColumn('d').label('Label').width(100))
      .column(LineUpJS.buildCategoricalColumn('cat', cats).color('green'))
      .column(LineUpJS.buildCategoricalColumn('cat2', cats).color('blue'))
      .column(LineUpJS.buildNumberColumn('a', [0, 10]).color('blue'));
    
    // and two rankings
    const ranking = LineUpJS.buildRanking()
      .supportTypes()
      .allColumns() // add all columns
      .impose('a+cat', 'a', 'cat2'); // create composite column
      .groupBy('cat')
      .sortBy('a', 'desc')
    
    
    builder
      .defaultRanking()
      .ranking(ranking);
    
    const lineup = builder.build(document.body);

    CodePen

    Advanced Result

    Supported Browsers

    • Chrome 64+ (best performance)
    • Firefox 57+
    • Edge 16+

    Demo Application

    A demo application is located at lineup_app. It support CSV Import, CSV Export, JSON Export, CodePen Export, nad local data management.

    The application is deployed at https://lineup.js.org/app

    Screenshot

    API Documentation

    LineUp is implemented in clean TypeScript in an object oriented manner. A fully generated API documentation based on TypeDoc is available at https://lineup.js.org/main/docs

    LineUp can be build manually or using via the builder design pattern (see Advanced Usage Example). The builder design pattern in the more common way.

    LineUp Builder

    The simplest methods to create a new instance are:

    • asLineUp returning a ready to use LineUp instance
      asLineUp(node: HTMLElement, data: any[], ...columns: string[]): LineUp
    • asTaggle returning a ready to use Taggle instance
      asTaggle(node: HTMLElement, data: any[], ...columns: string[]): Taggle
    • builder returning a new DataBuilder
      builder(arr: any[]): DataBuilder`

    The DataBuilder allows on the one hand to specify the individual columns more specificly and the creation of custom rankings.

    Builder factory functions for creating column descriptions include:

    In order to build custom rankings within the DataBuilder the buildRanking returning a new RankingBuilder is used.

    buildRanking(): RankingBuilder

    LineUp classes and manual creation

    The relevant classes for creating a LineUp instance manually are LineUp, Taggle, and LocalDataProvider. A LocalDataProvider is an sub class of ADataProvider implementing the data model management based on a local JavaScript array. LineUp and Taggle are the visual interfaces to the LocalDataProvider.

    The classes can be instantiated either using the factory pattern or via their regular class constructors:

    createLineUp(container: HTMLElement, data: ADataProvider, config?: Partial<ILineUpOptions>): LineUp
    
    createTaggle(container: HTMLElement, data: ADataProvider, config?: Partial<ITaggleOptions>): Taggle
    
    createLocalDataProvider(data: any[], columns: IColumnDesc[], options?: Partial<ILocalDataProviderOptions>): LocalDataProvider
    new LineUp(node: HTMLElement, data: DataProvider, options?: Partial<ILineUpOptions>): LineUp
    new Taggle(node: HTMLElement, data: DataProvider, options?: Partial<ITaggleOptions>): Taggle
    new LocalDataProvider(data: any[], columns?: IColumnDesc[], options?: Partial<ILocalDataProviderOptions & IDataProviderOptions>): LocalDataProvider

    Both LineUp and Taggle are sub classes of ALineUp. The most important functions of this class include:

    React Support (LineUp.jsx)

    A React wrapper is located at lineupjsx.

    Installation

    npm install --save lineupjsx
    <link href="https://unpkg.com/lineupjsx/build/LineUpJSx.css" rel="stylesheet" />
    <script src="https://unpkg.com/lineupjsx/build/LineUpJSx.js"></script>

    Minimal Usage Example

    // generate some data
    const arr = [];
    const cats = ['c1', 'c2', 'c3'];
    for (let i = 0; i < 100; ++i) {
      arr.push({
        a: Math.random() * 10,
        d: 'Row ' + i,
        cat: cats[Math.floor(Math.random() * 3)],
        cat2: cats[Math.floor(Math.random() * 3)],
      });
    }
    <LineUp data={arr} />

    CodePen

    Result is same as the builder minimal example

    Advanced Usage Example

    // arr from before
    <LineUp data={arr} defaultRanking>
      <LineUpStringColumnDesc column="d" label="Label" width={100} />
      <LineUpCategoricalColumnDesc column="cat" categories={cats} color="green" />
      <LineUpCategoricalColumnDesc column="cat2" categories={cats} color="blue" />
      <LineUpNumberColumnDesc column="a" domain={[0, 10]} color="blue" />
    
      <LineUpRanking groupBy="cat" sortBy="a:desc">
        <LineUpSupportColumn type="*" />
        <LineUpColumn column="*" />
        <LineUpImposeColumn label="a+cat" column="a" categeoricalColumn="cat2" />
      </LineUpRanking>
    </LineUp>

    CodePen

    Result is same as the builder advanced example

    Angular 6 Support (nglineup)

    An Angular wrapper is located at nglineup.

    Installation

    npm install --save nglineup

    Minimal Usage Example

    app.module.ts:

    import { BrowserModule } from '@angular/platform-browser';
    import { NgModule } from '@angular/core';
    import { LineUpModule } from '../lib/lineup.module';
    
    import { AppComponent } from './app.component.1';
    
    @NgModule({
      declarations: [AppComponent],
      imports: [BrowserModule, LineUpModule],
      providers: [],
      bootstrap: [AppComponent],
    })
    export class AppModule {}

    app.component.ts:

    import { Component } from '@angular/core';
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
    })
    export class AppComponent {
      readonly data = <any[]>[];
    
      readonly cats = ['c1', 'c2', 'c3'];
    
      constructor() {
        const cats = this.cats;
        for (let i = 0; i < 100; ++i) {
          this.data.push({
            a: Math.random() * 10,
            d: 'Row ' + i,
            cat: cats[Math.floor(Math.random() * 3)],
            cat2: cats[Math.floor(Math.random() * 3)],
          });
        }
      }
    }

    app.component.html:

    <lineup-lineup [data]="data"></lineup-lineup>

    CodePen

    Result is same as the builder minimal example

    Advanced Usage Example

    app.component.html:

    <lineup-lineup [data]="data" [defaultRanking]="true" style="height: 800px;">
      <lineup-string-column-desc column="d" label="Label" [width]="100"></lineup-string-column-desc>
      <lineup-categorical-column-desc column="cat" [categories]="cats" color="green"></lineup-categorical-column-desc>
      <lineup-categorical-column-desc column="cat2" [categories]="cats" color="blue"></lineup-categorical-column-desc>
      <lineup-number-column-desc column="a" [domain]="[0, 10]" color="blue"></lineup-number-column-desc>
    
      <lineup-ranking groupBy="cat" sortBy="a:desc">
        <lineup-support-column type="*"></lineup-support-column>
        <lineup-column column="*"></lineup-column>
        <lineup-impose-column label="a+cat" column="a" categoricalColumn="cat2"></lineup-impose-column>
      </lineup-ranking>
    </lineup-lineup>

    CodePen

    Result is same as the builder advanced example

    Vue.js Support (vue-lineup)

    A Vue.js wrapper is located at vue-lineup.

    Installation

    npm install --save vue-lineup

    Minimal Usage Example

    const cats = ['c1', 'c2', 'c3'];
    const data = [];
    for (let i = 0; i < 100; ++i) {
      data.push({
        a: Math.random() * 10,
        d: 'Row ' + i,
        cat: cats[Math.floor(Math.random() * 3)],
        cat2: cats[Math.floor(Math.random() * 3)],
      });
    }
    
    // enable plugin to register components
    Vue.use(VueLineUp);
    
    const app = new Vue({
      el: '#app',
      template: `<LineUp v-bind:data="data" />`,
      data: {
        cats,
        data,
      },
    });

    CodePen

    Result is same as the builder minimal example

    Advanced Usage Example

    const app = new Vue({
      el: '#app',
      template: `<LineUp v-bind:data="data" defaultRanking="true" style="height: 800px">
        <LineUpStringColumnDesc column="d" label="Label" v-bind:width="100" />
        <LineUpCategoricalColumnDesc column="cat" v-bind:categories="cats" color="green" />
        <LineUpCategoricalColumnDesc column="cat2" v-bind:categories="cats" color="blue" />
        <LineUpNumberColumnDesc column="a" v-bind:domain="[0, 10]" color="blue" />
        <LineUpRanking groupBy="cat" sortBy="a:desc">
          <LineUpSupportColumn type="*" />
          <LineUpColumn column="*" />
        </LineUpRanking>
      </LineUp>`,
      data: {
        cats,
        data,
      },
    });

    CodePen

    Result is same as the builder advanced example

    Polymer Support (LineUp-Element)

    A Polymer 2.0 web component wrapper is located at lineup-element.

    Installation

    bower install https://github.com/lineupjs/lineup-element
    <link rel="import" href="bower_components/lineup-element/lineup-element.html" />

    Minimal Usage Example

    // generate some data
    const arr = [];
    const cats = ['c1', 'c2', 'c3'];
    for (let i = 0; i < 100; ++i) {
      arr.push({
        a: Math.random() * 10,
        d: 'Row ' + i,
        cat: cats[Math.floor(Math.random() * 3)],
        cat2: cats[Math.floor(Math.random() * 3)]
      })
    }
    conat data = { arr, cats };
    <lineup-element data="[[data.arr]]"></lineup-element>

    TODO CodePen

    Result is same as the builder minimal example

    Advanced Usage Example

    // arr from before
    <lineup-element data="[[data.arr]]" side-panel side-panel-collapsed default-ranking="true">
      <lineup-string-desc column="d" label="Label" width="100"></lineup-string-desc>
      <lineup-categorical-desc column="cat" categories="[[cats]]" color="green"></lineup-categorical-desc>
      <lineup-categorical-desc column="cat2" categories="[[cats]]" color="blue"></lineup-categorical-desc>
      <lineup-number-desc column="a" domain="[0, 10]" color="blue"></lineup-number-desc>
      <lineup-ranking group-by="cat" sort-by="a:desc">
        <lineup-support-column type="*"></lineup-support-column>
        <lineup-column column="*"></lineup-column>
      </lineup-ranking>
    </lineup-element>

    TODO CodePen

    Result is same as the builder advanced example

    R, RShiny, and R Markdown Support

    A HTMLWidget wrapper for R is located at lineup_htmlwidget. It can be used within standalone R Shiny apps or R Markdown files. Integrated plotting does not work due to an outdated integrated Webkit version in RStudio. Crosstalk is supported for synching selections and filtering among widgets.

    Installation

    devtools::install_github("rstudio/crosstalk")
    devtools::install_github("lineupjs/lineup_htmlwidget")
    library(lineupjs)

    Examples

    lineup(iris)

    iris output

    Jupyter Widget (to be released)

    A Jupyter Widget wrapper for Python is located at lineup_widget.

    Installation

    pip install -e git+https://github.com/lineupjs/lineup_widget.git#egg=lineup_widget
    jupyter nbextension enable --py [--sys-prefix|--user|--system] lineup_widget

    Or, if you use jupyterlab:

    pip install -e git+https://github.com/lineupjs/lineup_widget.git#egg=lineup_widget
    jupyter labextension install @jupyter-widgets/jupyterlab-manager

    Examples

    Launch Binder

    import lineup_widget
    import pandas as pd
    import numpy as np
    
    df = pd.DataFrame(np.random.randint(0,100,size=(100, 4)), columns=list('ABCD'))
    
    w = lineup_widget.LineUpWidget(df)
    w.on_selection_changed(lambda selection: print(selection))
    w

    simple usage

    from __future__ import print_function
    from ipywidgets import interact, interactive, interact_manual
    
    def selection_changed(selection):
        return df.iloc[selection]
    
    interact(selection_changed, selection=lineup_widget.LineUpWidget(df));

    interact example

    Observable HQ

    A ObservableHQ wrapper is located at lineup-js-observable.

    data = {
      const arr = [];
      const cats = ['c1', 'c2', 'c3'];
      for (let i = 0; i < 100; ++i) {
        arr.push({
          a: Math.random() * 10,
          d: 'Row ' + i,
          cat: cats[Math.floor(Math.random() * 3)],
          cat2: cats[Math.floor(Math.random() * 3)]
        })
      }
      return arr;
    }
    import { asLineUp } from '@sgratzl/lineup-js-observable-library';
    viewof selection = asLineUp(arr)

    ObservableHQ

    Minimal Result

    Advanced Usage Example

    // arr from before
    viewof selection = {
      const b = builder(data);
      b.column(
        LineUpJS.buildStringColumn('d')
          .label('Label')
          .width(100)
      )
        .column(LineUpJS.buildCategoricalColumn('cat', cats).color('green'))
        .column(LineUpJS.buildCategoricalColumn('cat2', cats).color('blue'))
        .column(LineUpJS.buildNumberColumn('a', [0, 10]).color('blue'));
    
      // and two rankings
      const ranking = LineUpJS.buildRanking()
        .supportTypes()
        .allColumns() // add all columns
        .impose('a+cat', 'a', 'cat2') // create composite column
        .groupBy('cat')
        .sortBy('a', 'desc');
    
      b.defaultRanking().ranking(ranking);
      return b.build();
    }

    ObservableHQ

    Advanced Result

    PowerBI Custom Visual (under development)

    A PowerBI Visual wrapper is located at lineup_powerbi.

    Installation

    TODO

    Examples

    TODO

    API Documentation

    See API documentation and Develop API documentation

    Demos

    See Demos, Develop Demos, and R Demos

    Related Publications

    LineUp: Visual Analysis of Multi-Attribute Rankings Paper Paper Website

    Samuel Gratzl, Alexander Lex, Nils Gehlenborg, Hanspeter Pfister, and Marc Streit
    IEEE Transactions on Visualization and Computer Graphics (InfoVis '13), 19(12), pp. 2277–2286, doi:10.1109/TVCG.2013.173, 2013.

    🏆 IEEE VIS InfoVis 2013 Best Paper Award

    Taggle: Scalable Visualization of Tabular Data through Aggregation Paper Preprint Paper Website

    Katarina Furmanova, Samuel Gratzl, Holger Stitz, Thomas Zichner, Miroslava Jaresova, Martin Ennemoser, Alexander Lex, and Marc Streit
    Information Visualization, 19(2): 114-136, doi:10.1177/1473871619878085, 2019.

    Dependencies

    LineUp.js depends on

    Development Dependencies

    Webpack is used as build tool. LineUp itself is written in TypeScript and SASS.

    Development Environment

    Try the Gitpod online IDE and start coding instantly in your browser.

    Gitpod Ready-to-Code

    Otherwise follow the steps to setup a local development environment.

    Installation

    The setup requires Node.js v16 or higher.

    git clone https://github.com/lineupjs/lineupjs.git -b develop
    cd lineupjs
    npm i -g yarn
    yarn install
    yarn sdks vscode

    Common commands

    yarn start
    yarn run clean
    yarn run compile
    yarn test
    yarn run lint
    yarn run fix
    yarn run build
    yarn run docs

    Run E2E Tests

    via cypress.io

    Variant 1: with prebuilt LineUp

    yarn run compile
    yarn run build
    yarn run cy:compile
    yarn run cy:open

    Variant 2: with webpack-dev-server

    first shell:

    yarn start

    second shell:

    yarn run cy:compile
    yarn run cy:start

    Authors

    • Samuel Gratzl (@sgratzl)
    • Holger Stitz (@thinkh)
    • The Caleydo Team (@caleydo)
    • datavisyn GmbH (@datavisyn)

    This repository was created as part of the The Caleydo Project.

    Keywords

    none

    Install

    npm i lineupjs

    DownloadsWeekly Downloads

    804

    Version

    4.7.0

    License

    BSD-3-Clause

    Unpacked Size

    8.57 MB

    Total Files

    1207

    Last publish

    Collaborators

    • sgratzl
    • caleydo-bot
    • datavisyn