Categories
React

Add Charts into Our React App with Victory — Tooltip Customization

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.

Mouse Following Tooltip

We can add a tooltip with a pointer that stretches when we move the mouse.

To add it, we write:

import React from "react";
import {
  VictoryAxis,
  VictoryChart,
  VictoryLine,
  VictoryScatter,
  VictoryTooltip,
  VictoryVoronoiContainer
} from "victory";

export default function App() {
  return (
    <VictoryChart
      domain={{ y: [0, 6] }}
      containerComponent={
        <VictoryVoronoiContainer
          mouseFollowTooltips
          voronoiDimension="x"
          labels={({ datum }) => `y: ${datum.y}`}
        />
      }
    >
      <VictoryScatter
        style={{ data: { fill: "red" }, labels: { fill: "red" } }}
        data={[
          { x: 0, y: 2 },
          { x: 2, y: 3 },
          { x: 4, y: 4 },
          { x: 6, y: 5 }
        ]}
      />
      <VictoryScatter
        data={[
          { x: 2, y: 2 },
          { x: 4, y: 3 },
          { x: 6, y: 4 },
          { x: 8, y: 5 }
        ]}
      />
    </VictoryChart>
  );
}

We add the mouseFollowTooltips prop to the VictoryVoronoiContainer component to add this feature.

Also, we can listen to other events with the events prop.

For instance, we can write:

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

export default function App() {
  return (
    <VictoryChart domain={{ x: [0, 11], y: [-10, 10] }}>
      <VictoryBar
        labelComponent={<VictoryTooltip />}
        data={[
          { x: 2, y: 5, label: "A" },
          { x: 4, y: -6, label: "B" },
          { x: 6, y: 4, label: "C" },
          { x: 8, y: -5, label: "D" },
          { x: 10, y: 7, label: "E" }
        ]}
        style={{
          data: { fill: "tomato", width: 20 }
        }}
        events={[
          {
            target: "data",
            eventHandlers: {
              onMouseOver: () => {
                return [
                  {
                    target: "data",
                    mutation: () => ({ style: { fill: "gold", width: 30 } })
                  },
                  {
                    target: "labels",
                    mutation: () => ({ active: true })
                  }
                ];
              },
              onMouseOut: () => {
                return [
                  {
                    target: "data",
                    mutation: () => {}
                  },
                  {
                    target: "labels",
                    mutation: () => ({ active: false })
                  }
                ];
              }
            }
          }
        ]}
      />
    </VictoryChart>
  );
}

We have the onMouseOver and onMouseOut properties with the target property to set which item to mutate.

And the mutation method to change the styles by returning an object with the styles we want.

Custom Tooltip

We can add a custom tooltip by creating our own tooltip component.

For instance, we can write:

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

const CustomTooltip = (props) => {
  const { x, y } = props;
  const rotation = `rotate(-45 ${x} ${y})`;
  return (
    <g transform={rotation}>
      <VictoryTooltip {...props} renderInPortal={false} />
    </g>
  );
};
CustomTooltip.defaultEvents = VictoryTooltip.defaultEvents;

export default function App() {
  return (
    <VictoryChart domain={{ x: [0, 11], y: [-10, 10] }}>
      <VictoryBar
        labelComponent={<CustomTooltip />}
        data={[
          { x: 2, y: 5, label: "A" },
          { x: 4, y: -6, label: "B" },
          { x: 6, y: 4, label: "C" },
          { x: 8, y: -5, label: "D" },
          { x: 10, y: 7, label: "E" }
        ]}
        style={{
          data: { fill: "tomato", width: 20 }
        }}
      />
    </VictoryChart>
  );
}

to create the CustomTooltip component.

We have to set the defaultEvents property to VictoryTooltip.defaultEvents for the tooltip to work since it adds the required event handlers for the tooltip.

Conclusion

We can add a mouse following tooltip and custom tooltips into our React charts with Victory.

Categories
React

Add Charts into Our React App with Victory — Tooltips

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.

Tooltips

We can add tooltips to charts.

For example, we can write:

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

