npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

periphery-plots

v1.0.28

Published

A React component for multivariate time series analysis

Downloads

11

Readme

Periphery Plots from the Precision VISSTA Team

Patterns in temporal data are often across different scales, such as days, weeks, and months, making effective visualization of time-based data challenging. Periphery Plots are a new approach for providing focus and context in time-based charts to enable interpretation of patterns across heterogeneous time scales. Our approach employs a focus zone with a time axis and a second axis, that can either represent quantities or categories, as well as a set of adjacent periphery plots that aggregate data along the time dimension, value dimension, or both. This repository contains a prototype implementation of Periphery Plots as a React component as well as demo of the technique.

Developed by our teams from the University of North Carolina at Chapel Hill (Bryce Morrow, David Gotz, Arlene Chung) and from Harvard Medical School (Trevor Manz, Nils Gehlenborg) through funding support from the NIH NIBIB and Office of the Director.

Contact information: [email protected]

How to Use

  1. Live demo of the app visualizing a sample dataset of weather in seattle over multiple years.

  2. Local install from github:

Requires the latest version of NodeJS.

  1. git clone https://github.com/PrecisionVISSTA/PeripheryPlots.git
  2. cd PeripheryPlots
  3. npm i
  4. npm i react react-dom
  5. npm start
    • App is now using webpack-dev-server running at http://localhost:8080
  1. Install into an existing project via npm:

Requires the latest version of NodeJS.

  1. npm i periphery-plots
  2. npm i react react-dom
    • Only complete step 2 if you do not already have compatible versions of react and react-dom in your project already. See the reasoning here.

Preprint

A preprint describing the periphery plot data visualization approach in detail is available on arxiv: https://arxiv.org/abs/1906.07637.

Winner of the Best Short Paper award at IEEE VIS 2019.

Component Configuration

The PeripheryPlots React component takes a single configuration object as input. Properties that are bolded are required while all others are optional with sensible defaults. The React based prop-types library is used to validate the configuration object.

| Property | Type | Description | | ------------- | ------------- | ------------- | | trackwiseObservations | [ [ Object, ... ], ... ] | The set of temporal observations for each track. | | trackwiseTimeKeys | [ String, ... ] | Key used to index temporal attribute from observation objects. | | trackwiseValueKeys | [ String, ... ] | Key used to index value attribute from observation objects. | | trackwiseTypes | [ String, ... ] | Data type for each track. Can be "continuous", "discrete", or "other". | | trackwiseUnits | [ String OR Null, ... ] | Unit for each track. | | trackwiseNumAxisTicks | [ Integer+ OR Null, ... ] | The number of ticks for each track axis. | | trackwiseAxisTickFormatters | [ d3.format OR Null, ... ] | Tick formatter for each track axis. | | trackwiseEncodings | [ [ [ React.Component, ... ], ... ] ... ] | Layered encoding specification for each track. | | applyEncodingsUniformly | Boolean | Determines the number of encoding specifications required for each track. | | contextWidthRatio | Float in range [0.0, 1.0] default: .2 | Fraction of available space (whithin tracks) allocated to each context plot. | | numContextsPerSide | Integer+ default: 1 | The number of context zones on each side of the focus zone. | | timeExtentDomain | [ Date, Date ] | A temporal range including all data observations across all data sources. | | timeDomains | [ [ Date, Date ], ... ] | Temporal ranges corresponding to initially selected brush regions for the control timeline. | | tickInterval | d3.interval | The interval for tick placement for the control timeline axis. | | dZoom | Integer+ default: 5 | Speed of track generated zoom events for control timeline. For wide screens, it may be necessary to increase this value | | containerBackgroundColor | Valid input to d3.color default: "#ffffff" | Background color for the component container. | | focusColor | Valid input to d3.color default: "#576369" | Color of focus brush and focus plot borders. | | contextColor | Valid input to d3.color default: "#9BB1BA" | Color of context brush and context plot borders.| | lockActiveColor | Valid input to d3.color default: "#00496E" | Color of control timeline locks when active. | | lockInactiveColor | Valid input to d3.color default: "Grey" | Color of control timeline locks when inactive. | | containerPadding | Integer+ default: 10 | Component padding in pixels that surrounds tracks and control timeline. | | controlTimelineHeight | Integer+ default: 50 | The height of the control timeline in pixels. | | verticalAlignerHeight | Integer+ default: 30 | The height of the vertical alignment component in pixels. | | axesWidth | Integer+ default: 40 | The width of the axis for each track in pixels. | | trackHeight | Integer+ default: 50 | The width of each track in pixels. | | trackSvgOffsetTop | Integer+ default: 10 | The offset from top of svg plot containers defining top bound on drawable space. | | trackSvgOffsetBottom | Integer+ default: 5 | The offset from bottom of svg plot containers defining bottom bound on drawable space. | | trackSvgOffsetBottom | Integer+ default: 5 | The offset from bottom of svg plot containers defining bottom bound on drawable space. | | formatTrackHeader | Function(valueKey, unit) default: removes underscores and adds a space between valueKey and unit. | Function to format header string for each track receiving valueKey and unit as inputs | | msecsPadding | Integer default: 0 | When determining the observations bound to an individual plot, we expand the plot's bound time domain by msecsPadding time units on both sides. This property is helpful for encodings like line charts, which may appear discontinuous near the boundaries of the container if only the data points within the interval are visualized. | | lockOutlineColor | Valid input to d3.color default: "#000000" | The outline color for timeline control locks. | | handleOutlineColor | Valid input to d3.color default: "#000000" | The outline color for timeline control handles. | | brushOutlineColor | Valid input to d3.color default: "#000000" | The outline color for timeline control brushes. |

