@data-ui/sparkline
A React + d3 library for creating sparklines 📈 implemented with vx.
npm install --save @data-ui/sparkline
Demo it live at williaster.github.io/data-ui.
Example usage
Sparklines are composable using the container <Sparkline />
component and different types of children including one or more <*Series />
components and reference lines or bands. Additionally, you can customize aesthetics using the exported <PatternLines />
and <LinearGradient/>
components.
Note that the order of children passed to <Sparkline />
determines their rendering order, for example a <HorizontalReferenceLine />
passed after a <BarSeries />
will overlay the line on the bars.
import {
Sparkline,
LineSeries,
HorizontalReferenceLine,
BandLine,
PatternLines,
PointSeries } from '@data-ui/sparkline';
import { allColors } from '@data-ui/theme';
const data = Array(25).fill().map(Math.random);
<Sparkline
ariaLabel="A line graph of randomly-generated data"
margin={{ top: 24, right: 64, bottom: 24, left: 64,}}
width={500}
height={100}
data={data}
valueAccessor={datum => datum}
>
{/* this creates a <defs> referenced for fill */}
<PatternLines
id="unique_pattern_id"
height={6}
width={6}
stroke={allColors.grape[6]}
strokeWidth={1}
orientation={['diagonal']}
/>
{/* display innerquartiles of the data */}
<BandLine
band="innerquartiles"
fill="url(#unique_pattern_id)"
/>
{/* display the median */}
<HorizontalReferenceLine
stroke={allColors.grape[8]}
strokeWidth={1}
strokeDasharray="4 4"
reference="median"
/>
{/* Series children are passed the data from the parent Sparkline */}
<LineSeries
showArea={false}
stroke={allColors.grape[7]}
/>
<PointSeries
points={['min', 'max']}
fill={allColors.grape[3]}
size={5}
stroke="#fff"
renderLabel={val => val.toFixed(2)}
/>
</Sparkline>
Components
Check out the example source code and PropTable tabs in the Storybook williaster.github.io/data-ui for more!
<Sparkline />
The Sparkline
component renders an <svg />
and coordinates scales across all of it's child series and reference lines. It takes the following props:
Name | Type | Default | Description |
---|
ariaLabel | PropTypes.string.isRequired | - | Accessibility label for the svg |
children | PropTypes.node.isRequired | - | Child series, reference lines, defs, or other valid svg children |
className | PropTypes.string | - | Optional className to add to the svg |
data | PropTypes.array | [] | an array of data that is shared across, items can be any shape or number |
height | PropTypes.number.isRequired | - | Height of the svg including top/bottom margin |
margin | PropTypes.shape({ top: PropTypes.number, right: PropTypes.number, bottom: PropTypes.number, left: PropTypes.number }) | { top: 16, right: 16, bottom: 16, left: 16 } | chart margin, leave room for labels! note 0 may clip LineSeries and PointSeries. a partial { top/right/bottom/ left } object is filled with the other default values |
max | PropTypes.number | - | Optionally set the maximum y-value of the chart (e.g., to coordinate axes across multiple Sparklines) |
min | PropTypes.number | - | Optionally set the minimum y-value of the chart (e.g., to coordinate axes across multiple Sparklines) |
onMouseMove | PropTypes.func | - | func({ data, datum, event, index, color }) , passed to an invisible BarSeries that intercepts all mouse events (can pass to individual series for more control) |
onMouseLeave | PropTypes.func | - | func() , passed to an invisible BarSeries that intercepts all mouse events |
styles | PropTypes.object | - | Optional styles to apply to the svg |
width | PropTypes.number.isRequired | - | Width of the svg including left/right margin |
valueAccessor | PropTypes.func | d => d | Optional accessor function that takes an item from the data array as input and returns the y value of the datum. This value is passed back in e.g., renderLabel functions. |
Series
The following series components are available, they are passed the data and scales from the parent Sparkline
component, and you may compose multiple to create the sparkline you want 😍:
<LineSeries />
<PointSeries />
<BarSeries />
<PointSeries />
and <BarSeries />
support labeling of specific data points.
<LineSeries />
This component can be used to create lines and or area sparklines with various curve
types, and takes the following props:
Name | Type | Default | Description |
---|
fill | PropTypes.string | @data-ui/theme s color.default | If showArea=true , this sets the fill of the area path. |
fillOpacity | PropTypes.number | 0.3 | If showArea=true , this sets the fillOpacity of the area shape. |
curve | PropTypes.oneOf(['linear', 'cardinal', 'basis', 'monotoneX']) | 'cardinal' | The type of curve interpolator to use. |
onMouseMove | PropTypes.func | - | func({ data, datum, event, index, color }) called on line mouse move for the closest datum |
onMouseLeave | PropTypes.func | - | func() called on line mouse leave |
showArea | PropTypes.bool | false | Boolean indicating whether to render an Area path. |
showLine | PropTypes.bool | true | Boolean indicating whether to render a Line path. |
stroke | PropTypes.string | @data-ui/theme s color.default | If showLine=true , this sets the stroke of the line path. |
strokeDasharray | PropTypes.string | - | If showLine=true , this sets the strokeDasharray attribute of the line path. |
strokeLinecap | PropTypes.oneOf(['butt', 'square', 'round', 'inherit']) | 'round' | If showLine=true , this sets the strokeLinecap attribute of the line path. |
strokeWidth | PropTypes.number | 2 | If showLine=true , this sets the strokeWidth attribute of the line path. |
<BarSeries />
This component can be used to bar-graph sparklines and takes the following props:
Name | Type | Default | Description |
---|
fill | PropTypes.oneOfType([PropTypes.func, PropTypes.string]) | @data-ui/theme s color.default | A single fill to use for all Bar s or a function with the following signature (yVal, i) => fill called for each data point. If data objects have a fill property, it overrides this value. |
fillOpacity | PropTypes.oneOfType([PropTypes.func, PropTypes.number]) | 0.7 | A single fillOpacity value (0 - 1) to use for all Bar s or a function with the following signature (yVal, i) => opacity called for each data point. If data objects have a fillOpacity property, it overrides this value. |
LabelComponent | PropTypes.element | @data-ui/sparkline 's <Label /> component | Component to use for labels, if relevant. This component is cloned with appropriate x, y, dx, and dy values for positioning. |
labelOffset | PropTypes.number | 8 | (Absolute) pixel offset to use for positioning a label relative to a Bar . labelPosition is used to determine direction. |
labelPosition | PropTypes.oneOfType([PropTypes.func, PropTypes.oneOf(['top', 'right', 'bottom', 'left']), ]) | 'top' | A single string indicating how to position a label relative to the top point of a bar, or a function with the following signature (yVal, i) => position called for each data point. If the return value is not one of top, right, bottom, left, it is spread on the LabelComponent directly (e.g., { dx: -100, dy: 100 } ) |
onMouseMove | PropTypes.func | - | func({ data, datum, event, index, color }) called on bar mouse move |
onMouseLeave | PropTypes.func | - | func() called on bar mouse leave |
renderLabel | PropTypes.func | - | Optional function called for each datum, with the following signature (yVal, i) => node . If this is passed to the Series and returns a value, a label will be rendered for the passed point. This is used as the child of LabelComponent so any valid child of svg <text> elements can be returned. |
stroke | PropTypes.oneOfType([PropTypes.func, PropTypes.string]) | white | A single stroke to use for all Bar s or a function with the following signature (yVal, i) => stroke . If data objects have a stroke property, it overrides this value. |
strokeWidth | PropTypes.oneOfType([PropTypes.func, PropTypes.number]) | 1 | A single strokeWidth to use for all Bar s or a function with the following signature (yVal, i) => stroke . If data objects have a strokeWidth property, it overrides this value. |
<PointSeries />
This component can be used to render all or a subset of points for a sparkline and takes the following props:
Name | Type | Default | Description |
---|
fill | PropTypes.oneOfType([PropTypes.func, PropTypes.string]) | @data-ui/theme s color.default | A single fill to use for all Point s or a function with the following signature (yVal, i) => fill called for each data point. If data objects have a fill property, it overrides this value. |
fillOpacity | PropTypes.oneOfType([PropTypes.func, PropTypes.number]) | 1 | A single fillOpacity value (0 - 1) to use for all Point s or a function with the following signature (yVal, i) => opacity called for each data point. If data objects have a fillOpacity property, it overrides this value. |
LabelComponent | PropTypes.element | @data-ui/sparkline 's <Label /> component | Component to use for labels, if relevant. This component is cloned with appropriate x, y, dx, and dy values for positioning. |
labelOffset | PropTypes.number | 12 | (Absolute) pixel offset to use for positioning a label relative to a Point . labelPosition is used to determine direction. |
labelPosition | PropTypes.oneOfType([PropTypes.func, PropTypes.oneOf(['auto', 'top', 'right', 'bottom', 'left']), ]) | 'auto' | A single string indicating how to position a label relative to the center of a point, or a function with the following signature (yVal, i) => position called for each data point. 'auto' attempts to position the label on top or bottom of a point depending on the surrounding data points. If the return value is not one of auto, top, right, bottom, left, it is spread on the LabelComponent directly (e.g., { dx: -100, dy: 100 } ) |
onMouseMove | PropTypes.func | - | func({ data, datum, event, index, color }) called on point mouse move |
onMouseLeave | PropTypes.func | - | func() called on point mouse leave |
points | PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.number, PropTypes.oneOf(['all', 'min', 'max', 'first', 'last']), ])) | ['min', 'max'] | String(s) or index(s) indicating which point(s) to render. e.g., If all , all points are rendered, if ['min', 'max'] , only the minimum and maximum points are rendered. |
size | PropTypes.oneOfType([PropTypes.func, PropTypes.number]) | 3 | A single size to use as the radius of all Points s or a function with the following signature (yVal, i) => size called for each data point. If data objects have a size property, it overrides this value. |
renderLabel | PropTypes.func | - | Optional function called for each datum, with the following signature (yVal, i) => node . If this is passed to the Series and returns a value, a label will be rendered for the passed point. This is used as the child of LabelComponent so any valid child of svg <text> elements can be returned. |
stroke | PropTypes.oneOfType([PropTypes.func, PropTypes.string]) | white | A single stroke to use for all Point s or a function with the following signature (yVal, i) => stroke . If data objects have a stroke property, it overrides this value. |
strokeWidth | PropTypes.oneOfType([PropTypes.func, PropTypes.number]) | 1 | A single strokeWidth to use for all Point s or a function with the following signature (yVal, i) => stroke . If data objects have a strokeWidth property, it overrides this value. |
Tooltips
You can add tooltips to <Sparkline />
components by wrapping them with the higher-order <WithTooltip />
component. This component accepts a renderTooltip
function whose output is rendered into a boundary-aware (html-based) tooltip. <WithTooltip />
handles tooltip visibility state and passes onMouseMove
onMouseLeave
and tooltipData
props to its child. If these are passed to <Sparkline />
, it will render a series of invisible Bar
s to intercept mouse events. If they are passed to individual series, mouse events will be handled on the series level.
See the storybook for example usage!
Name | Type | Default | Description |
---|
children | PropTypes.func or PropTypes.object | - | Child function (to call) or element (to clone) with onMouseMove, onMouseLeave, and tooltipData props/keys |
className | PropTypes.string | - | Class name to add to the <div> container wrapper |
renderTooltip | PropTypes.func.isRequired | - | Renders the contents of the tooltip, signature of ({ event, data, datum, color }) => node . If this function returns a falsy value, a tooltip will not be rendered. |
styles | PropTypes.object | {} | Styles to add to the <div> container wrapper |
TooltipComponent | PropTypes.func or PropTypes.object | @vx 's TooltipWithBounds | Component (not instance) to use as the tooltip container component. It is passed top and left numbers for positioning |
tooltipProps | PropTypes.object | - | Props that are passed to TooltipComponent |
tooltipTimeout | PropTypes.number | 200 | Timeout in ms for the tooltip to hide upon calling onMouseLeave |
Reference lines and bands
The following reference line components are exported to support different types of annotations you may want:
<HorizontalReferenceLine />
<VerticalReferenceLine />
<BandLine />
.
<HorizontalReferenceLine />
This component can be used to render a single horizontal reference line to call out a point of interest. It takes the following props:
Name | Type | Default | Description |
---|
reference | PropTypes.oneOfType([PropTypes.number, PropTypes.oneOf(['mean', 'median', 'min', 'max'] ])) | mean | What reference to create a line for. This may be a raw number to call out, or one of 'mean', 'median', 'min', 'max' which will compute the relevant y value. |
LabelComponent | PropTypes.element | @data-ui/sparkline 's <Label /> component | Component to use for labels, if relevant. This component is cloned with appropriate x, y, dx, and dy values for positioning. |
labelOffset | PropTypes.number | 8 | (Absolute) pixel offset to use for positioning a label relative to a Point . labelPosition is used to determine direction. |
labelPosition | PropTypes.oneOf(['top', 'right', 'bottom', 'left']) | 'right' | A single string indicating how to position a label relative to the end of a reference line |
renderLabel | PropTypes.func | - | Optional function called for each datum, with the following signature (yVal) => node . If this is passed and returns a value, a label will be rendered. This is used as the child of LabelComponent so any valid child of svg <text> elements can be returned. |
stroke | PropTypes.string | @data-ui/theme s color.default | Sets the stroke of the line path. |
strokeDasharray | PropTypes.string | - | Sets the strokeDasharray attribute of the line path. |
strokeLinecap | PropTypes.oneOf(['butt', 'square', 'round', 'inherit']) | 'round' | Sets the strokeLinecap attribute of the line path. |
strokeWidth | PropTypes.number | 2 | Sets the strokeWidth attribute of the line path. |
<VerticalReferenceLine />
@TODO picture
This component can be used to render a single vertical reference line to call out a point of interest. It takes the following props:
Name | Type | Default | Description |
---|
reference | PropTypes.oneOfType([PropTypes.number, PropTypes.oneOf(['first', 'last', 'min', 'max'] ])) | last | What reference to create a line for. This may be a raw number (x index) to call out, or one of 'first', 'last', 'min', 'max' which will compute the relevant x index value. |
LabelComponent | PropTypes.element | @data-ui/sparkline 's <Label /> component | Component to use for labels, if relevant. This component is cloned with appropriate x, y, dx, and dy values for positioning. |
labelOffset | PropTypes.number | 10 | (Absolute) pixel offset to use for positioning a label relative to a Point . labelPosition is used to determine direction. |
labelPosition | PropTypes.oneOf(['top', 'right', 'bottom', 'left']) | 'top' | A single string indicating how to position a label relative to the top of a reference line |
renderLabel | PropTypes.func | - | Optional function called for each datum, with the following signature (xVal) => node . If this is passed and returns a value, a label will be rendered. This is used as the child of LabelComponent so any valid child of svg <text> elements can be returned. |
stroke | PropTypes.string | @data-ui/theme s color.default | Sets the stroke of the line path. |
strokeDasharray | PropTypes.string | - | Sets the strokeDasharray attribute of the line path. |
strokeLinecap | PropTypes.oneOf(['butt', 'square', 'round', 'inherit']) | 'round' | Sets the strokeLinecap attribute of the line path. |
strokeWidth | PropTypes.number | 2 | Sets the strokeWidth attribute of the line path. |
<BandLine />
This component can be used to render ranges of interest as opposed to single values. It may be used to create vertical or horizontal bands and takes the following props:
Name | Type | Default | Description |
---|
band | PropTypes.oneOfType([PropTypes.oneOf([ 'innerQuartiles' ]), PropTypes.shape({ from: PropTypes.shape({ x: PropTypes.number, y: PropTypes.number }).isRequired, to: PropTypes.shape({ x: PropTypes.number, y: PropTypes.number }) ]).isRequired }) | 'innerQuartiles' | Specifies the band to render. May be innerQuartiles which computes the midspread of the data values, or an object with the keys { from: coords, to: coords } specifying a custom band. If an x or y value is missing in either the from or to key, the bounds (min, max) of the chart are used. |
fill | PropTypes.string | @data-ui/theme s color.lightGray | Sets the fill of the bar shape. |
fillOpacity | PropTypes.number | 0.5 | Sets the fillOpacity of the bar shape. |
stroke | PropTypes.string | transparent | Sets the stroke of the bar shape. |
strokeWidth | PropTypes.number | 0 | Sets the strokeWidth of the bar shape. |
<PatternLines />
and <LinearGradient/>
s
These components are exported for convenience from @vx
to support customization of the aesthetics of your sparklines. They create <defs/>
elements with the specified id
, which are then referenced for fills or strokes in other components via url(#my_id)
. See example usage above and the Storybook for examples!
They take the following props:
<PatternLines />
Name | Type | Default | Description |
---|
id | PropTypes.string.isRequired | - | id for the <defs> that is created. When used as a fill in another component it can be referenced via url(#my_id) . |
width | PropTypes.number.isRequired | - | Width of the pattern (which is then repeated). |
height | PropTypes.number.isRequired | - | Height of the pattern (which is then repeated). |
stroke | PropTypes.string | - | Sets the stroke attribute of the pattern line. |
strokeWidth | PropTypes.number | - | Sets the strokeWidth attribute of the pattern line. |
strokeDasharray | PropTypes.string | - | Sets the strokeDasharray attribute of the pattern line. |
strokeLinecap | PropTypes.string | 'square' | Sets the strokeLinecap attribute of the pattern line. |
shapeRendering | PropTypes.string | 'auto' | Sets the shapeRendering attribute of the pattern line. |
orientation | PropTypes.arrayOf(PropTypes.oneOf(['vertical', 'horizontal', 'diagonal'])) | ['vertical'] | Array of orientations for lines. If multiple are passed, one path is rendered for each. |
background | PropTypes.string | - | Optional background fill for the pattern. |
className | PropTypes.string | - | Optional className added to the pattern path 's. |
<LinearGradient />
Name | Type | Default | Description |
---|
id | PropTypes.string.isRequired | - | id for the <defs> that is created. When used as a fill in another component it can be referenced via url(#my_id) . |
from | PropTypes.string | - | String used for the start color in the gradient. |
to | PropTypes.string | - | String used for the end color in the gradient. |
fromOffset | PropTypes.string | 0% | Sets the offset (as a %) of the from color. |
fromOpacity | PropTypes.number | 1 | Sets the opacity of the from color. |
toOffset | PropTypes.string | 100% | Sets the offset (as a %) of the to color |
toOpacity | PropTypes.number | 1 | Sets the opacity of the to color. |
rotate | PropTypes.oneOfType([PropTypes.string, PropTypes.number]) | - | Sets the transform attribute of the gradient to rotate(<rotate>) |
transform | PropTypes.string | - | Sets the gradientTransform of the linearGradient element, overridden by rotate |