Categories
React

Add Charts into Our React App with Victory — Data Processing

The Victory lets us add charts and data visualization into our React app.

In this article, we’ll look at how to add charts into our React app with Victory.

Specifying x and y Data

We can specify the data for the x and y axes with the property name if we have an array of objects as data.

For instance, we can write:

import React from "react";
import { VictoryBar, VictoryChart } from "victory";

export default function App() {
  return (
    <VictoryChart domainPadding={50}>
      <VictoryBar
        data={[
          { employee: "Jane Doe", salary: 65000 },
          { employee: "John Doe", salary: 62000 }
        ]}
        x="employee"
        y="salary"
      />
    </VictoryChart>
  );
}

We set the x and y props to the property names with the data for the x and y axes respectively.

If we have an array of arrays, we can specify the index with the data we want to display for the x and y axes:

import React from "react";
import { VictoryBar, VictoryChart } from "victory";

export default function App() {
  return (
    <VictoryChart domainPadding={50}>
      <VictoryBar
        data={[
          [1, 1],
          [2, 3],
          [3, 1]
        ]}
        x={0}
        y={1}
      />
    </VictoryChart>
  );
}

If we have an array od nested objects, we can also specify the path string or an array of strings to form the property path with the data we want to display:

import React from "react";
import { VictoryBar, VictoryChart } from "victory";

export default function App() {
  return (
    <VictoryChart domainPadding={50}>
      <VictoryBar
        data={[
          {
            employee: { firstName: "Jane", lastName: "Doe" },
            salary: { base: 65000, bonus: 2000 }
          },
          {
            employee: { firstName: "John", lastName: "Doe" },
            salary: { base: 62000, bonus: 6000 }
          }
        ]}
        x="employee.firstName"
        y={["salary", "base"]}
      />
    </VictoryChart>
  );
}

Processing Data

We can process data by passing in functions for the x and y props:

import React from "react";
import { VictoryAxis, VictoryBar, VictoryChart } from "victory";

export default function App() {
  return (
    <VictoryChart domainPadding={{ x: 40 }}>
      <VictoryBar
        data={[
          { experiment: "trial 1", expected: 3.95, actual: 3.21 },
          { experiment: "trial 2", expected: 3.95, actual: 3.38 },
          { experiment: "trial 3", expected: 3.95, actual: 2.05 },
          { experiment: "trial 4", expected: 3.95, actual: 3.71 }
        ]}
        x="experiment"
        y={(d) => (d.actual / d.expected) * 100}
      />
      <VictoryAxis
        label="experiment"
        style={{
          axisLabel: { padding: 30 }
        }}
      />
      <VictoryAxis
        dependentAxis
        label="percent yield"
        style={{
          axisLabel: { padding: 40 }
        }}
      />
    </VictoryChart>
  );
}

We pass in a function to compute the value of y to display with a function.

d has the data entry we want to compute.

Sorting Data

We can sort our data with the sortKey prop:

import React from "react";
import { VictoryChart, VictoryLine } from "victory";
import { range } from "lodash";

export default function App() {
  return (
    <VictoryChart domainPadding={{ x: 40 }}>
      <VictoryLine
        data={range(0, 2 * Math.PI, 0.01).map((t) => ({ t }))}
        sortKey="t"
        x={({ t }) => Math.sin(3 * t + 2 * Math.PI)}
        y={({ t }) => Math.sin(2 * t)}
      />
    </VictoryChart>
  );
}

Since sortKey is set to t , we sort by the t value.

Conclusion

We can process our data in various ways to create the chart we want with React Victory.

Categories
React

Add Charts into Our React App with Victory — Custom Chart Components

The Victory lets us add charts and data visualization into our React app.

In this article, we’ll look at how to add charts into our React app with Victory.

Polygon Charts

We can add polygon charts with the Polygon component.

For instance, we can write:

import React from "react";
import { VictoryChart, VictoryScatter } from "victory";

const data = [
  { x: 2, y: 1 },
  { x: 3, y: 5 },
  { x: 6, y: 3 }
];

const Polygon = (props) => {
  const getPoints = (data, scale) => {
    return data.reduce(
      (pointStr, { x, y }) => `${pointStr} ${scale.x(x)},${scale.y(y)}`,
      ""
    );
  };

  const { data, style, scale } = props;
  const points = getPoints(data, scale);
  return <polygon points={points} style={style} />;
};