Some of the descriptions in the table above are sufficient, but some properties are more complex and must satisfy specific criteria to be considered valid.

We describe these properties in further detail as they relate to the two core subcomponents of the PeripheryPlots framework:

  • Tracks
  • Control Timeline

Tracks

Tracks are vertically aligned containers that house multiple focus and context plots. The plots are horizontally organized along the temporal axis. The focus plot is always in the middle and there are an equal number of context plots on both sides of the focus plot.

All properties that begin with the word 'trackwise' are arrays and they must have equal lengths. The ith value in each of these arrays corresponds to some property for the ith track.

trackwiseObservations

Each individual set of observations is an array of objects. Each object is a temporal observation with a temporal attribute and one or more value attributes.

trackwiseTypes

We broadly group data into three classes: * Continuous (assumed to be numeric) * Discrete (can be numeric or of some other form) * Other These enumerative types are used to determine what type of axis is used for each track.

trackwiseUnits

If specified, the unit is displayed alongside the track name (or rather, the valueKey used to index observations).

trackwiseEncodings

For each track we specify a collection of encoding schemas. The dimensions of trackwiseEncodings is determined by applyContextEncodingsUniformly and numContextsPerSide.

  • if applyContextEncodingsUniformly === true:
    • trackwiseEncodings[i] is of the form: [     [ /* encoding schema to be applied to all left contexts plots */ ],     [ /* encoding schema for focus plot */ ],     [ /* encoding schema to be applied to all right contexts plots */ ] ]
  • if applyContextEncodingsUniformly === false:
    • trackwiseEncodings[i] is of the form: [     [ /* encoding schema to be applied to the 1st left context plot */ ],     ...     [ /* encoding schema to be applied to the numContextsPerSide-th left context plot */ ],     [ /* encoding schema for focus plot */ ],     [ /* encoding schema to be applied to the 1st right context plot */ ],     ...     [ /* encoding schema to be applied to the numContextsPerSide-th right context plot */ ] ]

Each encoding schema, represented by trackwiseEncodings[i][j] is an array where each element is a React.Component (can be class, function, or any other kind). Each possible value of trackwiseEncodings[i][j] is bound to some plot within the interface (as described above). After this binding occurs, the elements of trackwiseEncodings[i][j] are rendered into the plot (svg) they are bound to in the order they are specified.

  • ex: if trackwiseEncodings[i][j] = [BarChart, AverageLineGroup], then some plot within some track will be populated with a bar chart visualization with an average line annotation layered over top. You can see an example of this in the 'precipitation' track in the .gif demo at the top of this page.

Control Timeline

The control timeline is a set of multiple linked brushes which allow users to dynamically configure focus and context zones, temporal regions to be viewed and summarized at varying visual resolutions.

The ith brush (from left to right) in the control timeline determines the temporal period bound to the ith subplot (from left to right) across all tracks in the interface.

timeExtentDomain

A temporal range containing all points. This should almost always be as small as possible, so there is no temporal subrange for which there is no data.

timeDomains

The initial temporal ranges of analysis. There should be (numContextsPerSide * 2) + 1 timeDomains specified. There should be no temporal distance between two adjacent temporal ranges (i.e. where timeDomains[i] ends, timeDomains[i+1] should begin).

Component Styling via CSS

Many of the internal style properties for the component must be specified through the configuration object to ensure only certain style properties of sub-components are changed.

One area where this is not as much of a problem is styling the text that appears within the component. We have given the text elements within the component special class names to allow for custom styling via CSS.

| Class | Description | | ------------- | ------------- | | pplot-control-timeline-text | Control timeline axis labels. | | pplot-track-header-text | Header text for each track. | | pplot-track-header-text-container | Container (div) for header text for each track. This container can control the text-alignment of the track label. | | pplot-track-axis-text | Axis text for each track. |