export default function App() {
  return (
    <div>
      <VictoryChart domain={{ x: [0, 11], y: [-10, 10] }}>
        <VictoryBar
          labelComponent={<VictoryTooltip />}
          data={[
            { x: 2, y: 5, label: "right-side-up" },
            { x: 4, y: -6, label: "upside-down" },
            { x: 6, y: 4, label: "tiny" },
            { x: 8, y: -5, label: "or a little n BIGGER" },
            { x: 10, y: 7, label: "automatically" }
          ]}
          style={{
            data: { fill: "tomato", width: 20 }
          }}
        />
      </VictoryChart>
      ​
    </div>
  );
}

We set the labelComponent to the VictoryTooltip component to show the tooltip.

Also, we can change the tooltip styles with a few props:

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

export default function App() {
  return (
    <div>
      <VictoryChart domain={{ x: [0, 11], y: [-10, 10] }}>
        <VictoryBar
          labelComponent={
            <VictoryTooltip
              cornerRadius={({ datum }) => (datum.x > 6 ? 0 : 20)}
              pointerLength={({ datum }) => (datum.y > 0 ? 5 : 20)}
              flyoutStyle={{
                stroke: ({ datum }) => (datum.x === 10 ? "tomato" : "black")
              }}
            />
          }
          data={[
            { x: 2, y: 5, label: "right-side-up" },
            { x: 4, y: -6, label: "upside-down" },
            { x: 6, y: 4, label: "tiny" },
            { x: 8, y: -5, label: "or a little n BIGGER" },
            { x: 10, y: 7, label: "automatically" }
          ]}
          style={{
            data: { fill: "tomato", width: 20 }
          }}
        />
      </VictoryChart>
      ​
    </div>
  );
}

VictoryVoronoiContainer

The VictoryVoronoiContainer lets us add tooltips to a line or to data points that are too small to hover over.

For instance, we can write:

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

export default function App() {
  return (
    <div>
      <VictoryChart
        domain={{ x: [0, 5], y: [-5, 5] }}
        containerComponent={<VictoryVoronoiContainer />}
      >
        <VictoryScatter
          style={{
            data: { fill: "tomato" },
            labels: { fill: "tomato" }
          }}
          size={({ active }) => (active ? 5 : 3)}
          labels={({ datum }) => datum.y}
          labelComponent={<VictoryTooltip />}
          data={[
            { x: 1, y: -4 },
            { x: 2, y: 4 },
            { x: 3, y: 2 },
            { x: 4, y: 1 }
          ]}
        />
        <VictoryScatter
          style={{
            data: { fill: "blue" },
            labels: { fill: "blue" }
          }}
          size={(datum, active) => (active ? 5 : 3)}
          labels={({ datum }) => datum.y}
          labelComponent={<VictoryTooltip />}
          data={[
            { x: 1, y: -3 },
            { x: 2, y: 3 },
            { x: 3, y: 3 },
            { x: 4, y: 0 }
          ]}
        />
        <VictoryScatter
          data={[
            { x: 1, y: 4 },
            { x: 2, y: -4 },
            { x: 3, y: -2 },
            { x: 4, y: -3 }
          ]}
          labels={({ datum }) => datum.y}
          labelComponent={<VictoryTooltip />}
          size={({ active }) => (active ? 5 : 3)}
        />
      </VictoryChart>
    </div>
  );
}

We set the containerComponent prop’s value to VictoryVoronoiContainer to add the tooltip.

The content is set by the labels prop.

Conclusion

We can add various kinds of tooltips to our charts with React Victory.

Categories
React

Add Charts into Our React App with Victory — Events and Layouts

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.

Simple Events

We can attach events straight onto the chart components.

For instance, we can write:

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

export default function App() {
  return (
    <VictoryBar
      data={[
        { x: 1, y: 2 },
        { x: 2, y: 4 },
        { x: 3, y: 7 },
        { x: 4, y: 3 },
        { x: 5, y: 5 }
      ]}
      dataComponent={
        <Bar
          events={{
            onClick: (evt) => alert(`(${evt.clientX}, ${evt.clientY})`)
          }}
        />
      }
    />
  );
}

