Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
@visx/xychart
Advanced tools
@visx/xychart is a powerful and flexible library for creating complex and customizable charts in React applications. It leverages D3 for calculations and rendering, providing a declarative API for building various types of XY charts.
Line Chart
This code demonstrates how to create a simple line chart using @visx/xychart. It includes animated axes, grid, and a line series with a tooltip.
import { XYChart, AnimatedAxis, AnimatedGrid, AnimatedLineSeries, Tooltip } from '@visx/xychart';
const data = [
{ x: 0, y: 50 },
{ x: 1, y: 10 },
{ x: 2, y: 20 },
{ x: 3, y: 30 },
{ x: 4, y: 40 },
];
const accessors = {
xAccessor: d => d.x,
yAccessor: d => d.y,
};
function LineChart() {
return (
<XYChart height={300} width={500} xScale={{ type: 'linear' }} yScale={{ type: 'linear' }}>
<AnimatedAxis orientation="bottom" />
<AnimatedAxis orientation="left" />
<AnimatedGrid columns={false} numTicks={4} />
<AnimatedLineSeries dataKey="Line Series" data={data} {...accessors} />
<Tooltip />
</XYChart>
);
}
Bar Chart
This code demonstrates how to create a bar chart using @visx/xychart. It includes animated axes, grid, and a bar series with a tooltip.
import { XYChart, AnimatedAxis, AnimatedGrid, AnimatedBarSeries, Tooltip } from '@visx/xychart';
const data = [
{ x: 'A', y: 30 },
{ x: 'B', y: 80 },
{ x: 'C', y: 45 },
{ x: 'D', y: 60 },
{ x: 'E', y: 20 },
];
const accessors = {
xAccessor: d => d.x,
yAccessor: d => d.y,
};
function BarChart() {
return (
<XYChart height={300} width={500} xScale={{ type: 'band' }} yScale={{ type: 'linear' }}>
<AnimatedAxis orientation="bottom" />
<AnimatedAxis orientation="left" />
<AnimatedGrid columns={false} numTicks={4} />
<AnimatedBarSeries dataKey="Bar Series" data={data} {...accessors} />
<Tooltip />
</XYChart>
);
}
Scatter Plot
This code demonstrates how to create a scatter plot using @visx/xychart. It includes animated axes, grid, and a point series with a tooltip.
import { XYChart, AnimatedAxis, AnimatedGrid, AnimatedPointSeries, Tooltip } from '@visx/xychart';
const data = [
{ x: 10, y: 20 },
{ x: 20, y: 30 },
{ x: 30, y: 40 },
{ x: 40, y: 50 },
{ x: 50, y: 60 },
];
const accessors = {
xAccessor: d => d.x,
yAccessor: d => d.y,
};
function ScatterPlot() {
return (
<XYChart height={300} width={500} xScale={{ type: 'linear' }} yScale={{ type: 'linear' }}>
<AnimatedAxis orientation="bottom" />
<AnimatedAxis orientation="left" />
<AnimatedGrid columns={false} numTicks={4} />
<AnimatedPointSeries dataKey="Point Series" data={data} {...accessors} />
<Tooltip />
</XYChart>
);
}
Recharts is a composable charting library built on React components. It provides a wide range of chart types and is known for its simplicity and ease of use. Compared to @visx/xychart, Recharts offers a more straightforward API but may lack some of the advanced customization options.
Nivo provides a rich set of dataviz components, built on top of D3 and React. It offers a variety of chart types and is highly customizable. Nivo is similar to @visx/xychart in terms of flexibility and customization but provides more out-of-the-box chart types and themes.
Victory is a collection of composable React components for building interactive data visualizations. It is known for its modularity and ease of integration. Victory offers a balance between ease of use and customization, similar to @visx/xychart, but with a different approach to component composition.
In contrast to other visx
packages which are low-level, this package seeks to abstract some of the
complexity of common visualization engineering, and exposes a high-level x,y (cartesian
coordinate) chart API. However, it is implemented using modularized React.context
layers for
theme, canvas dimensions, x/y/color scales, data, events, and tooltips which allows for more
expressivity and advanced use cases.
Out of the box it supports the following:
<*Series />
types (animated or not) such as lines, bars, etc.<Axis />
(animated or not)<Grid />
(animated or not)<Annotation />
(animated or not)<Tooltip />
theme
ingThe following illustrates basic usage to create an animated line chart with a bottom Axis
, Grid
,
and Tooltip
:
import {
AnimatedAxis, // any of these can be non-animated equivalents
AnimatedGrid,
AnimatedLineSeries,
XYChart,
Tooltip,
} from '@visx/xychart';
const data1 = [
{ x: '2020-01-01', y: 50 },
{ x: '2020-01-02', y: 10 },
{ x: '2020-01-03', y: 20 },
];
const data2 = [
{ x: '2020-01-01', y: 30 },
{ x: '2020-01-02', y: 40 },
{ x: '2020-01-03', y: 80 },
];
const accessors = {
xAccessor: (d) => d.x,
yAccessor: (d) => d.y,
};
const render = () => (
<XYChart height={300} xScale={{ type: 'band' }} yScale={{ type: 'linear' }}>
<AnimatedAxis orientation="bottom" />
<AnimatedGrid columns={false} numTicks={4} />
<AnimatedLineSeries dataKey="Line 1" data={data1} {...accessors} />
<AnimatedLineSeries dataKey="Line 2" data={data2} {...accessors} />
<Tooltip
snapTooltipToDatumX
snapTooltipToDatumY
showVerticalCrosshair
showSeriesGlyphs
renderTooltip={({ tooltipData, colorScale }) => (
<div>
<div style={{ color: colorScale(tooltipData.nearestDatum.key) }}>
{tooltipData.nearestDatum.key}
</div>
{accessors.xAccessor(tooltipData.nearestDatum.datum)}
{', '}
{accessors.yAccessor(tooltipData.nearestDatum.datum)}
</div>
)}
/>
</XYChart>
);
See sections below for more detailed guidance and advanced usage, or explore the comprehensive API below.
npm install --save @visx/xychart react-spring
Note: react-spring
is a required peerDependency
for importing Animated*
components.
The following Series
types are currently supported and we are happy to review or consider
additional Series types in the future.
| Component name | Description | Usage |
| --------------------- | ------------------------------------------------------------------------------------------------ | ---------------------------------------------------- | --- |
| (Animated)AreaSeries | Connect data points with a <path />
, with a color fill to the zero baseline | <AreaSeries />
|
| (Animated)BarSeries | Render a <rect />
for each data point | <BarSeries />
|
| (Animated)BarGroup | Group multiple child <BarSeries />
values together | <BarGroup><BarSeries /><BarSeries />...</BarGroup>
|
| (Animated)BarStack | Stack multiple child <BarSeries />
values together | <BarStack><BarSeries /><BarSeries />...</BarStack>
| |
| (Animated)GlyphSeries | Render a Glyph
(any shape, defaults to <circle />
) for each data point, e.g., a scatter plot | <GlyphSeries renderGlyph={() => ...} />
|
| (Animated)LineSeries | Connect data points with a <path>
| <GlyphSeries />
|
All Series
have animated and non-animated variants to give you more control over your bundle size,
support missing (null
) data, and can be rendered vertically or horizontally.
Default lightTheme
and darkTheme
themes are exported from @visx/xychart
and the utility
buildChartTheme
is exported to support easy creation of custom themes.
import { buildChartTheme, XYChart } from '@visx/xychart';
import { TextProps as SVGTextProps } from '@visx/text/lib/Text'; // just for types
const customTheme = buildChartTheme({
// colors
backgroundColor: string, // used by Tooltip, Annotation
colors: string[], // categorical colors, mapped to series via `dataKey`s
// labels
svgLabelBig?: SVGTextProps,
svgLabelSmall?: SVGTextProps,
htmlLabel?: HTMLTextStyles,
// lines
xAxisLineStyles?: LineStyles,
yAxisLineStyles?: LineStyles,
xTickLineStyles?: LineStyles,
yTickLineStyles?: LineStyles,
tickLength: number,
// grid
gridColor: string,
gridColorDark: string, // used for axis baseline if x/yxAxisLineStyles not set
gridStyles?: CSSProperties,
});
() => <XYChart theme={customTheme} />
@visx/tooltip
Tooltip
s are integrated into @visx/xychart
, and should be rendered as a child of
XYChart
(or a child where TooltipContext
is provided).
Tooltip
positioning is handled by the Tooltip
itself, based on TooltipContext
. Tooltip
is rendered inside a Portal
, avoiding clipping by parent DOM elements with higher z-index
contexts. See the API below for a full list of props
to support additional behavior, such as
snapping to data point positions and rendering cross-hairs.
Tooltip
content is controlled by the specified prop.renderTooltip
which has access to:
tooltipData.nearestDatum
– the globally closest Datum
, across all Series
's dataKey
stooltipData.datumByKey
– the closest Datum
for each Series
's dataKey
; this enables
"shared tooltips" where you can render the nearest data point for each Series
.colorScale
which maps Series
's dataKey
s to theme
colorsThe following PointerEvent
s (handling both MouseEvent
s and TouchEvent
s) are currently
supported. They may be set on individual Series
components (e.g.,
<BarSeries onPointerMove={() => ...} />
), or at the chart level (e.g.,
<XYChart onPointerMove={() => {}} />
) in which case they are invoked once for every *Series
.
To disable event emitting for any Series
set <*Series enableEvents=false />
. The
onFocus/onBlur
handlers enable you to make your chart events and Tooltip
s accessible via
keyboard interaction. Note that the current implementation requires your target browser to support
the SVG 2.0
spec for tabIndex
on SVG
elements.
Below, HandlerParms
has the following type signature:
type EventHandlerParams<Datum> = {
datum: Datum; // nearest Datum to event, for Series with `dataKey=key`
distanceX: number; // x distance between event and Datum, in px
distanceY;: number; // y distance between event and Datum, in px
event: React.PointerEvent | React.FocusEvent; // the event
index: number; // index of Datum in Series `data` array
key: string; // `dataKey` of Series to which `Datum` belongs
svgPoint: { x: number; y: number }; // event position in svg-coordinates
};
Prop name | Signature | XYChart support | *Series support |
---|---|---|---|
onPointerMove | (params: EventHandlerParams<Datum>) => void | ✅ | ✅ |
onPointerOut | (event: React.PointerEvent) => void | ✅ | ✅ |
onPointerUp | (params: EventHandlerParams<Datum>) => void | ✅ | ✅ |
onPointerDown | (params: EventHandlerParams<Datum>) => void | ✅ | ✅ |
onFocus | (params: EventHandlerParams<Datum>) => void | ❌ | ✅ |
onBlur | (event: React.TouchEvent) => void | ❌ | ✅ |
Composable @visx/annotations
annotations are integrated into @visx/xychart
and use its theme and
dimension context. These components allow for annotation of individual points using
AnnotationCircleSubject
, or x- or y-thresholds using AnnotationLineSubject
.
import React from 'react';
import {
Annotation,
AnnotationLabel,
AnnotationConnector,
AnnotationCircleSubject,
Grid,
LineSeries,
XYChart,
} from '@visx/xychart';
const data = [
{ x: '2020-01-01', y: 50 },
{ x: '2020-01-02', y: 10 },
{ x: '2020-01-03', y: 20 },
{ x: '2020-01-04', y: 5 },
];
const labelXOffset = -40;
const labelYOffset = -50;
const chartConfig = {
xScale: { type: 'band' },
yScale: { type: 'linear' },
height: 300,
margin: { top: 10, right: 10, bottom: 10, left: 10 },
};
export default () => (
<XYChart {...chartConfig}>
<Grid numTicks={3} />
<LineSeries dataKey="line" data={data} xAccessor={d => d.x} yAccessor={d => d.y} />
<Annotation
dataKey="line" // use this Series's accessor functions, alternatively specify x/yAccessor here
datum={data[2]}
dx={labelXOffset}
dy={labelYOffset}
>
{/** Text label */}
<AnnotationLabel
title="Title"
subtitle="Subtitle deets"
showAnchorLine={false}
backgroundFill="rgba(0,150,150,0.1)"
/>
{/** Draw circle around point */}
<AnnotationCircleSubject />
{/** Connect label to CircleSubject */}
<AnnotationConnector />
</AnimatedAnnotation>
</XYChart>
);
ResizeObserver
dependencyResponsive XYChart
s, Tooltip
, and AnnotationLabel
components rely on
ResizeObserver
s. If your
browser target needs a polyfill, you can either pollute the window
object or inject it cleanly
using the resizeObserverPolyfill
prop for these components. A polyfill passed to XYChart
will be
accessible to child Tooltip
and AnnotationLabel
components.
❌ Error: This browser does not support ResizeObserver out of the box
// no polyfill, no browser support
() => <XYChart {...} />
() => <XYChart {...}><Tooltip /></XYChart>
✅ No errors
// no polyfill, target browser supports ResizeObserver
() => <XYChart {...} />
() => <XYChart {...}><Tooltip /></XYChart>
// import the polyfill in the needed module, or set it on `window` object
import ResizeObserver from 'resize-observer-polyfill';
() => <XYChart {...}><Tooltip /></XYChart> // 😎
// cleanly pass polyfill to component that needs it
import ResizeObserver from 'resize-observer-polyfill';
() => (
<XYChart resizeObserverPolyfill={ResizeObserver} {...}>
<Tooltip />
</XYChart>
)
XYChart
is implemented using modularized React.context
layers for scales, canvas dimensions,
data, events, and tooltips which enables more advanced usage than many other chart-level
abstractions.
By default XYChart
renders all context providers if a given context is not available, but you can
share context across multiple XYChart
s to implement functionality such as linked tooltips, shared
themes, or shared data.
This context provides chart canvas dimensions (width
, height
, and margin
), x/y/color scales,
and a data registry. The data registry includes data from all child *Series
, and x/y/color scales
are updated accordingly accounting for canvas dimensions.
This context provides an XYChart
theme, its used by all visual elements that compose a chart, and
can be used to render custom visual elements that are on theme.
This context provides an event publishing / subscription object which can be used via the
useEventEmitter
hook. Series
and XYChart
events, including tooltip updates, are emitted and
handled with through this context.
import React, { useState } from 'react';
import { useEventEmitter, EventEmitterProvider } from '@visx/xychart';
const eventSourceId = 'optional-source-id-filter';
const EmitEvent = () => {
const emit = useEventEmitter();
return (
<button onPointerUp={(event) => emit('pointerup', event, eventSourceId)}>emit event</button>
);
};
const SubscribeToEvent = () => {
const [clickCount, setClickCount] = useState(0);
const allowedEventSources = [eventSourceId];
useEventEmitter('pointerup', () => setClickCount(clickCount + 1), allowedEventSources);
return <div>Emitted {clickCount} events</div>;
};
export default function Example() {
return (
<EventEmitterProvider>
<EmitEvent />
<SubscribeToEvent />
</EventEmitterProvider>
);
}
This context provides access to @visx/tooltip
s useTooltip
state, including whether the tooltip
is visible (tooltipOpen
), tooltlip position (tooltipLeft
, tooltipTop
),
tooltipData: { nearestDatum, datumByKey }
described above, and functions to update context
(hideTooltip
, showTooltip
, and updateTooltip
).
FAQs
Composable cartesian coordinate chart built with visx primitives
The npm package @visx/xychart receives a total of 140,576 weekly downloads. As such, @visx/xychart popularity was classified as popular.
We found that @visx/xychart demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 4 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.