export default function App() {
  return (
    <VictoryChart height={400} width={400} domain={[-10, 10]}>
      <Polygon data={data} style={{ fill: "tomato", opacity: 0.5 }} />
      <VictoryScatter data={data} />
    </VictoryChart>
  );
}

We create the getPoint function in the Polygon component to create the point string for the polygon path.

Then we pass that into the polygon element to create the points.

In App , we pass in the Polygon component with the data prop to create the polygon from the given corner points.

We render the same points as dots with the VictoryScatter component.

Using Victory Components to Create Custom Components

We can use Victory components to create custom components.

For instance, we can write:

import React from "react";
import {
  VictoryAxis,
  VictoryChart,
  VictoryGroup,
  VictoryLine,
  VictoryPie,
  VictoryScatter
} from "victory";

const data = [
  { x: 2, y: 1 },
  { x: 3, y: 5 },
  { x: 6, y: 3 }
];

const CustomPie = (props) => {
  const { datum, x, y } = props;
  const pieWidth = 120;

  return (
    <g transform={`translate(${x - pieWidth / 2}, ${y - pieWidth / 2})`}>
      <VictoryPie
        standalone={false}
        height={pieWidth}
        width={pieWidth}
        data={datum.pie}
        style={{ labels: { fontSize: 0 } }}
        colorScale={["#f77", "#55e", "#8af"]}
      />
    </g>
  );
};

export default function App() {
  return (
    <VictoryChart domain={{ y: [0, 100] }}>
      <VictoryAxis />
      <VictoryGroup data={data}>
        <VictoryLine />
        <VictoryScatter dataComponent={<CustomPie />} />
      </VictoryGroup>
    </VictoryChart>
  );
}

We create the CustomPie component that renders small pie charts with the VictoryPie component to render pie charts as points.

The in App , we render VictoryGroup to render the data by setting it as the data prop.

VictoryScatter lets us render the points.

And we set CustomPie as the dataComponent prop to render the pies as points.

We can pass in any SVG component as point components in the dataComponent prop.

For instance, we can use styled-components to create the SVG circles for the points:

import React from "react";
import styled from "styled-components";
import { VictoryChart, VictoryLine, VictoryScatter } from "victory";

const data = [
  { x: 2, y: 1 },
  { x: 3, y: 5 },
  { x: 6, y: 3 }
];

const StyledPoint = styled.circle`
  fill: ${(props) => props.color};
`;

const colors = ["#A8E6CE", "#DCEDC2", "#FFD3B5", "#FFAAA6", "#FF8C94"];

const ScatterPoint = ({ x, y, datum, min, max }) => {
  const i = React.useMemo(() => {
    return Math.floor(((datum.y - min) / (max - min)) * (colors.length - 1));
  }, [datum, min, max]);

return <StyledPoint color={colors[i]} cx={x} cy={y} r={6} />;
};

export default function App() {
  const temperatures = data.map(({ y }) => y);
  const min = Math.min(...temperatures);
  const max = Math.max(...temperatures);

  return (
    <VictoryChart>
      <VictoryLine data={data} />
      <VictoryScatter
        data={data}
        dataComponent={<ScatterPoint min={min} max={max} />}
      />
    </VictoryChart>
  );
}

The StyledPoint component has the points.

And ScatterPoint renders the StyledPoint with the fill color for the point.

Then we pass the ScatterPoint as the value of dataComponent to render the points.

Conclusion

We can render polygon charts and create custom components for charts with React Victory.

Categories
React

Add Charts into Our React App with Victory — Custom Labels and Points

The Victory lets us add charts and data visualization into our React app.

In this article, we’ll look at how to add charts into our React app with Victory.

Altering Default Label Components

We can override the appearance of the components that comes with Victory.

For instance, we can change the labels that are displayed with bar charts by writing:

import React from "react";
import { VictoryBar, VictoryLabel } from "victory";

export default function App() {
  return (
    <VictoryBar
      data={[
        { x: 1, y: 3, label: "Alpha" },
        { x: 2, y: 4, label: "Bravo" },
        { x: 3, y: 6, label: "Charlie" },
        { x: 4, y: 3, label: "Delta" },
        { x: 5, y: 7, label: "Echo" }
      ]}
      labelComponent={
        <VictoryLabel angle={90} verticalAnchor="middle" textAnchor="end" />
      }
    />
  );
}