Creating Custom Encodings

You can create your own custom encodings for use with the PeripheryPlots component. Simply write a React component, import it, and include it somewhere in trackwiseEncodings. All components in trackwiseEncodings will recieve a object called pplot which contains a number of properties that can be used to plot data within a corresponding plot.

| Property | Type | Description | | ------------- | ------------- | ------------- | | observations | [ Object, ... ] | all observations within timeDomain. | | timeKey | String | The temporal index into each individual observation object. | | valueKey | String | The value index into each individual observation object. | | timeDomain | [Date, Date] | The temporal range for the plot. | | valueDomain | [ Number, Number ] OR [ Object, ... ] OR Null | Range of possible values across all observations. | | xRange | [ Number, Number ] | Plottable range in x dimension. | | yRange | [ Number, Number ] | Plottable range in y dimension. | | scaleRangeToBox | Function (d3.scale, d3.scale) | Binds input d3.scale objects to plottable ranges (x and/or y). | | isLeft | Boolean | Whether or not the encoding is bound to a left context plot. | | isFocus | Boolean | Whether or not the encoding is bound to focus plot. | | getAllObservations | Function() | Escape hatch that allows an encoding bound to any plot to access all observations, not just observations within a set time domain. This should only be used for encodings that require knowledge of other data points to generate their own visual representation (for performance reasons). An example would be a 21 day moving average encoding. |

We describe some of these properties in more detail below.

valueDomain

The value of valueDomain depends on the type of the current track (specified in trackwiseTypes in the configuration object)

  • if type === "continuous":
    • valueDomain is of the form [ Number, Number ] and represents the minimum and maximum numerical values seen across all observations.
  • if type === "discrete":
    • valueDomain is of the form [ Object, ... ] and represents all unique values seen across all observations.
  • if type === "other":
    • valueDomain is Null.

scaleRangeToBox

a function that takes two d3.scale objects as input. Sets the range of the first scale to the xRange and sets the range of the second scale to yRange. Either scale input can be omitted (Null value) if the encoding only requires a single scale to have its range set.

This can be done manually by the programmer but since the operation is so common we still provide this utility function.

isLeft and isFocus

These two Boolean values can be used to determine what kind of plot the encoding is bound to. There are sometimes cases where this information is useful.

For example, when using either the QuantitativeTracePlot or NominalTracePlot encodings that come packaged with the framework, we often want to flip the encoding about the y axis to preserve symmetry relative to the focus plot. You can see an example of this in the 'temp max' and 'weather' tracks in the gif demo at the top of this page.

yRange and yRange

It's important to note that both yRange and yRange are monotonically increasing ranges (i.e. range[1] > range[0]). As is typical in computer graphics, the y-coordinate system begins from the top of the container and extends towards the bottom of the container as the y-coordinate increases. If you want your custom encoding to use a coordinate system where (0, 0) is in the lower left corner of the plot and (width, height) is in the upper right hand corner of the plot, you can flip the yRange before setting it as the range for your scale.

Default Encodings

The PeripheryPlots framework has a number of encodings implemented by default.

Any one of these default encodings can be used as a reference template when developing custom encodings.

BarGroup - Quantitative bar chart.

EventGroup - Categorical event timeline where each event is a rectangle. Rectangles are colored by event type.

LineGroup - Quantitative line chart.

MovingAverageEnvelopeGroup - Envelope computed using 10 day moving average.

ScatterGroup - Quantitative scatter chart.

AverageLineGroup - Average line annotation.

NominalTraceGroup - Categorical sideways histogram.

QuantitativeTraceGroup - Quantitative sideways histogram.

Custom Encoding Example

Here is an example of what a line plot encoding might look like using the new React Hooks API.

import React, { useState } from "react";
import { line, curveMonotoneX } from 'd3-shape'; 
import { scaleLinear, scaleTime } from 'd3-scale'; 

export default function LineGroup(props) {

    let [line, setLine] = useState(() => line().curve(curveMonotoneX)); 
    let [timeScale, setTimeScale] = useState(() => scaleTime()); 
    let [valueScale, setValueScale] = useState(() => scaleLinear()); 

    let { pplot } = props; 
    let { timeKey, valueKey, timeDomain, valueDomain, observations, scaleRangeToBox } = pplot; 

    let scales = scaleRangeToBox(timeScale, valueScale); 
    timeScale = scales.xScale; 
    valueScale = scales.yScale; 

    timeScale.domain(timeDomain); 
    valueScale.domain(valueDomain); 

    line.x(d => timeScale(d[timeKey]))
        .y(d => valueScale(d[valueKey]));

    return (
        <g>
            {/* Line */}
            <path d={line(observations)} fill="none" stroke="steelblue"/>
        </g>
    ); 

}