to attach a click handler to the Bar component with the events prop.

We get the click coordinates with the clientX and clientY properties from the event object.

Events on Custom Components

Also, we can attach event handlers to custom components.

For instance, we can write:

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

const ScatterPoint = ({ x, y, datum }) => {
  const [selected, setSelected] = React.useState(false);
  const [hovered, setHovered] = React.useState(false);

return (
    <circle
      cx={x}
      cy={y}
      r={datum.x * datum.y}
      stroke={hovered ? "purple" : "white"}
      strokeWidth={2}
      fill={selected ? "cyan" : "magenta"}
      onClick={() => setSelected(!selected)}
      onMouseEnter={() => setHovered(true)}
      onMouseLeave={() => setHovered(false)}
    />
  );
};

export default function App() {
  return (
    <VictoryChart>
      <VictoryScatter
        data={[
          { x: 1, y: 7 },
          { x: 2, y: 5 },
          { x: 3, y: 7 },
          { x: 4, y: 2 },
          { x: 5, y: 1 }
        ]}
        dataComponent={<ScatterPoint />}
      />
    </VictoryChart>
  );
}

to create the ScatterPoint component.

We add the onMouseEnter , onMouseLeave and onClick props to add the event handlers for those mouse events.

Layout

We can change the render order to change which component appears above which one.

For example, we can write:

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

export default function App() {
  return (
    <div>
      <VictoryChart>
        <VictoryScatter
          y={(data) => Math.sin(2 * Math.PI * data.x)}
          samples={25}
          size={5}
          style={{ data: { fill: "tomato" } }}
        />
        <VictoryLine
          style={{ data: { stroke: "orange" } }}
          y={(data) => Math.sin(2 * Math.PI * data.x)}
        />
        <VictoryAxis />
        <VictoryAxis dependentAxis />
      </VictoryChart>
    </div>
  );
}

to render the scatter points below the other components since it’s rendered first.

The items that are rendered earlier go below the ones that are rendered later.

VictoryPortal

We can also use the VictoryPortal component to render components in a top-level container.

This way, they appear above other components.

For instance, we wrap the VictoryLabel in the VictoryPortal :

import React from "react";
import {
  VictoryAxis,
  VictoryBar,
  VictoryChart,
  VictoryLabel,
  VictoryLine,
  VictoryPortal,
  VictoryScatter,
  VictoryStack
} from "victory";

export default function App() {
  return (
    <div>
      <VictoryChart domainPadding={40}>
        <VictoryStack
          colorScale={["gold", "orange", "tomato"]}
          style={{
            data: { width: 30 },
            labels: { padding: -20 }
          }}
          labelComponent={
            <VictoryPortal>
              <VictoryLabel />
            </VictoryPortal>
          }
        >
          <VictoryBar
            data={[
              { x: 1, y: 3, label: "C" },
              { x: 2, y: 4, label: "C" },
              { x: 3, y: 2, label: "C" }
            ]}
          />
          <VictoryBar
            data={[
              { x: 1, y: 3, label: "B" },
              { x: 2, y: 4, label: "B" },
              { x: 3, y: 2, label: "B" }
            ]}
          />
          <VictoryBar
            data={[
              { x: 1, y: 3, label: "A" },
              { x: 2, y: 4, label: "A" },
              { x: 3, y: 2, label: "A" }
            ]}
          />
        </VictoryStack>
        <VictoryAxis />
      </VictoryChart>
    </div>
  );
}

to render the labels above the other components.

Conclusion

We can render chart components in different orders and attach events to components with React Victory.

Categories
React

Add Charts into Our React App with Victory — Polar Charts

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.

Responsive VictoryContainer

We can set the responsive prop of the VictoryContainer component to render a responsive chart:

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

export default function App() {
  return (
    <div>
      <VictoryChart
        height={200}
        width={300}
        containerComponent={<VictoryContainer responsive />}
      >
        <VictoryLine y={(data) => Math.sin(2 * Math.PI * data.x)} />
      </VictoryChart>
    </div>
  );
}