We set the angle of the VictoryLabel to display the labels vertically.

textAnchor is set to end to move them to the right.

Wrapping Components

We can wrap components to display what we want.

For instance, we can create our own wrapper component to add labels to our chart:

import React from "react";
import { VictoryChart, VictoryLabel, VictoryScatter } from "victory";

const WrapperComponent = (props) => {
  const renderChildren = () => {
    const children = React.Children.toArray(props.children);
    return children.map((child) => {
      const style = { ...child.props.style, ...props.style };
      return React.cloneElement(
        child,
        Object.assign({}, child.props, props, { style })
      );
    });
  };

  return (
    <g transform="translate(20, 40)">
      <VictoryLabel text={"add labels"} x={110} y={30} />
      <VictoryLabel text={"offset data from axes"} x={70} y={150} />
      <VictoryLabel text={"alter props"} x={280} y={150} />
      {renderChildren()}
    </g>
  );
};

export default function App() {
  return (
    <VictoryChart>
      <WrapperComponent>
        <VictoryScatter
          y={(d) => Math.sin(2 * Math.PI * d.x)}
          samples={15}
          symbol="square"
          size={6}
          style={{ data: { stroke: "tomato", strokeWidth: 3 } }}
        />
      </WrapperComponent>
    </VictoryChart>
  );
}

WrapperComponent takes the child components from the children prop and render them with React.cloneElement .

We also combine the styles by merging the styles from the child and the props.

In the return statement, we have the VictoryLabel s and call the renderChildren function to render the child items.

Then in App , we render VictoryScatter in the WrapperComponent to render the sine curve with the VictoryLabel s.

Customize Points

For instance, we can create the CatPoint component and pass that as the value of dataComponent in the VictoryScatter component:

import React from "react";
import { VictoryChart, VictoryScatter } from "victory";

const CatPoint = (props) => {
  const { x, y, datum } = props;
  const cat = datum._y >= 0 ? "?" : "?";
  return (
    <text x={x} y={y} fontSize={30}>
      {cat}
    </text>
  );
};

export default function App() {
  return (
    <VictoryChart>
      <VictoryScatter
        y={(d) => Math.sin(2 * Math.PI * d.x)}
        samples={25}
        dataComponent={<CatPoint />}
      />
    </VictoryChart>
  );
}

We get the data entry from the datum prop, and the _y property has the y value.

x and y has the position.

Conclusion

We can customize labels and points with charts created with Victory in our React app.

Categories
React

Add Charts into Our React App with Victory — Custom Chart

The Victory lets us add charts and data visualization into our React app.

In this article, we’ll look at how to add charts into our React app with Victory.

Custom Chart

We can create a custom chart by adding multiple components together.

For instance, we can write:

import React from "react";
import { VictoryAxis, VictoryLabel, VictoryLine } from "victory";

const getDataSetOne = () => {
  return [
    { x: new Date(2000, 1, 1), y: 12 },
    { x: new Date(2001, 6, 1), y: 10 },
    { x: new Date(2002, 12, 1), y: 11 },
    { x: new Date(2003, 1, 1), y: 5 },
    { x: new Date(2004, 1, 1), y: 4 }
  ];
};

const getDataSetTwo = () => {
  return [
    { x: new Date(2000, 1, 1), y: 5 },
    { x: new Date(2001, 1, 1), y: 6 },
    { x: new Date(2002, 1, 1), y: 4 },
    { x: new Date(2003, 1, 1), y: 10 },
    { x: new Date(2004, 1, 1), y: 12 }
  ];
};

const getTickValues = () => {
  return [
    new Date(2000, 1, 1),
    new Date(2001, 1, 1),
    new Date(2002, 1, 1),
    new Date(2003, 1, 1),
    new Date(2004, 1, 1)
  ];
};

const dataSetOne = getDataSetOne();
const dataSetTwo = getDataSetTwo();
const tickValues = getTickValues();

export default function App() {
  return (
    <svg viewBox="0 0 450 350">
      <VictoryLabel
        x={25}
        y={55}
        text={"Economy n % change on a year earlier"}
      />
      <VictoryLabel x={200} y={55} text={"Dinosaur exportsn $bn"} />

<g transform={"translate(0, 40)"}>
        <VictoryAxis
          scale="time"
          standalone={false}
          tickValues={tickValues}
          tickFormat={(x) => x.getFullYear()}
        />
        <VictoryAxis
          dependentAxis
          domain={[-10, 15]}
          offsetX={50}
          orientation="left"
          standalone={false}
        />
        <VictoryLine
          data={[
            { x: new Date(2000, 1, 1), y: 0 },
            { x: new Date(2004, 6, 1), y: 0 }
          ]}
          domain={{
            x: [new Date(2000, 1, 1), new Date(2004, 1, 1)],
            y: [-10, 15]
          }}
          scale={{ x: "time", y: "linear" }}
          standalone={false}
        />
        <VictoryLine
          data={dataSetOne}
          domain={{
            x: [new Date(2000, 1, 1), new Date(2004, 1, 1)],
            y: [-10, 15]
          }}
          interpolation="monotoneX"
          scale={{ x: "time", y: "linear" }}
          standalone={false}
        />
        <VictoryAxis
          dependentAxis
          domain={[0, 50]}
          orientation="right"
          standalone={false}
        />
        <VictoryLine
          data={dataSetTwo}
          domain={{
            x: [new Date(2000, 1, 1), new Date(2004, 1, 1)],
            y: [0, 50]
          }}
          interpolation="monotoneX"
          scale={{ x: "time", y: "linear" }}
          standalone={false}
        />
      </g>
    </svg>
  );
}

We get our data for the lines with the functions.

Then we add the labels with the VictoryLabel components.

We set the x and y props to set their positions.

Then we put our chart components in the g element.

VictoryAxis renders the x-axis.

We set the scale to 'time' to render the dates on the axis.

Also, we set the offsetX to shift the axis.

The first VictoryLine has renders a horizontal line.

We set the data prop to set the data.

Also, we set the x and y domain to set the range of values to show on the axis.

scale is set individually for x and y since they have different scales.

And we set standalone to false so we can add more to the chart.

Then add another VictoryLine to render the data from dataSetOne .

We add another VictoryAxis to put a y-axis on the right side. And we set their own domain.

Then add another VictoryLine to render the data from dataSetTwo.

Now we get a line chart with 3 lines, one y-axis each on each side, an x-axis at the bottom, and labels at the top of the chart.

Conclusion

We can add custom charts with the components that comes with Victory in our React app.

Categories
React

Add Charts into Our React App with Victory — Transition, Brush and Zoom

The Victory lets us add charts and data visualization into our React app.

In this article, we’ll look at how to add charts into our React app with Victory.

Transitions

We can set the transition effects for animations with the VictoryBar component.

For instance, we can write:

import React, { useEffect, useState } from "react";
import { VictoryBar, VictoryChart } from "victory";

const random = (min, max) => Math.floor(min + Math.random() * max);

const getData = () => {
  const bars = random(6, 10);
  return Array(bars)
    .fill()
    .map((_, index) => {
      return {
        x: index + 1,
        y: random(2, 100)
      };
    });
};

export default function App() {
  const [data, setData] = useState([]);
  useEffect(() => {
    const timer = setInterval(() => {
      setData(getData());
    }, 3000);
    return () => clearInterval(timer);
  }, []);

  return (
    <VictoryChart domainPadding={{ x: 20 }} animate={{ duration: 500 }}>
      <VictoryBar
        data={data}
        style={{
          data: { fill: "tomato", width: 12 }
        }}
        animate={{
          onExit: {
            duration: 500,
            before: () => ({
              _y: 0,
              fill: "orange",
              label: "BYE"
            })
          }
        }}
      />
    </VictoryChart>
  );
}

We generate random data for our graph and update it with the new data every 3 seconds.

We set the animate prop on the VictoryBar component to add transition effects for the bars.

onExit.duration has the duration of the leave animation.

We change the color of the bars with fill property.

And the label is displayed when the bars leave the screen.

Brush and Zoom

We can add brush and zoom into our charts with the VictoryChart‘s containerComponent prop.

For instance, we can write:

import React from "react";
import { VictoryChart, VictoryScatter, VictoryZoomContainer } from "victory";

const random = (min, max) => Math.floor(min + Math.random() * max);