Rendering Components in Custom Containers

We can render components in custom containers.

For instance, we can write:

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

export default function App() {
  return (
    <svg viewBox="0 0 400 400">
      <VictoryPie
        standalone={false}
        width={400}
        height={400}
        data={[
          { x: "A", y: 10 },
          { x: "B", y: 20 },
          { x: "C", y: 80 }
        ]}
        innerRadius={70}
        labelRadius={100}
        style={{ labels: { fontSize: 20, fill: "white" } }}
      />
      <circle
        cx="200"
        cy="200"
        r="65"
        fill="none"
        stroke="black"
        strokeWidth={3}
      />
      <circle
        cx="200"
        cy="200"
        r="155"
        fill="none"
        stroke="black"
        strokeWidth={3}
      />
      <VictoryLabel
        textAnchor="middle"
        verticalAnchor="middle"
        x={200}
        y={200}
        style={{ fontSize: 30 }}
        text="Label"
      />
    </svg>
  );
}

to render the pie chart in the svg element.

This is because the chart components are rendered as svgs.

Polar Charts

We can add polar charts into our React app.

For instance, we can write:

import React from "react";
import {
  VictoryAxis,
  VictoryBar,
  VictoryChart,
  VictoryPolarAxis,
  VictoryTheme
} from "victory";
const data = [
  { x: 1, y: 3 },
  { x: 2, y: 4 },
  { x: 3, y: 2 }
];

export default function App() {
  return (
    <div>
      <VictoryChart polar domain={{ x: [0, 10] }} theme={VictoryTheme.material}>
        <VictoryPolarAxis tickCount={8} />
        <VictoryBar
          data={data}
          style={{ data: { fill: "#c43a31", stroke: "black", strokeWidth: 2 } }}
        />
      </VictoryChart>      ​
    </div>
  );
}

to add a polar chart with the VictoryChart component.

VictoryAxis has the axes for the chart.

VictoryBar are rendered in the chart as segments.

We can add the VictoryPolarAxis component to add the tick lines to the polar chart:

import React from "react";
import {
  VictoryBar,
  VictoryChart,
  VictoryPolarAxis,
  VictoryTheme
} from "victory";
const data = [
  { x: 1, y: 3 },
  { x: 2, y: 4 },
  { x: 3, y: 2 }
];

export default function App() {
  return (
    <div>
      <VictoryChart polar theme={VictoryTheme.material}>
        <VictoryPolarAxis
          dependentAxis
          style={{
            axis: { stroke: "none" },
            tickLabels: { fill: "none" },
            grid: { stroke: "grey", strokeDasharray: "4, 8" }
          }}
        />
        <VictoryPolarAxis tickValues={[0, 3, 6, 9]} />
        <VictoryBar
          style={{ data: { fill: "#c43a31", width: 50 } }}
          data={data}
        />
      </VictoryChart>
      ​
    </div>
  );
}

We can add multiple segments into the polar chart with the VictoryBar components:

import React from "react";
import {
  VictoryBar,
  VictoryChart,
  VictoryPolarAxis,
  VictoryStack,
  VictoryTheme
} from "victory";
const data = [
  { x: 1, y: 3 },
  { x: 2, y: 4 },
  { x: 3, y: 2 }
];

export default function App() {
  return (
    <div>
      <VictoryChart
        polar
        maxDomain={{ x: 360 }}
        height={250}
        width={250}
        padding={30}
      >
        <VictoryPolarAxis
          dependentAxis
          style={{
            axis: { stroke: "none" },
            tickLabels: { fill: "none" },
            grid: { stroke: "grey", strokeDasharray: "4, 8" }
          }}
        />
        <VictoryPolarAxis tickValues={[0, 45, 90, 135, 180, 225, 270, 315]} />
        <VictoryStack
          colorScale={["#ad1b11", "#c43a31", "#dc7a6b"]}
          style={{ data: { width: 50 } }}
        >
          <VictoryBar data={data} />
          <VictoryBar data={data} />
          <VictoryBar data={data} />
        </VictoryStack>
      </VictoryChart>
      ​
    </div>
  );
}

Conclusion

We can add various kinds of polar charts with React Victory.

Categories
React

Add Charts into Our React App with Victory — Shared and Dynamic Events

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.

VictorySharedEvents

We can add events shared between multiple charts with the VictorySharedEvents component.

For instance, we can write:

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

export default function App() {
  return (
    <svg viewBox="0 0 450 350">
      <VictorySharedEvents
        events={[
          {
            childName: ["pie", "bar"],
            target: "data",
            eventHandlers: {
              onMouseOver: () => {
                return [
                  {
                    childName: ["pie", "bar"],
                    mutation: (props) => {
                      return {
                        style: Object.assign({}, props.style, {
                          fill: "tomato"
                        })
                      };
                    }
                  }
                ];
              },
              onMouseOut: () => {
                return [
                  {
                    childName: ["pie", "bar"],
                    mutation: () => {
                      return null;
                    }
                  }
                ];
              }
            }
          }
        ]}
      >
        <g transform={"translate(150, 50)"}>
          <VictoryBar
            name="bar"
            width={300}
            standalone={false}
            style={{
              data: { width: 20 },
              labels: { fontSize: 25 }
            }}
            data={[
              { x: "a", y: 2 },
              { x: "b", y: 3 },
              { x: "c", y: 5 }
            ]}
            labels={["a", "b", "c"]}
            labelComponent={<VictoryLabel y={290} />}
          />
        </g>
        <g transform={"translate(0, -75)"}>
          <VictoryPie
            name="pie"
            width={250}
            standalone={false}
            style={{ labels: { fontSize: 25, padding: 10 } }}
            data={[
              { x: "a", y: 1 },
              { x: "b", y: 4 },
              { x: "c", y: 5 }
            ]}
          />
        </g>
      </VictorySharedEvents>
    </svg>
  );
}

In the events prop, we add an array with the eventsHandlers object to add event handlers for various events.

We have event handlers for mouseover with onMouseOver and one for mouseout with onMouseOut .

The mutation method lets us change the fill style of the segment we hover over.

childName has the name values of the charts we want to change.

Similarly, we have the onMouseOut event handler to return null to revert to the original style.

External Event Mutations

We can attach event mutations by changing states.

For instance, we can write:

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

const buttonStyle = {
  backgroundColor: "black",
  color: "white",
  padding: "10px",
  marginTop: "10px"
};

export default function App() {
  const [externalMutations, setExternalMutations] = useState({});
  const removeMutation = () => {
    setExternalMutations(undefined);
  };

const clearClicks = () => {
    setExternalMutations([
      {
        childName: "Bar-1",
        target: ["data"],
        eventKey: "all",
        mutation: () => ({ style: undefined }),
        callback: removeMutation
      }
    ]);
  };

return (
    <div>
      <button onClick={clearClicks} style={buttonStyle}>
        Reset
      </button>
      <VictoryChart
        domain={{ x: [0, 5] }}
        externalEventMutations={externalMutations}
        events={[
          {
            target: "data",
            childName: "Bar-1",
            eventHandlers: {
              onClick: () => ({
                target: "data",
                mutation: () => ({ style: { fill: "orange" } })
              })
            }
          }
        ]}
      >
        <VictoryBar
          name="Bar-1"
          style={{ data: { fill: "grey" } }}
          labels={() => "click me!"}
          data={[
            { x: 1, y: 2 },
            { x: 2, y: 4 },
            { x: 3, y: 1 },
            { x: 4, y: 5 }
          ]}
        />
      </VictoryChart>
    </div>
  );
}

to add click event handlers with the events prop on VictoryChart .

When we click on the bars, the fill changes to orange.

The Reset button calls clearClicks to clear all the click handlers by setting externalMutations to undefined .

clearClicks clear all the styles from the bars.

And we set externalEventMutations to externalMutations .

Conclusion

We can add event handlers dynamically and add shared events into charts with React Victory.