const getData = () => {
  return Array(50)
    .fill()
    .map((index) => {
      return {
        x: random(1, 50),
        y: random(10, 90),
        size: random(8) + 3
      };
    });
};

export default function App() {
  return (
    <VictoryChart
      domain={{ y: [0, 100] }}
      containerComponent={
        <VictoryZoomContainer zoomDomain={{ x: [5, 35], y: [0, 100] }} />
      }
    >
      <VictoryScatter
        data={getData()}
        style={{
          data: {
            opacity: ({ datum }) => (datum.y % 5 === 0 ? 1 : 0.7),
            fill: ({ datum }) => (datum.y % 5 === 0 ? "tomato" : "black")
          }
        }}
      />
    </VictoryChart>
  );
}

We set containerComponent to the VictoryZoomContainer component.

The zoomDomain prop lets us set the zoom level range for the x and y axes with the x and y properties.

We can also create a separate chart for the brush:

import React, { useState } from "react";
import {
  VictoryAxis,
  VictoryBrushContainer,
  VictoryChart,
  VictoryLine,
  VictoryZoomContainer
} from "victory";

export default function App() {
  const [selectedDomain, setSelectedDomain] = useState();
  const [zoomDomain, setZoomDomain] = useState();

const handleZoom = (domain) => {
    setSelectedDomain(domain);
  };

const handleBrush = (domain) => {
    setZoomDomain(domain);
  };

return (
    <>
      <VictoryChart
        width={550}
        height={300}
        scale={{ x: "time" }}
        containerComponent={
          <VictoryZoomContainer
            responsive={false}
            zoomDimension="x"
            zoomDomain={zoomDomain}
            onZoomDomainChange={handleZoom}
          />
        }
      >
        <VictoryLine
          style={{
            data: { stroke: "tomato" }
          }}
          data={[
            { x: new Date(1982, 1, 1), y: 125 },
            { x: new Date(1987, 1, 1), y: 257 },
            { x: new Date(1993, 1, 1), y: 345 },
            { x: new Date(1997, 1, 1), y: 515 },
            { x: new Date(2001, 1, 1), y: 132 },
            { x: new Date(2005, 1, 1), y: 305 },
            { x: new Date(2011, 1, 1), y: 270 },
            { x: new Date(2015, 1, 1), y: 470 }
          ]}
        />
      </VictoryChart>

<VictoryChart
        width={550}
        height={90}
        scale={{ x: "time" }}
        padding={{ top: 0, left: 50, right: 50, bottom: 30 }}
        containerComponent={
          <VictoryBrushContainer
            responsive={false}
            brushDimension="x"
            brushDomain={selectedDomain}
            onBrushDomainChange={handleBrush}
          />
        }
      >
        <VictoryAxis
          tickValues={[
            new Date(1985, 1, 1),
            new Date(1990, 1, 1),
            new Date(1995, 1, 1),
            new Date(2000, 1, 1),
            new Date(2005, 1, 1),
            new Date(2010, 1, 1),
            new Date(2015, 1, 1)
          ]}
          tickFormat={(x) => new Date(x).getFullYear()}
        />
        <VictoryLine
          style={{
            data: { stroke: "tomato" }
          }}
          data={[
            { x: new Date(1982, 1, 1), y: 125 },
            { x: new Date(1987, 1, 1), y: 257 },
            { x: new Date(1993, 1, 1), y: 345 },
            { x: new Date(1997, 1, 1), y: 515 },
            { x: new Date(2001, 1, 1), y: 132 },
            { x: new Date(2005, 1, 1), y: 305 },
            { x: new Date(2011, 1, 1), y: 270 },
            { x: new Date(2015, 1, 1), y: 470 }
          ]}
        />
      </VictoryChart>
    </>
  );
}

We do this by setting the zoomDomain and the selectedDomain by dragging on the bottom graph.

In the bottom VictoryChart , we have the containerComponent set to the VictoryBrushContainer .

brushDomain is set to the selectedDomain ,

And the onBrushDomainChange is set to the handleBrush function to change selectedDomain .

The location will be reflected in the top chart.

We have similar code to set the zoomDomain in the top chart.

The zoom is reflected in the bottom chart.

Conclusion

We can add transitions, brush, and zoom into charts in our React app with Victory.