The Widlarz Group Blog

Make your custom charts with react-native-svg-charts and typescript. Step-by-step tutorial

September 14, 2021

react-native-svg-charts

typescript

react native

mobile

Introduction

At the start, I want to ask you one question.
Did you ever use charts in your React Native project, especially with typescript?

If you did, you know it’s not always easy, but you also know what impression it can make on the user.
Writing about data in the block of text and showing it on a neat chart cannot be compared.
Let me show you the methods and examples prepared and explained in detail for you.

If you never used charts in your mobile app, this article will guide you step-by-step through the react-native-charts-svg library and additional parts I decided to talk about. You will learn how to create really good-looking and useful charts on your own in a simple way. You don’t need to worry about complicated parts, or blind spots when you have no idea what just happened. Why? Because I intend to make this topic clear and simple for anyone.
I’m pretty sure next time when you have to write about data in your project, you will use charts for that.

Repository

All the examples explained in this article (and few more) are available in the GitHub repository.
You can find it here:

React Native Chart Examples Library

Hope it will help you!

Table of Contents

What will we learn

- How to create different chart types:

  • Area chart
  • Bar chart
  • Line chart
  • Pie chart
  • Progress circle
  • Scatter chart

    - How to modify each part of the chart

    - Add typescript types to the charts we will create

React-native-svg-charts setup

First, we need to add the library to our project using npm:

npm install --save react-native-svg-charts

or yarn

yarn add react-native-svg-charts

We use typescript, so we also need to add types for it by npm:

npm install --save @types/react-native-svg-charts

or yarn

yarn add @types/react-native-svg-charts

Now we can start creating our first chart!

Area chart

Base example with props and typescript

Let’s start with the Area chart. First, we need to import it from the library:

import { AreaChart } from 'react-native-svg-charts'

If we implement it, just like that:

export const AreaChartScreen = () => {
    return <AreaChart />
}

We cannot see a thing there. We need to add at least 3 props:

  • data - an array of arbitrary data. For example, it can be an array of numbers or objects. For now, let’s take it as an array of numbers.
  • style - well-known line-style prop. In this case, it’s a style for the chart’s CONTAINER. Not the chart’s itself. Height is set in default at 0, so we need to pass the expected height by ourselves. Always. We can treat the container here not as a box, but more like a canvas, we’re writing on. If we did not set the height, there is nothing to overlay the chart on.
  • svg - this prop is a style-prop for the chart itself. It can take several properties, but the most important for the Area chart is the fill one. If we do not insert it, then technically we have our area chart set, but… it’s not visible.

With those 3 props:

import { AreaChart } from 'react-native-svg-charts'

const data = [50, 10, 40, 95, -4, -24, 85, 91, 35, 53, -53, 24, 50, -20, -80]

export const AreaChartScreen = () => {
    return <AreaChart style={{ height: 200 }} data={data} svg={{ fill: '#ADD8E6' }} />
}

It is maybe not the most beautiful one, but at least ready for use:

areaChart base

Line with circle decorators and grid

Now let’s add some more features to our new chart. Props we are interested in now are:

  • gridMin - minimal visible chart’s value. By default, it’s set for the minimal value of the data. We can set the value by ourselves also, but if we will set it for a higher value than the smallest data value, the system will take minimal data value. For example, if the min value in the data array is -20, and we will set it for 0, then the system will set it for -20. But if we will set it for -40, then the system will set it for -40. In other words, the system always compares our value with the lowest value in the array and sets a lower one.
  • gridMax - maximal visible chart’s value. Works the same as gridMin, but opposite. The system always compares the value provided by us with the highest value from the data array and sets the higher one.
  • contentInset - object with four values: top, bottom, left, and right. It sets the distance between the component and chart border. For example, if we set { bottom: 30 }, then the distance between the component bottom border and the chart’s bottom border will be 30px. We can consider it as padding for the chart.

We will also add three additional components. Let’s call them ‘decorators’.

<Grid /> - literally chart’s grid
<Line /> - line marking the range of the chart
<Dots /> - dots showing exact data values on the chart

Let’s look at our code, and chart now:

import { AreaChart, Grid } from 'react-native-svg-charts'
import { Dots, Line } from '@/screens/AreaChartScreen/chartAdds'

const data = [50, 10, 40, 95, -4, -24, 85, 91, 35, 53, -53, 24, 50, -20, -80]

export const AreaChartScreen = () => {
    return (
        <AreaChart
            style={{ height: 200 }}
            data={data}
            gridMin={-100}
            gridMax={120}
            contentInset={{ top: 30, bottom: 30 }}
            svg={{ fill: '#ADD8E6' }}>
            <Grid />
            <Line />
            <Dots />
        </AreaChart>
    )
}

areaChart grid line dots

As we can see, even if the chart has the same height - 200px, looks more flattened. It’s because the vertical range is no longer from -80 to 95 (default min and max data values), but from -100 to 120 as we set it. Also we set contentInset top and bottom for 30px.
Lines we can see in the background are our <Grid />, navy line marking the chart border is <Line /> and the small black circles are <Dots /> components.
<Grid /> is a decorator we get with the react-native-svg-charts library, so we can just import it from there.
Let’s take a closer look at the structure of the other two:

Basic <Line /> structure:

import { Path } from 'react-native-svg'

export const Line = ({ line }) => {
    return <Path key={'line'} d={line} stroke={'#0000BF'} fill={'none'} />
}

If we take a closer look at the code, we will notice that something is wrong.

<Grid />
<Line />
<Dots />
export const Line = ({ line }) => { }

Component Line requires a ‘line’ prop. But we’re not passing any to it.
That will be no problem in javascript. Even if we don’t understand what just happened, we can just leave it and go ahead. Because it’s working! YES, it is.
Of course, we should ask: WHY? And typescript is doing it. Typescript is asking:
‘Hey buddy, it’s working, great. But can you tell me, how is this possible? You need to pass this prop, or explain this weird behavior to me”.
So with the component created like that:

import { Path } from 'react-native-svg'

export const Line = ({ line }) => {
    return <Path key={'line'} d={line} stroke={'#0000BF'} fill={'none'} />
}

We get errors from typescript:

tsError


tsError2

Let’s first answer the question, why is this working.
Like we can see, the <Line /> component is placed inside the chart component. We did it for a specific reason. Charts in the react-native-svg-charts library have their own specific lexical scope.
That means, functions (components) inside them, can use specific data provided for the chart.
Like we can see, we provided a ‘data’ array to the AreaChart component. It has been calculated by AreaChart and passed to the lexical scope, as a path string.
<Line /> component used lexical scope and pulled ‘line’ prop from there.
To read more about lexical scope visit the MDN website - closures .

Now we know how is it working. So how could we handle it with typescript?
There are few ways to do that, but the easiest way is to use Partial<>.

Firstly we create an interface, which will take function props for our <Line /> component.
We know that <Path> props ‘d’ is in fact line path, so it is for sure type string. Thanks to the react-native-svg types we can also check it, to be sure:

pathProps

Let’s create interface LineProps, pass it to the <Line /> component and make a type assertion.

import { Path } from 'react-native-svg'

interface LineProps {
    line: string
}

export const Line = (props: Partial<LineProps>) => {
    const { line } = props as LineProps
    return <Path key={'line'} d={line} stroke={'#0000BF'} fill={'none'} />
}

Now <Line /> component doesn’t require line prop from us. line is still passed to the component, and it’s typed properly. Problem solved :) let’s study <Path> props, if we would like to modify them:

  • d - path of the drawn line
  • stroke - color of the circle border
  • fill - color of the circle background

Basic <Dots /> structure:

import { Circle } from 'react-native-svg'

export const Dots = ({ x, y, data }) => {
    return (
        <>
            {data?.map((value, index) => (
                <Circle
                    key={index}
                    cx={x(index)}
                    cy={y(value)}
                    r={4}
                    stroke={'rgb(0, 0, 0)'}
                    fill={'white'}
                />
            ))}
        </>
    )
}

Like you probably guess, we face here exactly the same problem as with the <Line /> component. Fortunately, the solution is also the same:

import { Circle } from 'react-native-svg'

interface DecoratorProps {
    x: (arg: number) => number
    y: (arg: number) => number
    data: number[]
}

export const Dots = (props: Partial<DecoratorProps>) => {
    const { x, y, data } = props as DecoratorProps
    return (
        <>
            {data?.map((value, index) => (
                <Circle
                    key={index}
                    cx={x(index)}
                    cy={y(value)}
                    r={4}
                    stroke={'rgb(0, 0, 0)'}
                    fill={'white'}
                />
            ))}
        </>
    )
}

From the definition of the <Circle> component, we know that props cx and cy have to return number types. Also, the index and value will be always numbers. Now x and y typing are not hard. We also know that data is taken from the lexical scope of AreaChart so it has to be number[]. So we have the circles on the chart. If we want to modify them, then we need to know what props are they taking.

  • cx - coordinate on the axis x
  • cy - coordinate on the axis y
  • r - radius of the single circle
  • stroke - the color of the circle border
  • fill - the color of the circle background

Start prop

In this example, we will pay attention to only one prop:

  • start - number on the axis Y, from which area chart is painted.

This prop can change the perception of our chart dramatically. We still have the same data provided in our chart, but the start prop will be set for the -100. Let’s take a look:

import { AreaChart, Grid } from 'react-native-svg-charts'
import { Dots, Line } from '@/screens/AreaChartScreen/chartAdds'

const data = [50, 10, 40, 95, -4, -24, 85, 91, 35, 53, -53, 24, 50, -20, -80]

export const AreaChartScreen = () => {
    return (
        <AreaChart
            style={{ height: 200 }}
            data={data}
            gridMin={-100}
            gridMax={120}
            start={-100}
            contentInset={{ top: 30, bottom: 30 }}
            svg={{ fill: '#ADD8E6' }}>
            <Grid />
            <Line />
            <Dots />
        </AreaChart>
    )
}

areaChartBottomArea

Even if the min value on the chart is -80, it looks like all the values are really height.

Let’s reverse it, we will set the start for 120, and we will get blue sky above our values:

import { AreaChart, Grid } from 'react-native-svg-charts'
import { Dots, Line } from '@/screens/AreaChartScreen/chartAdds'

const data = [50, 10, 40, 95, -4, -24, 85, 91, 35, 53, -53, 24, 50, -20, -80]

export const AreaChartScreen = () => {
    return (
        <AreaChart
            style={{ height: 200 }}
            data={data}
            gridMin={-100}
            gridMax={120}
            start={120}
            contentInset={{ top: 30, bottom: 30 }}
            svg={{ fill: '#ADD8E6' }}>
            <Grid />
            <Line />
            <Dots />
        </AreaChart>
    )
}

areaChartTopArea

Curve and gradient

In this example let’s get rid of the <Line /> and <Circles /> components. Also, the start prop. You know, we can use them anytime in the line charts, but other features will be better visible without them on the board. As mentioned in the title, our new features will be curve and gradient. So what they really are?
The curve is another prop:

  • curve - the shape of our area chart. d3 library has been used here to allow the chart to take many different shapes. All the possibilities are listed HERE . We can also read there more about the d3 library. To pull some shapes from the library, we need to import the main object from d3 and rename it. shape will be a good choice. Now just pull chosen shape from the shape object. For example curve={shape.curveNatural}.

The Gradient is another additional component:

  • <Gradient /> - this additional component let us change the color of the chart for the… gradient itself. Inserting it inside the chart is unfortunately not enough to make it work. We need to remember also to change the color of the fill property for the 'url(#gradient)'. The svg prop will take the form svg={{ fill: 'url(#gradient)' }}

Let’s take a look at our code and chart after these changes:

import { AreaChart, Grid } from 'react-native-svg-charts'
import * as shape from 'd3-shape'
import { Gradient } from '@/screens/AreaChartScreen/chartAdds'

const data = [50, 10, 40, 95, -4, -24, 85, 91, 35, 53, -53, 24, 50, -20, -80]

export const AreaChartScreen = () => {
    return (
        <AreaChart
            style={{ height: 200 }}
            gridMin={-100}
            gridMax={120}
            data={data}
            contentInset={{ top: 30, bottom: 30 }}
            curve={shape.curveNatural}
            svg={{ fill: 'url(#gradient)' }}>
            <Grid />
            <Gradient />
        </AreaChart>
    )
}

areaChart curve gradient

Like we can see, there are no more acute angles. They have been beautifully rounded. Also, the color has been set for the gradient.

So how the Gradient component is built then?

import { Defs, LinearGradient, Stop } from 'react-native-svg'

export const Gradient = () => (
    <Defs>
        <LinearGradient id={'gradient'} x1={'0%'} y1={'0%'} x2={'0%'} y2={'100%'}>
            <Stop offset={'0%'} stopColor={'rgb(194, 65, 244)'} stopOpacity={0.8} />
            <Stop offset={'100%'} stopColor={'rgb(134, 65, 244)'} stopOpacity={0.2} />
        </LinearGradient>
    </Defs>
)

We use here elements provided by react-native-svg:

  • <Defs> - this element is used to embed definitions that can be reused inside an SVG image.
  • <LinearGradient> - it’s a linear-gradient box, for which we can set from which point gradient should start and at which should end. x1, x2 are used to set gradient horizontal, and y1, y2 to set it vertical. Like we can see, in our case, it’s set from the top (where is 100%) to the bottom (0%).
  • <Stop> - this element is used to set border color. If we want to have a gradient consisting of 5 colors, we would use a new one for each color. offset property determines how to cover the element with color. In our example, we set the end result to 0%. This means that the rgb(194, 65, 244) color will be distributed from 100% at the beginning of the gradient to 0% at the end. stopColor is a color that we want to use, and stopOpacity is just its opacity.

    We can also remove the <Gradient>, add the <Line> and change the curve to step form:

import { AreaChart, Grid } from 'react-native-svg-charts'
import { Line } from '@/screens/AreaChartScreen/chartAdds'

const data = [50, 10, 40, 95, -4, -24, 85, 91, 35, 53, -53, 24, 50, -20, -80]

export const AreaChartScreen = () => {
    return (
        <AreaChart
            style={{ height: 200 }}
            gridMin={-100}
            gridMax={120}
            data={data}
            contentInset={{ top: 30, bottom: 30 }}
            curve={shape.curveStep}
            svg={{ fill: 'rgba(134, 65, 244, 0.5)' }}>
            <Line />
            <Grid />
        </AreaChart>
    )
}

areaChart steps

Multiple areas in one chart

Another option that we should know is the interpenetration of the areas. We can easily get this effect by putting one area chart on another. To do that we need to use Styleshit’s property absoluteFill.
This property allows us to create layers, by absolute positioning content in positions {top: 0, right: 0, bottom: 0, left: 0}.
I will also reverse the data array for the effect.

import { AreaChart, Grid } from 'react-native-svg-charts'
import { Line } from '@/screens/AreaChartScreen/chartAdds'

const data = [50, 10, 40, 95, -4, -24, 85, 91, 35, 53, -53, 24, 50, -20, -80]

export const AreaChartScreen = () => {
    return (
        <ChartContainer>
            <AreaChart
                style={{ height: 200 }}
                gridMin={-100}
                gridMax={120}
                data={data}
                contentInset={{ top: 30, bottom: 30 }}
                curve={shape.curveNatural}
                svg={{ fill: 'rgb(124,252,0)' }}
            />
            <AreaChart
                style={StyleSheet.absoluteFill}
                gridMin={-100}
                gridMax={120}
                data={[...data].reverse()}
                contentInset={{ top: 30, bottom: 30 }}
                curve={shape.curveNatural}
                svg={{ fill: 'rgb(176,224,230, 0.8)' }}>
                <Grid />
            </AreaChart>
        </ChartContainer>
    )
}

areaChart multiArea

It can be useful sometimes, but I don’t recommend this kind of solution. If we want to compare data, other charts, like for example Line chart (we will talk about it further in this article), will be much better.
To prove that, let me show you the anti-pattern. I will put only 3 areas (3 data arrays) on the same chart:

areaChart antiPattern

Even on the big screen it looks horrible, but on the phone it’s completely illegible.

Area chart props summary

Let’s summarize props we already used in the Area charts:

  • data - an array of arbitrary data. For example, it can be an array of numbers or objects. For now, let’s take it as an array of numbers.
  • style - well known line-style prop. In this case, it’s a style for the chart’s CONTAINER. Not the chart itself. Height is set in default at 0, so we need to pass the expected height by ourselves. Always. We can treat the container here not as a box, but more like a canvas, we’re writing on. If we did not set the height, there is nothing we can put the chart on.
  • svg - this prop is a style-prop for the chart itself. It can take several properties, but the most important for the Area chart is fill property. If we do not adjust it, then technically we have our area chart set, but… it’s not visible.
  • gridMin - minimal visible chart’s value. By default, it’s set for the minimal value of the data. We can set the value by ourselves also, but if we will set it for a higher value than the smallest data value, the system will take the smallest data value. For example, if the min value in the data array is -20, and we will set it for 0, then the system will set it for -20. But if we will set it for -40, then the system will set it for -40. In other words, the system always compares our value with the smallest value in the array and sets a lower one.
  • gridMax - maximal visible chart’s value. Works the same as gridMin, but opposite. The system always compares the value provided by us with the highest value from the data array and sets the higher one.
  • contentInset - object with four values: top, bottom, left and right. It sets the distance between the component’s and the chart’s border. For example, if we set { bottom: 30 }, then the distance between the component bottom border and the chart’s bottom border will be 30px. We can consider it as padding for the chart.
  • curve - the shape of our area chart. d3 library has been used here to allow the chart to take many different shapes. All the possibilities are listed HERE . We can also read there more about the d3 library. To pull some shapes from the library, we need to import the main object from d3 and rename it. shape will be a good choice. Now just pull chosen shape from the shape object. For example curve={shape.curveNatural}.
  • start - number on the axis Y, from which area chart is painted. The area chart will be painted from this level on the axis X to each point on the chart.

In my opinion, those are most useful but there are a few more we can use:

  • yAccessor - thanks to that function, we can provide a more complicated data structure and chose the value we want to use from keys in the objects array (used for axis Y) - we will use this prop later for other charts, so you will get familiar with it
  • xAccessor - thanks to that function, we can provide a more complicated data structure and chose the value we want to use from keys in the objects array (used for axis X) - we will use this prop later for other charts, so you will get familiar with it
  • yScale - A function that determines the scale of axis Y. As said in the documentation it’s not very well tested
  • xScale - A function that determines the scale of axis X. As said in the documentation it’s not very well tested
  • xMin - the minimal visible value of axis X. Not really useful if you want to use all the available space to show data. Let’s imagine your data start from 0. If you set it from -10, then you will get just empty white space on the left side. If you set it for 10, then part of your data will be not visible. Mobile devices are usually narrow. I recommend using the available space to the maximum, to increase readability
  • xMax - the maximal visible value of axis X. Same situation like with xMin
  • yMin - the minimal visible value of axis Y. We can get the same effect using gridMin
  • yMax - the maximal visible value of axis Y. We can get the same effect using gridMan
  • numberOfTicks - number of lines visible on the background grid (of course only when we use additional component Grid)

Stacked area charts

The last topic in this section is the stacked area chart. This solution can be very useful, for example, if we want to show the sum of values in time. The idea is very simple - we put one value on another one. For example, let’s say I have an orchard, with apples, pears, cherries, and plums. I want to see how many kilograms of fruits I gained in the last four years. I want to compare the values, but also see the difference in the sum in particular years.
A stacked area chart will be perfect for that task.

First, we need to import StackedAreaChart from the react-native-svg-charts:

import { StackedAreaChart } from 'react-native-svg-charts'

To create the chart, we need data. The question is, how to handle that? It’s obvious that we cannot just push number[]. When we were talking about data props in the first chart, I mentioned that data can be also an array of objects. That is the time to use that knowledge. StackedSreaChart is taking an array of objects as data props. Each object will be responsible for one year, and we have four kinds of fruits each year. So each year will be an object with 4 keys:

export const stackedAreaChartData = [
    {
        apples: 1840,
        pears: 1920,
        cherries: 960,
        plums: 400,
    },
    {
        apples: 1600,
        pears: 1440,
        cherries: 960,
        plums: 400,
    },
    {
        apples: 640,
        pears: 960,
        cherries: 1640,
        plums: 400,
    },
    {
        apples: 3320,
        pears: 480,
        cherries: 640,
        plums: 400,
    },
]

Like we know, we need to pass three values to make any chart visible: data, height, and fill (color). Now we have data, height is not a problem, but how to handle different colors for different fruits?
We need to create an additional array, with as many colors as we have keys (fruits in this case):

const colors = ['#8800cc', '#FF0000', '#0000FF', '#00FF00']

StackedAreaChart requires from us one additional prop. We need to pass keys props. Chart need to know on what variables it will be working. In other words, we need to provide an array with keys from our object (our fruits). Using typescript, we also need to pass the array of the proper type:

type Keys = ('apples' | 'pears' | 'cherries' | 'plums')[]

const keys: Keys = ['apples', 'pears', 'cherries', 'plums']

Now we can create our chart:

import { StackedAreaChart } from 'react-native-svg-charts'
import * as shape from 'd3-shape'
import { stackedAreaChartData } from '@/data/data'

type Keys = ('apples' | 'pears' | 'cherries' | 'plums')[]

export const StackedAreaChartComponent = () => {
    const colors = ['#8800cc', '#FF0000', '#0000FF', '#00FF00']
    const keys: Keys = ['apples', 'pears', 'cherries', 'plums']

    return (
        <StackedAreaChart
            style={{ height: 150, paddingVertical: 16 }}
            data={stackedAreaChartData}
            keys={keys}
            colors={colors}
            curve={shape.curveNatural}
        />
    )
}

Because now colors are picked from the array, different props are responsible for handling them. We need to pass the colors array to colors props. Also, the keys array has to be passed to the keys props, to inform the chart on what variables it will be working.
Remember, that we always need to have the same value of kays and colors. One color for one key. Let’s take a look at our chart now:

stackedAreaChart

Bar chart

Thanks to what we learned in the Area chart chapter, the Bar chart should be an easy part. Most of the props will be the same.
We will learn few new things, but this chapter mostly will be base on the ready examples.
Let’s start with the first one.

Basic Bar chart

First we need to import BarChart from the react-native-svg-charts library:

import { BarChart } from 'react-native-svg-charts'

Now we can create base BarChart:

import { AreaChart, Grid } from 'react-native-svg-charts'
import { Dots, Line } from '@/screens/AreaChartScreen/chartAdds'

const data = [50, 10, 40, 95, -4, -24, 85, 91, 35, 53, -53, 24, 50, -20, -80]

export const AreaChartScreen = () => {
    return (
        <BarChart
            style={{ height: 200 }}
            gridMin={-100}
            gridMax={120}
            data={data}
            svg={{ fill: 'rgb(134, 65, 244)' }}
            contentInset={{ top: 30, bottom: 30 }}>
            <Grid />
        </BarChart>
    )
}

We have well known props:

  • style
  • gridMin
  • gridMax
  • data
  • svg
  • contentInset

Nothing new for us. Let’s see how our chart looks like:

baseBarChart

Spacing and Gradient

Now let me introduce you to two new props occurring only in the BarChart:

-spacingInner - space between the bars. Default set for 0.05 -spacingOuter - space outside the bars. In other words from the right and the left border of the chart. We can consider it as a kind of padding inside the chart.

import { BarChart, Grid } from 'react-native-svg-charts'

const data = [50, 10, 40, 95, -4, -24, 85, 91, 35, 53, -53, 24, 50, -20, -80]

export const BarChartScreen = () => {
    return (
        <BarChart
            style={{ height: 200 }}
            spacingInner={0.4}
            spacingOuter={0.1}
            gridMin={-100}
            gridMax={120}
            data={data}
            svg={{ fill: 'rgb(134, 65, 244)' }}
            contentInset={{ top: 30, bottom: 30 }}>
            <Grid />
        </BarChart>
    )
}

We just set space between the charts for 0.4, which means that we set it for 40% width of the FULL bar width. The width that bar would take if the spacingInner would be set to 0. Now white space is taking 40% of that space and the bar is taking 60% of that space. It’s the same with the spacingOuter. Now we set distance from the left and right border for 10% of the original bar chart width. We also injected Gradient component which is literally the same as in Area chart:

barChart spacing gradient

yAccessor and different bar colors

As I said when we were summing up props at the end of the Area chart part, we will now deal with the yAccessor. But let me first explain how to create data, which will let us give different colors for different bars on the same chart.

Again, we need to leave out convenient number[] and create an array of objects.
Each bar needs to have its own color. In other words, each object needs to have a key with a value and a key with color. The number of objects is identical to the number of bars we want to display. For our example, let’s say it will be five:

export const data6 = [
    {
        value: 50,
        svg: {
            fill: 'red',
        },
    },
    {
        value: 10,
        svg: {
            fill: 'orange',
        },
    },
    {
        value: 95,
        svg: {
            fill: 'purple',
        },
    },
    {
        value: 40,
        svg: {
            fill: 'blue',
        },
    },
    {
        value: 85,
        svg: {
            fill: 'green',
        },
    },
]

yAccessor will let us iterate over the chosen key. In this case, it will be the value. Like we can see, now the svg prop will be taken automatically from each object. We will not pass it to the BarChart component then.

import { BarChart } from 'react-native-svg-charts'
import { data6 } from '@/data/data'

export const BarChartScreen = () => {
    return (
        <BarChart
            style={{ height: 200 }}
            spacingInner={0.1}
            gridMin={-10}
            gridMax={120}
            data={data6}
            yAccessor={({ item }) => item.value}
            contentInset={{ top: 30, bottom: 30 }}
        />
    )
}

Look for the props we pass. spacingOuter wasn’t really necessary, so we removed it. It’s the same for svg. We don’t need it here, because each bar has its own svg object, and the chart will take it now from the objects.
The result looks like that:

barChartColored

We can now make a better definition for yAccessor:

  • yAccessor - we pass it a function that tells us, which key in the object’s array should be taken as a value to display on the chart. In other words, we pass the object key the chart should iterate at. Another thing is that thanks to it, chart iterating over the object’s array, can take other properties of the object (bar) and inject them into a specific bar.

Sounds logic? Hope so.

Dashed bars

Now, if the svg objects have a lot of properties to use, let’s have a bit of fun and create something unusual. I will just remind you that the full list of svg object properties is listed HERE .

First please take a look, what we want to achieve:

barChart dashed

It’s easier than you could expect. In fact, we don’t need to do a thing with the previously used BarChart component (I just made a chart a little bit taller for a better impression). The interesting part is the data array. We need to change svg object in each iteration to give us the effect we expect:

export const data7 = [
    {
        value: 50,
        svg: {
            fill: 'white',
            stroke: 'red',
            strokeWidth: 1,
            strokeDasharray: [30, 5],
        },
    },
    {
        value: 10,
        svg: {
            fill: 'white',
            stroke: 'orange',
            strokeWidth: 2,
        },
    },
    {
        value: 95,
        svg: {
            fill: 'white',
            stroke: 'purple',
            strokeWidth: 2,
            strokeDasharray: [4, 2],
        },
    },
    {
        value: 40,
        svg: {
            fill: 'white',
            stroke: 'blue',
            strokeWidth: 1,
            strokeDasharray: [14, 4],
        },
    },
    {
        value: 85,
        svg: {
            fill: 'white',
            stroke: 'green',
            strokeWidth: 2,
            strokeDasharray: [2, 1],
        },
    },
]

So what happened?
In fact not much. We just added few properties to the svg objects:

  • fill - background color of each bar. We set it transparent because it should be transparent.
  • stroke - this property is borderline’s color.
  • strokeWidth - it is a borderline’s width
  • strokeDasharray - we set this property, only when we want to make our line dashed. This property gets an array with two numbers. The first one tells the chart how long should be pieces of our borderline. The second one tells, how long should be spaces between them.

You can of course be even more creative and create even more interesting examples using svg possibilities.

Grades ( low, average, height )

For now, we will leave styling for some time, and focus on simple logic. We want to color our bars depending on the score or grade. Let’s stay again with the same BarChart component, and work with data again.
If we want to color the bars depending on the score, should we give each bar its own color manually? Of course not. We will prepare a simple function that will do it for us.

We should remember that we’re working with typescript all this time. It’s not really visible, because of the types we added to our project at the beginning. The function we will create right now will be typed by us.
Here is it:

export const transformDataForBarChart = (
    number: number
): { value: number; svg: { fill: string; stroke?: string; strokeWidth?: number } } => {
    // random ranges > number < inscribed to distinguish colors
    if (number <= 30) {
        return {
            value: number,
            svg: {
                fill: 'red',
            },
        }
    } else if (number > 30 && number < 70) {
        return {
            value: number,
            svg: {
                stroke: 'orange',
                strokeWidth: 2,
                fill: '#FFD580',
            },
        }
    } else {
        return {
            value: number,
            svg: {
                fill: 'green',
            },
        }
    }
}

Like we can see, this function takes a number(value) as an argument and returns for us prepared object. fill property, is required because we always want to color our bar. But depending on the score, we sometimes want to give the bar borderline. That’s why properties border and borderWidth are optional.
We depend on simple conditions:

  • if the score is lower or equal to 30, the bar will become red
  • if the score is lower than 70 but higher than 30, the bar will become orange
  • if the score is higher or equal to 70, the bar will become green ( it’s a score. Minimal value is a 0, so we can use else)

Now we can use this function and create the chart:

import { BarChart } from 'react-native-svg-charts'

const data5 = [10, 20, 60, 30, 5, 90, 21, 47, 68, 88, 96, 55, 10, 73]

export const BarChartScreen = () => {
    const dataWithPickedColors = data5.map((item) => transformDataForBarChart(item))

    return (
        <BarChart
            style={{ height: 200 }}
            spacingInner={0.1}
            gridMin={-10}
            gridMax={120}
            data={dataWithPickedColors}
            yAccessor={({ item }) => item.value}
            contentInset={{ top: 30, bottom: 30 }}
        />
    )
}

First using the map, we iterate over each value and transform it for the required object. When it’s done, we assign a new array of objects to the dataWithPickedColors variable. The last step is to just pass it to the data prop. Here is the result we got:

barChart scores

Of course, you can make much more complicated functions and examples. In fact, everything that you need at a particular moment.

Horizontal Bar chart

Till now, we made few examples with classic BarChart. Another prop I want you to get familiar with is horizontal.

  • horizontal - this props can take only two values, true or false. By default, it’s false. If it’s true, our chart will be rotated 90 degrees.

If we would like to add the Grid component to our chart, we can also rotate it.
Just add direction={Grid.Direction.VERTICAL} to it.
There is nothing more to talk about here. It can be very useful, but it’s also super easy.

import { BarChart } from 'react-native-svg-charts'

const data8 = [10, 20, 60, 30, 5, 90]

export const BarChartScreen = () => {
    return (
        <BarChart
            style={{ height: 200, marginVertical: 20 }}
            horizontal={true}
            spacingInner={0.1}
            gridMin={0}
            gridMax={100}
            data={data8}
            svg={{ fill: 'lightblue' }}
            contentInset={{ top: 30, bottom: 30 }}>
            <Grid direction={Grid.Direction.VERTICAL} />
        </BarChart>
    )
}

barChart rotated

Stacked Bar chart

The rule is exactly the same as with Stacked Area Chart .

First, we need to create an array of objects with particular keys:

export const stackedBarChartData = [
    {
        apples: 1840,
        pears: 1920,
        cherries: 960,
        plums: 400,
    },
    {
        apples: 1600,
        pears: 1440,
        cherries: 960,
        plums: 400,
    },
    {
        apples: 640,
        pears: 960,
        cherries: 1640,
        plums: 400,
    },
    {
        apples: 3320,
        pears: 480,
        cherries: 640,
        plums: 400,
    },
]

After, arrays with colors and keys:

type Keys = ('apples' | 'pears' | 'cherries' | 'plums')[]

const colors = ['#142459', '#FF0000', '#0000FF', '#00FF00']
const keys: Keys = ['apples', 'pears', 'cherries', 'plums']

And pass them to proper props in the StackedBarChart component:

import { StackedBarChart } from 'react-native-svg-charts'
import { stackedBarChartData } from '@/data/data'

type Keys = ('apples' | 'pears' | 'cherries' | 'plums')[]

export const StackedBarChartComponent = () => {
    const colors = ['#8800cc', '#FF0000', '#0000FF', '#00FF00']
    const keys: Keys = ['apples', 'pears', 'cherries', 'plums']

    return (
        <StackedBarChart
            style={{ height: 200, paddingVertical: 16 }}
            data={stackedBarChartData}
            keys={keys}
            colors={colors}
            contentInset={{ top: 30, bottom: 30 }}
        />
    )
}

stackedBarChart

Bar chart props summary

Let’s summarize props we already used in Bar charts:

  • data - an array of arbitrary data. For example, it can be an array of numbers or objects.
  • style - well known line-style prop. In this case, it’s a style for the chart CONTAINER. Not the chart itself. Height is set in default at 0, so we need to pass the expected height by ourselves. Always. We can treat the container here not as a box, but more like a canvas, we’re writing on. If we did not set the height, there is nothing we can put the chart on.
  • svg - this prop is a style-prop for the chart itself. It can take several properties. A full list of them is available HERE
  • gridMin - minimal visible chart’s value. By default, it’s set for the minimal value of the data. We can set the value by ourselves also, but if we will set it for a higher value than the smallest data value, the system will take the smallest data value. For example, if the min value in the data array is -20, and we will set it for 0, then the system will set it for -20. But if we will set it for -40, then the system will set it for -40. In other words, the system always compares our value with the smallest value in the array and sets a lower one.
  • gridMax - maximal visible chart’s value. Works the same as gridMin, but opposite. The system always compares the value provided by us with the highest value from the data array and sets the higher one.
  • contentInset - object with four values: top, bottom, left and right. It sets the distance between the component and chart border. For example, if we set { bottom: 30 }, then the distance between the component’s bottom border and the chart’s bottom border will be 30px. We can consider it as padding for the chart.
  • spacingInner - space between the bars. Default set for 0.05.
  • spacingOuter - space outside the bars. In other words from the right and the left border of the chart. We can consider it as a kind of padding inside the chart.
  • yAccessor - we pass it a function that tells us, which key in the object’s array should be taken as a value to display on the chart. In other words, we pass the object key the chart should iterate at. Another thing is that thanks to it, chart iterating over the object’s array, can take other properties of the object (bar) and inject them into a specific bar.
  • horizontal - this props can take only two values, true or false. By default, it’s false. If it’s true, our chart will be rotated 90 degrees.

We can use also:

  • xAccessor - thanks to that function, we can provide a more complicated data structure and chose the value we want to use from keys in the objects array (used for axis X) - we will use this prop later for other charts, so you will get familiar with it
  • yScale - A function that determines the scale of axis Y. As said in the documentation it’s not very well tested
  • xScale - A function that determines the scale of axis X. As said in the documentation it’s not very well tested
  • xMin - the minimal visible value of axis X. Not really useful if you want to use all the available space to show data. Let’s imagine your data start from 0. If you set it from -10, then you will get just empty white space on the left side. If you set it for 10, then part of your data will be not visible. Mobile devices are usually narrow. I recommend using the available space to the maximum, to increase readability
  • xMax - the maximal visible value of axis X. Same situation like with xMin
  • yMin - the minimal visible value of axis Y. We can get the same effect using gridMin
  • yMax - the maximal visible value of axis Y. We can get the same effect using gridMan
  • numberOfTicks - number of lines visible on the background grid (of course only when we use additional component Grid)

(Remember that some props are available only in a specific type of chart. For example, you cannot use start in the BarChart, and horizontal is not available for AreaChart)

Line chart

The line chart is very simple-looking, and probably this is its greatest advantage. We can put many different lines on the chart, and it still will be legible. Of course, we still have a lot of possibilities to change it in the way we would like to see it.
Let’s check the possibilities then :)

Basic Line Chart

We already know most of the props we can use. If you will be not sure about any of them, please check the summary section [[[WRZUCIC LINK]]]. Our first Line Chart is a basic chart just with the Grid. Let’s import it from the react-native-svg-charts, add required props, and take a look at the result:

import { LineChart, Grid } from 'react-native-svg-charts'

export const LineChartComponent = () => {
    const data2 = [80, 10, 95, 48, 24, 67, 51, 12, 33, 0, 24, 20, 50]

    return (
        <LineChart
            style={{ height: 200 }}
            gridMin={-20}
            gridMax={120}
            data={data2}
            svg={{ stroke: 'rgb(134, 65, 244)' }}
            contentInset={{ top: 20, bottom: 20 }}>
            <Grid />
        </LineChart>
    )
}

As you probably notice, there is one difference inside the svg prop. But if you think about it, it’s completely logical. That far we were working on the area, or bars we were coloring, and a stroke was optional. Here the stroke is actually the part we want to show. It is our line. If we use fill property, then we will get some kind of AreaChart in fact. The stroke is the property we’re working on here.

LineChart base

Line shadow

Let’s add the shadow to our line. To do that we need to add another additional component - <Shadow>.

  • <Shadow> - this additional component lets us add the shadow to the Line chart. It is another line made to look like a shadow in fact.

We will now get rid of the Grid component and add Shadow component to our chart. Of course, we can use both if we like to.

import { LineChart } from 'react-native-svg-charts'
import { Shadow } from './chartAdds'

export const LineChartComponent = () => {
    const data2 = [80, 10, 95, 48, 24, 67, 51, 12, 33, 0, 24, 20, 50]

    return (
        <LineChart
            style={{ height: 200 }}
            gridMin={-20}
            gridMax={120}
            data={data2}
            svg={{ stroke: 'rgb(134, 65, 244)' }}
            contentInset={{ top: 20, bottom: 20 }}>
            <Shadow />
        </LineChart>
    )
}

lineChart shadow

Like I said before, Shadow is a line. That’s how it is built:

interface LineProps {
    line: string
}

export const Shadow = (props: Partial<LineProps>) => {
    const { line } = props as LineProps
    return (
        <Path
            key={'shadow'}
            y={2}
            x={1}
            d={line}
            fill={'none'}
            strokeWidth={4}
            stroke={'rgba(134, 65, 244, 0.2)'}
        />
    )
}

Once again we had to face the lexical scope of the chart component. Fortunately now we already know how to handle that case. Once again, we use the Path component. If you want to remind yourself about all Path props, go to the section Line, circle decorators and grid . What is new here?

  • y - props that allow us to change the position of the line on axis Y.
  • x - props that allow us to change the position of the line on axis X.

In the Line component, we also didn’t have strokeWidth applied, but it’s the props that we know already.

Line round shape, grid and gradient

In this example, we will add Grid and Gradient components, and round the angles of the chart. Also, we will make the line a little wilder to make the gradient more visible. Like I already said, now the stroke property is responsible for color, so we have to inject url(#gradient) there.

import { LineChart, Grid } from 'react-native-svg-charts'
import { Shadow, Gradient } from './chartAdds'

export const LineChartComponent = () => {
    const data2 = [80, 10, 95, 48, 24, 67, 51, 12, 33, 0, 24, 20, 50]

    return (
        <LineChart
            style={{ height: 200 }}
            gridMin={-20}
            gridMax={120}
            data={data2}
            curve={shape.curveNatural}
            svg={{
                strokeWidth: 2,
                stroke: 'url(#gradient)' }}
            contentInset={{ top: 20, bottom: 20 }}>
            <Shadow />
            <Grid />
            <Gradient />
        </LineChart>
    )
}

lineChart curve shadow gradient

Line steps shape

Let’s change the shape of our line for the steps. A full list of shapes can be found HERE .

import { LineChart, Grid } from 'react-native-svg-charts'
import { Shadow, Gradient } from './chartAdds'

export const LineChartComponent = () => {
    const data2 = [80, 10, 95, 48, 24, 67, 51, 12, 33, 0, 24, 20, 50]

    return (
        <LineChart
            style={{ height: 200 }}
            gridMin={-20}
            gridMax={120}
            data={data2}
            curve={shape.curveStep}
            svg={{
                strokeWidth: 2,
                stroke: 'url(#gradient)' }}
            contentInset={{ top: 20, bottom: 20 }}>
            <Shadow />
            <Grid />
            <Gradient />
        </LineChart>
    )
}

lineChart steps

Partial line with the shadow

Now it’s time to provide a new component - Clips. It will let us make a partial line with the shadow.
What do I mean? Let’s take a look at the chart below:

lineChart partial

As we can see, the line goes only to the 5th point. After that, we can see only the shadow.

  • Clips - this component creates the area where the line of the chart is visible. Clips limits elements inside to their own dimensions.

That’s how we use it inside the chart component:

import { LineChart, Grid } from 'react-native-svg-charts'
import { Shadow, Gradient, Clips } from './chartAdds'

export const LineChartComponent = () => {
    const data2 = [80, 10, 95, 48, 24, 67, 51, 12, 33, 0, 24, 20, 50]
    const indexToClipFrom = 4

    return (
        <LineChart
            style={{ height: 200 }}
            gridMin={-20}
            gridMax={120}
            data={data2}
            contentInset={{ top: 20, bottom: 20 }}
            svg={{
                stroke: 'url(#gradient)',
                strokeWidth: 2,
                clipPath: 'url(#clip-path-1)',
            }}>
            <Shadow />
            <Gradient />
            <Grid />
            <Clips indexToClipFrom={indexToClipFrom} />
        </LineChart>
    )
}

We need to pass prop indexToClipFrom to the Clips component. It’s the index number, that we would like to cut the line at. At the moment it’s set to 4, which means that our colored line, will be cut at point number 5. Also, we need to add clipPath property to the svg prop. It’s an ID of the clip we would like to use.

So what happens inside the Clips component?

interface ClipProps {
    x: (arg: number) => number
    indexToClipFrom: number
}

export const Clips = (props: Partial<ClipProps>) => {
    const { x, indexToClipFrom } = props as ClipProps
    return (
        <ClipPath id="clip-path-1">
            <Rect x={'0'} y={'0'} width={x(indexToClipFrom)} height={'100%'} />
        </ClipPath>
    )
}
  • ClipPath - it’s a container for the svg element Rect. It’s also holding the ID which is a key to invoke this structure. We used it in svg props clipPath property. It’s using the old JS rule, which tells that we can call an element using its ID.
  • Rect - svg basic element which creates a rectangle

If we would like to change the settings of the Clips component or to be exact: ClipPath with id="clip-path-1", we need to know which props are responsible for in Rect element:

  • x - position on the axis X (in px). Now it’s set to 0, which means it sticks to the left border of the chart.
  • y - position on the axis Y (in px). Now it’s set to 0, which means it sticks to the top border of the chart.
  • width - it’s exactly the width of the rectangle. In this case, calculated based on the number of the index we pass. It can be just a number also, which will give us width in px.
  • height - literally the height of the rectangle. Now it’s set for 100%, so the rectangle covers the entire height of the chart.

Why it affects only the line? Because it’s injected inside the chart. Grid and Gradient are separated components. That’s the magic behind the scene :)

We can also add DashedLine component to cover the shadow. There is not much to explain there, it’s basically the line width strokeDasharray props. You can find a ready example in the repository.

Let’s move on to the multiple lines chart!

Multiple lines chart

Now we’re in the situation when we need to put few different data lines on one chart. To complicate it a bit, we will also add the decorators to all the points at the lines. Like you probably guessed we need to work with our data array again. In fact, we need to create the combined array. Combined of what? Of the data arrays.

We can imagine we got four number[]:

const data9 = [13, 4, 91, 67, 42, 27, 10, 20]
const data10 = [40, 83, 60, 30, 75, 90, 27, 52]
const data11 = [80, 60, 25, 48, 24, 67, 51, 12]
const data12 = [10, 20, 41, 4, 50, 33, 21, 47]

We need to create an object from each of them, and push them into our combined data array:

export const quadrupleLineChart = [
    {
        data: data9,
        svg: {
            stroke: 'red',
            strokeWidth: 1,
        },
    },
    {
        data: data10,
        svg: {
            stroke: 'blue',
            strokeWidth: 1,
        },
    },
    {
        data: data11,
        svg: {
            stroke: 'orange',
            strokeWidth: 1,
        },
    },
    {
        data: data12,
        svg: {
            stroke: 'green',
            strokeWidth: 1,
        },
    },
]

So what happened?
We took each data array and created an object which contains:

  • this particular array
  • svg props for each array

We could just push the data array, without svg, but then all the lines would have the same color, and it wouldn’t be legible at all. We push all that data to one array, to compare them probably, so we need to distinguish them at a glance. Our LineChart component is so intelligent, that when we pass this combined array to the data props, we don’t even need to pass yAccessor there. All we need to do is to pass the combined data to the LineChart data props (if we name the key of the object “data”). Our LineChart component looks easy as always:

import { LineChart, Grid } from 'react-native-svg-charts'
import { Shadow, Gradient, Clips } from './chartAdds'
import { quadrupleLineChart } from '@/data/data'
import { MultipleLinesChartDecorator } from '@/screens/LineChartComponent/chartAdds'

export const LineChartComponent = () => {
    return (
        <LineChart
            style={{ height: 200 }}
            gridMin={-20}
            gridMax={120}
            data={quadrupleLineChart}
            contentInset={{ top: 20, bottom: 20 }}>
            <Grid />
            <MultipleLinesChartDecorator combinedData={quadrupleLineChart} />
        </LineChart>
    )
}

With one exception…
What is MultipleLinesChartDecorator, and how it works?
It’s a variation of well know Dots component. I explained it in the part Line, circle decorators and grid .
Let’s take a look:

interface DecoratorProps {
    x: any
    y: any
    combinedData: {
        data: number[]
        svg: {
            stroke: string
            strokeWidth: number
        }
    }[]
}

const min = 1
const max = 10000000

const uniqueKey = (index: number): number => {
    return Math.floor(Math.random() * (max - min + 1)) + min + index
}

export const MultipleLinesChartDecorator = (props: Partial<DecoratorProps>) => {
    const { x, y, combinedData } = props as DecoratorProps

    return (
        <>
            {combinedData &&
            combinedData.map((item, index) => {
                return (
                    <Svg key={uniqueKey(index)}>
                        {item.data.map((value, index) => (
                            <Circle
                                key={uniqueKey(index)}
                                cx={x(index)}
                                cy={y(value)}
                                r={2.5}
                                stroke={'rgb(0, 0, 0)'}
                                fill={'white'}
                            />
                        ))}
                    </Svg>
                )
            })}
        </>
    )
}

If you take a closer look at the MultipleLinesChartDecorator and Dots components, there is only one difference in the operation process. We just need multiple Dots components for each data array - for each object in a new combined array. In other words, we need to iterate over the combined data array. One more difference is that we have to pass data by ourselves. Our MultipleLinesChartDecorator is getting lost when it’s trying to pull data, with data keys inside data object etc.
We need to type the props for MultipleLinesChartDecorator, pass the combined data as a prop (x and y are still taken from the chart lexical scope), and use it instead of data pulled previously from the chart’s lexical scope. Now we work on the data we passed ourselves. The effect is visible below:

lineChart multiple dots

If we need to display multiple data on one chart, that is a very good way to do it.

Line chart with average

We have all those great examples above, and I hope they will be really useful to you.
But what if we need to put an average value on the chart? Library react-native-charts-svg doesn’t offer us any built solution, but we can make a solution by ourselves, like many times above.

We need an extra line for the average value. If we want to display a line on the chart, we need a data array.
So we need a data array filled with the average value. Let’s prepare a function for that:

export const createAverageValuesArray = (data: number[]): number[] => {
    const averageValue = data.reduce((a, b) => a + b) / data.length
    return Array(data.length).fill(averageValue)
}

Our function takes the original data array, calculates the average, and creates an array with the averages value. The important part is that the length of the new array has to be the same as the original array length. Axis X operates on the index, so if the data array has 10 elements, and our average array would have 5 elements, then the data line will be long for full width, but the average line will take only half of that width. We don’t want that. Let’s remember that the average line, should have the same number of elements in the array, as an original data array.

The next step is to create a combined data array as we did in the previous example. We can also make a function for that:

export const composeDataWithAverageValue = (
    valuesArray: number[],
    averageValuesArray: number[]
) => {
    return [
        {
            data: valuesArray,
            svg: { strokeWidth: 3 },
        },
        {
            data: averageValuesArray,
            svg: { strokeWidth: 1.5, strokeDasharray: [8, 16] },
        },
    ]
}

We didn’t set a stroke (color) property in our objects. Only strokeWidth and strokeDasharray (only for average). In that case, the color for both lines will be taken from svg props passed to the LineChart.
Now we just need to import the LineChart component, and put it all together:

import { LineChart, Grid } from 'react-native-svg-charts'
import { Shadow, Gradient } from './chartAdds'

export const LineChartWithAverage: VFC<Props> = () => {
    const data2 = [80, 10, 95, 48, 24, 67, 51, 12, 33, 0, 24, 20, 50]

    const averageValuesArray = createAverageValuesArray(data2)
    const dataWithAverageValue = composeDataWithAverageValue(data2, averageValuesArray)

    return (
        <>
            <Container>
                <LineChart
                    style={{ height: 300 }}
                    gridMin={-50}
                    gridMax={150}
                    data={dataWithAverageValue}
                    curve={shape.curveNatural}
                    svg={{
                        stroke: 'url(#gradient)',
                    }}
                    contentInset={{ top: 20, bottom: 20 }}>
                    <Shadow />
                    <Gradient />
                </LineChart>
            </Container>
        </>
    )
}

The result is visible below:

lineChartWithAverage

The example with Multiple Line Chart with averages is available in the repository.

Line chart props summary

Let’s summarize props we already used in Line charts:

  • data - array of arbitrary data. For example, it can be array of numbers or objects.
  • style - well known line-style prop. In this case it’s a style for the chart CONTAINER. Not the chart itself. Height is set in default at 0, so we need to pass expected height by ourselves. Always. We can treat container here not like a box, but more like a canvas we’re writing on. If we not set the height, there is nothing we can put chart on.
  • svg - this prop is a style-prop for the chart itself. It can take several properties. A full list of them is available HERE
  • gridMin - minimal visible chart’s value. By default, it’s set for the minimal value of the data. We can set the value by ourselves also, but if we will set it for higher value than the minimal data value, system will take minimal data value. For example if the min value in data array is -20, and we will set it for 0, then system will set it for -20. But if we will set it for -40, then system will set it for -40. In other words, system always compare our value with the lowest value in the array, and set lower one.
  • gridMax - maximal visible chart’s value. Works exactly the same as gridMin, but opposite. System always compare value provided by us with the highest value from the data array, and set the higher one.
  • contentInset - object with four values: top, bottom, left and right. It sets distance between component and chart border. FOr example if we set { botom: 30 }, then distance between component bottom border and chart’s bottom border will be 30px. We can consider it as a padding for chart.
  • curve - shape of our area chart. d3 library has been used here to allow chart to take many different shapes. All the possibilities are listed HERE . We can also read there more about d3 library. To pull some shape from the library, we need to import main object from the it and rename it. shape will be a good choice. Now just pull chosen shape from the shape object. For example curve={shape.curveNatural}.

What else we can use:

  • yAccessor - we pass it a function which tell us, which key in the objects array should be taken as a value to display on the chart. In other words we pass the object key the chart should iterate at. Another thing is that thanks to it, chart iterating over the objects array, can take other properties of the object (bar) and inject it to a specific bar.
  • xAccessor - thanks to that function, we can provide more complicated data structure and chose the value we want to use from keys in objects array (used for axis X) - we will use this props later for other charts, so you will get familiar with it
  • yScale - A function that determines the scale of axis Y. As said in the documentation it’s not very well tested
  • xScale - A function that determines the scale of axis X. As said in the documentation it’s not very well tested
  • xMin - minimal visible value of axis X. Not really useful if you want to use all the available space to show data. Let’s imagine your data start from 0. If you set it from -10, then you will get just empty white space on the left side. If you set it for 10, then part of your data will be not visible. Mobile devices are usually narrow. I recommend using the available space to the maximum, to increase readability
  • xMax - maximal visible value of axis X. Same situation like with xMin
  • yMin - minimal visible value of axis Y. We can get the same effect using gridMin
  • yMax - maximal visible value of axis Y. We can get the same effect using gridMan
  • numberOfTicks - number of lines visible on the background grid (of course only when we use additional component Grid)

(Remember that some props are available only in a specific type of charts. For example, you cannot use start in the LineChart)

Pie Chart

The pie chart is very useful to show the percentage participation in something. We will create few examples to get through props and give you something nice and ready to use.

Pie chart data

To display the most basic example of react-native-svg-charts PieChart, we just need a data array, width, and height. Here we cannot pass basic number[], as we did before. Every object in the array of objects needs to have a specific structure. Let’s take a look at the PieChartData interface:

export interface PieChartData {
    svg?: Partial<PathProps> | undefined;
    key: string | number;
    value?: number | undefined;
    arc?: {
        outerRadius?: number | string | undefined;
        cornerRadius?: number | string | undefined;
    } | undefined;
}
  • svg - well known style props for svg elements. We can check the full list of possible properties HERE
  • key - ID of each slice of the pie
  • value - the value of each slice of the pie
  • arc - object with values:

    • outerRadius - radius of the single slice of the pie. It can be set separately, different from than whole pie radius.
    • cornerRadius - sets the corner rounding angle of each slice of the pie

Even if the PieChartData interface tells us, that only key property is required, it is not entirely true. If we do not pass svg with fill or stroke property set, then our piece will be not visible. If we do not pass value, then it will be set to undefined by default, which means - not visible again. We can assume that if we want for each piece to be visible it has to get at least:

  • svg - fill or stroke
  • key - required
  • value

With that knowledge, we can create our most basic PieChart.

Basic Pie Chart

First let’s prepare the function which will take an array of numbers as an argument and return an array of data, required for the PieChart:

export const getPieChartData = (data: number[]) => {
    return data.map((item, index) => {
        const randomColor = '#' + Math.floor(Math.random() * 16777215).toString(16)

        return {
            key: index,
            value: item,
            svg: { fill: randomColor },
        }
    })
}

Now we can create our component:

import { PieChart} from 'react-native-svg-charts'
import { getPieChartData } from './utilityFunctions'

export const PieChartComponent = () => {
    const data10 = [40, 83, 60, 30, 75, 90, 27, 52]
    const pieChartData = getPieChartData(data10)

    return (
        <PieChart
            style={{ width: 200, height: 200 }}
            data={pieChartData}
        />
    )
}

The result of our work is visible below:

pieChart base

Looks pretty nice. But of course, we will not stop on the base form.

Inner radius, pad angle and sort

We will now focus on the three new props we can use in the PieChart:

  • innerRadius - it’s a radius of the inner circle (in px). The bigger it is, the slimmer is our ‘donut’.
  • padAngle - this property is not working very well. To be honest it’s hard to control it. It should be the angle between slices. But it has an important function: if you set it for ‘0’, the distance between the slices will disappear. So we should remember two options. Default, when we have our distance between the slices or 0 when that distance is gone.
  • sort - sort the slices. If you take a closer look at the base example above, you notice that slices are arranged from the smallest to the largest one. That’s the default behavior, but we can change it using this prop.

We will use again our getPieChartData function and props listed above to create another example:

import { PieChart} from 'react-native-svg-charts'
import { getPieChartData } from './utilityFunctions'

export const PieChartComponent = () => {
    const data10 = [40, 83, 60, 30, 75, 90, 27, 52]
    const pieChartData = getPieChartData(data10)

    return (
        <PieChart
            style={{ width: 200, height: 200 }}
            innerRadius={0}
            data={pieChartData}
            padAngle={0}
            sort={(a, b) => b.key - a.key}
        />
    )
}

We set innerRadius and padAngle(angle between slices) for 0. Slices now are sorted by the key, not by the value like before:

pieChart innerRadius padAngle sort

What we received is not a donut anymore but literally the pie :)

Corner radius and labels

Now we will consider a more complicated case.
First let’s create a donut, where each slice has rounded angles.
We already know that each of our slices can get arc props, which is an object with cornerRadius property inside.

  • cornerRadius - sets the corner rounding angle of each slice of the pie (set in px)

We can modify our getPieChartData function, adding cornerRadius property:

export const getPieChartDataRounded = (data: number[]) => {
    return data.map((item, index) => {
        const randomColor = '#' + Math.floor(Math.random() * 16777215).toString(16)

        return {
            key: index,
            value: item,
            svg: { fill: randomColor },
            arc: { cornerRadius: 5 },
        }
    })
}

Other props that will be necessary for this example are:

  • outerRadius - sets the distance between the center of the pie and its outer border (set in px or %. If set in % - ‘100% means that it takes all the space to the closest container border )
  • labelRadius - sets the distance between pie center and eventual labels, we want to add (set in px or %)

Now we’re ready to create PieChart with rounded angles of the slices:

import { PieChart} from 'react-native-svg-charts'
import { getPieChartDataRounded } from './utilityFunctions'

export const PieChartComponent = () => {
    const data10 = [40, 83, 60, 30, 75, 90, 27, 52]
    const pieChartDataRounded = getPieChartDataRounded(data10)

    return (
        <PieChart
            style={{ width: 300, height: 300 }}
            data={pieChartDataRounded}
            innerRadius={35}
            outerRadius={70}
            labelRadius={120}
            sort={(a, b) => b.key - a.key}
        />
    )
}

pieChart roundedCorners

Another step is to create Labels component:

import { Circle, Line, G, Text } from 'react-native-svg'
import { PieChartData } from 'react-native-svg-charts'

interface LabelsProps {
    slices: {
        pieCentroid: string
        labelCentroid: string
        data: PieChartData
    }[]
}

export const Labels = (props: Partial<LabelsProps>) => {
    const { slices } = props as LabelsProps
    return (
        <>
            {slices.map((slice, index) => {
                const { labelCentroid, pieCentroid, data } = slice
                return (
                    <G key={index}>
                        <Line
                            x1={labelCentroid[0]}
                            y1={labelCentroid[1]}
                            x2={pieCentroid[0]}
                            y2={pieCentroid[1]}
                            stroke={data?.svg && data.svg.fill}
                        />

                        <G x={labelCentroid[0]} y={labelCentroid[1]}>
                            <Circle r={22} fill={data?.svg && data.svg.fill} />
                            <Circle r={17} fill={'white'} />
                            <Text
                                key={index}
                                x={-0.5}
                                y={1.5}
                                fill={'black'}
                                textAnchor={'middle'}
                                alignmentBaseline={'middle'}
                                fontSize={16}
                                fontWeight={'bolder'}
                                stroke={'white'}
                                opacity={'1'}
                                strokeWidth={0.4}>
                                {data.value}
                            </Text>
                        </G>
                    </G>
                )
            })}
        </>
    )
}

What is going on there, and what is it made of?
Let’s start from the beginning.
PieChart prepare for us slices[], which can be used to set labels for chart. slices[] is composed of objects containing:

  • labelCentroid - the array with 2 coordinates: [x, y] that determines the center of the label
  • pieCentroid - the array with 2 coordinates: [x, y] that determines the center of the pie slice
  • data - object with information about slice

Like we already know, G component is a wrapper for the SVG elements. Line is an SVG element for the line, with x1, x2, y1, y2 coordinates, and stroke as o color of the line taken from the data object (that we previously passes as a prop to the PieChart). The first Circle is an outer circle of the label, and the second Circle is the inner circle of the label. The last element Text is the value, taken again from the data object. Like in every element above, x, y are the coordinates and r is the circle radius. Text element can take various props, depending on what style would we like to apply for it(please check Text props in the react-native-svg types).

Now let’s apply our Label component to the PieChart we already made before:

import { PieChart } from 'react-native-svg-charts'
import { Labels } from '@/screens/PieChartComponent/chartAdds'
import { getPieChartDataRounded } from './utilityFunctions'

export const PieChartComponent = () => {
    const data10 = [40, 83, 60, 30, 75, 90, 27, 52]
    const pieChartDataRounded = getPieChartDataRounded(data10)

    return (
        <PieChart
            style={{ width: 300, height: 300 }}
            data={pieChartDataRounded}
            innerRadius={35}
            outerRadius={70}
            labelRadius={120}
            sort={(a, b) => b.key - a.key}>
            <Labels />
        </PieChart>
    )
}

I hope you agree with me, that final effect looks interesting ;) :

pieChart labels

Slice outer radius

We already know what the outerRadius property does. Just to remind you, it sets the distance between the circle center and its border. So what if we set it for a slice in our data array? The slice will become smaller, or bigger than the circle itself.

Let’s create our data first:

export const data13 = [
    {
        key: 1,
        value: 50,
        svg: { fill: '#600080' },
        arc: { outerRadius: '120%', cornerRadius: 10 },
    },
    {
        key: 2,
        value: 50,
        svg: { fill: '#9900cc' },
        arc: { cornerRadius: 5 },
    },
    {
        key: 3,
        value: 40,
        svg: { fill: '#c61aff' },
        arc: { cornerRadius: 5 },
    },
    {
        key: 4,
        value: 95,
        svg: { fill: '#d966ff' },
        arc: { cornerRadius: 5 },
    },
    {
        key: 5,
        value: 35,
        svg: { fill: '#ecb3ff', stroke: 'purple', strokeWidth: 2 },
        arc: { outerRadius: '120%', cornerRadius: 10 },
    },
]

We set outerRadius of two slices, for 120%. It’s useful if we want to highlight particular data. The effect is visible below:

pieChart sliceSouterRadius

import { PieChart} from 'react-native-svg-charts'
import { getPieChartDataRounded } from './utilityFunctions'
import { data13 } from '@/data/data'

export const PieChartComponent = () => {
    return (
        <PieChart
            style={{ width: 300, height: 300 }}
            outerRadius={'70%'}
            innerRadius={40}
            data={data13}
        />
    )
}

We can also create a function which will make each slice in the pie smaller than the previous one:

export const getPieChartDataSteps = () => {
    const keys = ['google', 'facebook', 'linkedin', 'youtube', 'Twitter']
    const values = [15, 25, 35, 45, 55]
    const colors = ['#600080', '#9900cc', '#c61aff', '#d966ff', '#ecb3ff']
    return values.map((key, index) => {
        return {
            key,
            value: values[index],
            svg: { fill: colors[index], stroke: colors[index - 1], strokeWidth: 2 },
            arc: { outerRadius: 70 + values[index] + '%', padAngle: 0.1 },
        }
    })
}

Thanks to that, we can prepare examples like this one:

pieChart slicesOuterRadius2

import { PieChart} from 'react-native-svg-charts'
import { getPieChartDataRounded } from './utilityFunctions'
import { data13 } from '@/data/data'

export const PieChartComponent = () => {
    const pieChartDataSteps = getPieChartDataSteps()

    return (
        <PieChart
            style={{ width: 310, height: 300 }}
            outerRadius={'80%'}
            innerRadius={'45%'}
            data={pieChartDataSteps}
        />
    )
}

Nested pie charts

We can also make more complicated charts, with a very simple method. We can nest different pie charts in other ones, by manipulating their innerRadius and outherRadius:

Let’s use getPieChartData function again:

export const DeepPieChart = () => {
    const pieChartData = getPieChartData(data10)
    const pieChartData2 = getPieChartData(data11)
    const pieChartData3 = getPieChartData(data12)
    const pieChartData4 = getPieChartData(data9)
    const pieChartData5 = getPieChartData(data8)
    const pieChartData6 = getPieChartData(data5)
    const pieChartData7 = getPieChartData(data2)

    return (
        <>
            <PieChart
                style={{ width: 250, height: 250 }}
                innerRadius={25}
                outerRadius={35}
                data={pieChartData}>
                <Svg>
                    <PieChart
                        style={{ width: 250, height: 250 }}
                        innerRadius={40}
                        outerRadius={50}
                        data={pieChartData2}>
                        <Svg>
                            <PieChart
                                style={{ width: 250, height: 250 }}
                                innerRadius={55}
                                outerRadius={65}
                                data={pieChartData3}>
                                <Svg>
                                    <PieChart
                                        style={{ width: 250, height: 250 }}
                                        innerRadius={70}
                                        outerRadius={80}
                                        data={pieChartData4}>
                                        <Svg>
                                            <PieChart
                                                style={{ width: 250, height: 250 }}
                                                innerRadius={85}
                                                outerRadius={95}
                                                data={pieChartData5}>
                                                <Svg>
                                                    <PieChart
                                                        style={{ width: 250, height: 250 }}
                                                        innerRadius={100}
                                                        outerRadius={110}
                                                        data={pieChartData6}>
                                                        <Svg>
                                                            <PieChart
                                                                style={{ width: 250, height: 250 }}
                                                                innerRadius={115}
                                                                outerRadius={125}
                                                                data={pieChartData7}
                                                            />
                                                        </Svg>
                                                    </PieChart>
                                                </Svg>
                                            </PieChart>
                                        </Svg>
                                    </PieChart>
                                </Svg>
                            </PieChart>
                        </Svg>
                    </PieChart>
                </Svg>
            </PieChart>
        </>
    )
}

Like I said before, we manipulate circles innerRadius and outerRadius. Every next pieChart’s innerRadius is 15px wider. It’s the same for outerRadius. Also, the important thing is that we need to wrap each nested pieChart in Svg component. In other cases, data from the higher-order pieChart will overwrite data of the nested pieChart. We would get 7 exactly the same pieCharts. But, we already know that, so we didn’t make this mistake. We got the result we expected:

nestedPieCharts

Pie chart props summary

Let’s summarize props we already used in Pie charts:

  • data - an array of arbitrary data. For example, it can be an array of numbers or objects.
  • style - well known line-style prop. In this case, it’s a style for the chart’s CONTAINER. Not the chart itself. Height is set in default at 0, so we need to pass the expected height by ourselves. Always. We can treat the container here not as a box, but more like a canvas, we’re writing on. If we did not set the height, there is nothing we can put the chart on.
  • svg - this prop is a style-prop for the chart itself. It can take several properties. A full list of them is available HERE
  • outerRadius - sets the distance between the center of the pie and its outer border (set in px or %. If set in % - ‘100% means that it takes all the space to the closest container border )
  • labelRadius - sets the distance between pie center and eventual labels, we want to add (set in px or %)
  • innerRadius - it’s a radius of the inner circle (in px). The bigger it is, the slimmer is our ‘donut’.
  • padAngle - this property is not working very well. To be honest it’s hard to control it. It should be the angle between slices. But it has an important function: if you set it for ‘0’, the distance between the slices will disappear. So we should remember two options. Default, when we have our distance between the slices or 0 when that distance is gone.
  • sort - sort the slices. Slices are arranged from the smallest to the largest one (value). That’s the default behavior, but we can change it using this prop.

What else we can use:

  • startAngle - the start angle in radians of the entire pie
  • endAngle - the end angle in radians of the entire pie
  • valueAccessor - we pass it a function that tells us, which key in the object’s array should be taken as a value to display on the chart. In other words, we pass the object key the chart should iterate at. Another thing is that thanks to it, chart iterating over the object’s array, can take other properties of the object (slice) and inject them into a specific slice.

Progress Circle

One of the simplest charts. Basically, we can consider it as a line in the shape of a circle. But, as we have already seen working with LineChart, the simplest solutions can be most useful. And, the fact is, that progress circle is used very often.

Basic Progress circle

There is not much to say about the basic progress circle, so let’s create one and see what we need to use, to display it:

import { ProgressCircle } from 'react-native-svg-charts'

export const ProgressCircleComponent = () => {
    return (
        <ProgressCircle
            style={{ height: 200 }}
            progress={0.6}
            progressColor={'rgb(192, 0, 0)'}
        />
    )
}

So the first difference that we should notice, is that we have no data array. The reason is simple - the progress circle displays no data. Progress circle display… progress :)
So instead of data props, we have progress props. Also, instead of svg or color props, we have the progressColor props.

To display the basic progress bar we need three props then:

  • style - like always we need to set height, to put our svg elements on something. Of course, we can set a lot of other properties. All of them are listed HERE.
  • progress - progress we want to display. We set it in the range 0-1, which corresponds to values from 0% to 100%.
  • progressColor - color of progressBar. Not the background but the progress line itself.

That’s how it looks like now:

basicProgressBar

Quite simple, but often it’s enough for us.
Anyway, let’s have a little fun with that.

Start angle and end angle

Like you probably guessed, we can change the place, where the progress bar starts and ends on the circle. We have two props responsible for it.

  • startAngle - a point on the circle, where the progress bar starts (number of degrees). Default setting: Math.PI
  • endAngle - a point on the circle, where the progress bar ends (number of degrees). Default setting: -Math.PI

So let’s reverse our progress bar:

import { ProgressCircle } from 'react-native-svg-charts'

export const ProgressCircleComponent = () => {
    return (
        <ProgressCircle
            style={{ height: 200 }}
            progress={0.6}
            progressColor={'rgb(134, 65, 244)'}
            startAngle={-Math.PI}
            endAngle={Math.PI}
        />
    )
}

Our progress bar looks like that now (we also changed the progress bar color):

progressBar reversed

As we know, we use Math.PI to calculate the circumference of the circle. Nothing prevents us from reducing it a bit:

import { ProgressCircle } from 'react-native-svg-charts'

export const ProgressCircleComponent = () => {
    return (
        <ProgressCircle
            style={{ height: 200 }}
            progress={0.7}
            progressColor={'rgb(249, 166, 2)'}
            startAngle={-Math.PI * 0.8}
            endAngle={Math.PI * 0.8}
        />
    )
}

We reduced the circumference of the circle by 20% from each side. Let’s see, what effect we have achieved:

progressBar partial

Progress number corner radius and stroke width

Now we can make something still easy, but more complicated compared to the previous examples:

import { ProgressCircle } from 'react-native-svg-charts'

export const ProgressCircleComponent = () => {
    return (
        <ProgressCircle
            style={{ height: 200 }}
            progress={0.8}
            progressColor={'rgb(249, 166, 2)'}
            startAngle={-Math.PI}
            cornerRadius={0}
            strokeWidth={15}
            endAngle={Math.PI}>
          <Gradient />
          <Text
                  x={-0.5}
                  y={1.5}
                  fill={'black'}
                  textAnchor={'middle'}
                  alignmentBaseline={'middle'}
                  fontSize={36}
                  fontWeight={'bolder'}
                  stroke={'white'}
                  opacity={'1'}
                  strokeWidth={0.4}>
            80%
          </Text>
    )
}

We inserted well known Gradient component and styled the Text component. It’s nothing new for us. But we have two new props, we already use above:

  • cornerRadius - this prop is responsible for the angle of our line
  • strokeWidth - it’s literally the width of our progress line

When you will take a closer look at the end of our progress line, you will notice, it’s rounded. It’s because the default value of cornerRadius is 45 (45 degrees). Now we set it to 0, so it will be flat on the end. Also, we used strokeWidth and set it to 15, which makes it 3 times wider (default is 5).

The effect is visible below:

progressCircle wide

Combine stroke width with the angles and text - Speedometer

Ok, let’s create a simple speedometer in this case, because… why not? :) Our maximum speed will be 400 km/h. We will set our endAngle for Math.PI / 2 and startAngle for the -Math.PI / 2. In other words, out circle will take 50% of the original size. Also we will set stroke with for 7px, so it will be little wider. Last thing we will set will be backgroundColor. We have to remeber that if we want to change background color of our COMPONENT, then we will do that in the style props. Here we set background color, for the circle line, we operate at:

-backgroundColor - the color of the circle below the our line (circle in the background, under progress progress line)

Firstly we have to remember, that our progress have to be passed as a number in range 0 - 1. So, we can create a simple function which will convert our speed to the desired value:

const calculateSpeedForProgress = (speed: number, maxSpeed: number) => {
    return speed / maxSpeed
  }

We can provide any speed and max speed values, and we will always get the right value for the progress circle.

Ok, let’s create our Speedometer component then:

import { ProgressCircle } from 'react-native-svg-charts'

export const Speedometer = () => {
  
  const maxSpeed = 400
  const speed = 234
  
  const calculateSpeedForProgress = (speed: number, maxSpeed: number) => {
    return speed / maxSpeed
  }

  const calculatedProgress = calculateSpeedForProgress(speed, maxSpeed)

  return (
          <ProgressCircle
                  style={{ height: 200 }}
                  progress={calculatedProgress}
                  progressColor={'rgb(249, 166, 2)'}
                  backgroundColor={'rgba(194, 65, 244, 0.1)'}
                  strokeWidth={7}
                  startAngle={-Math.PI / 2}
                  endAngle={Math.PI / 2}>
              <Gradient />
              <Text
                 x={1}
                 y={-12}
                 fill={'black'}
                 textAnchor={'middle'}
                 alignmentBaseline={'middle'}
                 fontSize={27}
                 fontWeight={'bolder'}
                 stroke={'white'}
                 opacity={'1'}
                 strokeWidth={0.4}>
                {`${speed} km/h`}
              </Text>
            </ProgressCircle>
          )
}

Here is our basic Speedometer:

speedometer

Nested multiple progress circles

We can make quite the same trick, as we didi with pieChart. We can nest progress circles inside another ones. Here the trick is a little more complicated because, we have to set justifyContent property in the style prop, for center.
Without that all our progress circles will be lifted to the top of the component.

The component itself, should look like that then:

export const DeepProgressCircle = () => {
  return (
    <>
      <ProgressCircle
        style={{ height: 200 }}
        progress={0.8}
        progressColor={'rgb(134, 65, 244)'}
        startAngle={-Math.PI}
        endAngle={Math.PI}>
        <Svg style={{ justifyContent: 'center' }}>
          <ProgressCircle
            style={{ height: 180 }}
            progress={0.7}
            progressColor={'rgb(134, 65, 244)'}
            startAngle={-Math.PI}
            endAngle={Math.PI}>
            <Svg style={{ justifyContent: 'center' }}>
              <ProgressCircle
                style={{ height: 160 }}
                progress={0.6}
                progressColor={'rgb(134, 65, 244)'}
                startAngle={-Math.PI}
                endAngle={Math.PI}>
                <Svg style={{ justifyContent: 'center' }}>
                  <ProgressCircle
                    style={{ height: 140 }}
                    progress={0.5}
                    progressColor={'rgb(134, 65, 244)'}
                    startAngle={-Math.PI}
                    endAngle={Math.PI}>
                    <Svg style={{ justifyContent: 'center' }}>
                      <ProgressCircle
                        style={{ height: 120 }}
                        progress={0.4}
                        progressColor={'rgb(134, 65, 244)'}
                        startAngle={-Math.PI}
                        endAngle={Math.PI}>
                        <Svg style={{ justifyContent: 'center' }}>
                          <ProgressCircle
                            style={{ height: 100 }}
                            progress={0.3}
                            progressColor={'rgb(134, 65, 244)'}
                            startAngle={-Math.PI}
                            endAngle={Math.PI}
                          />
                        </Svg>
                      </ProgressCircle>
                    </Svg>
                  </ProgressCircle>
                </Svg>
              </ProgressCircle>
            </Svg>
          </ProgressCircle>
        </Svg>
      </ProgressCircle>
    </>
  )
}

The result is visible below:

deepProgressCircle

It’s very useful if we need to compare progress of the different actions, for example.

Colored bows

We have already studied a few useful cases, so let’s make a little art.
We will take the example from above, set the backgroundColor of the progress circles for white. Also we will work a bit with the startAngle and endAngle:

export const DeepProgressCircle = () => {
  return (
    <>
      <ProgressCircle
              style={{ height: 200 }}
              progress={0.8}
              backgroundColor={'white'}
              progressColor={'rgb(134, 65, 244)'}
              startAngle={-Math.PI}
              endAngle={Math.PI}>
        <Svg style={{ justifyContent: 'center' }}>
          <ProgressCircle
                  style={{ height: 180 }}
                  progress={0.7}
                  backgroundColor={'white'}
                  progressColor={'blue'}
                  startAngle={-Math.PI * 0.9}
                  endAngle={Math.PI * 1.1}>
            <Svg style={{ justifyContent: 'center' }}>
              <ProgressCircle
                      style={{ height: 160 }}
                      progress={0.6}
                      backgroundColor={'white'}
                      progressColor={'green'}
                      startAngle={-Math.PI * 0.8}
                      endAngle={Math.PI * 1.2}>
                <Svg style={{ justifyContent: 'center' }}>
                  <ProgressCircle
                          style={{ height: 140 }}
                          progress={0.5}
                          backgroundColor={'white'}
                          progressColor={'red'}
                          startAngle={-Math.PI * 0.7}
                          endAngle={Math.PI * 1.3}>
                    <Svg style={{ justifyContent: 'center' }}>
                      <ProgressCircle
                              style={{ height: 120 }}
                              progress={0.4}
                              backgroundColor={'white'}
                              progressColor={'orange'}
                              startAngle={-Math.PI * 0.6}
                              endAngle={Math.PI * 1.4}>
                        <Svg style={{ justifyContent: 'center' }}>
                          <ProgressCircle
                                  style={{ height: 100 }}
                                  progress={0.3}
                                  backgroundColor={'white'}
                                  progressColor={'yellow'}
                                  startAngle={-Math.PI * 0.5}
                                  endAngle={Math.PI * 1.5}
                          />
                        </Svg>
                      </ProgressCircle>
                    </Svg>
                  </ProgressCircle>
                </Svg>
              </ProgressCircle>
            </Svg>
          </ProgressCircle>
        </Svg>
      </ProgressCircle>
    </>
  )
}

As you can see in each subsequent case we reduced startAngle for 10%, and increased endAnglefor 10%. Thanks to that, each of our progress circle still have 360 deg, but is rotated 36 deg (10% we used to reduce startAngle and increased endAngle), to the right.
We also reduced each subsequent progress for 0.1. Thanks to that we got the rainbow bows:

rainbowBows

If we set progress prop of all of them for 0.8, we can perfectly see how each of the subsequent circles turned 36 deg to the right:

rainbowBows2

Pac-man

At the end of the ProgressCircle part, I just couldn’t resist to create Pac-man :) so here it is:

import { ProgressCircle } from 'react-native-svg-charts'

export const Pacman = () => {
  return (
    <>
      <ProgressCircle
        style={{ height: 200 }}
        progress={0.79}
        strokeWidth={100}
        cornerRadius={0}
        backgroundColor={'white'}
        progressColor={'#ffe737'}
        startAngle={-Math.PI * 1.3}
        endAngle={Math.PI * 0.7}
      />
    </>
  )
}

pac man

Pie chart props summary

Let’s summarize props we already used in the Progress circle:

  • style - like always we need to set height, to put our svg elements on something. Of course, we can set a lot of other properties, available in the CSS sheets
  • progress - progress we want to display. We set it in the range 0-1, which corresponds to values from 0% to 100%.
  • progressColor - color of progressBar. Not the background but the progress line itself.
  • startAngle - a point on the circle, where the progress bar starts (number of degrees). Default setting: Math.PI
  • endAngle - a point on the circle, where the progress bar ends (number of degrees). Default setting: -Math.PI
  • cornerRadius - this prop is responsible for the angle of our line
  • strokeWidth - it’s literally the width of our progress line
  • backgroundColor - the color of the circle below the line (circle in the background, under progress line)

Axes

So far we have gone through 5 types of charts:

  • Area Chart
  • Bar Chart
  • Line Chart
  • Pie Chart
  • Progress Circle

For sure, you already noticed, maybe asked yourself, where are the axes?
Of course, we don’t use them in the Pie Chart or Progress Circle (we can create our default labels for them). But with the first three kinds of charts, they are almost inseparable.

In the react-native-svg-charts, axis X and axis Y are separated components. In fact, they can be so troublesome sometimes, that I decided to devote a separate chapter to them.
Let’s dive into them and talk about those possibly problematic parts, and how to get through them. We will use one of the previously prepared and explained components, to wrap it up inside axes.

Axis Y

To display the axis Y ‘on’ our chart, we have to follow a few rules. The first of them is that the chart and the axis have to be places in the same wrapping container (for example in View).
Another one is that we need to pass basic data to the axis. Thanks to that, component will know how to render proper axis for the chart. Which data exactly?
We need to consider two basic situations:

  1. When we pass an number[] to the chart. For example:

    const data = [80, 10, 95, 48, 24, 67, 51, 12, 33, 0, 24, 20, 50]

    That’s the most basic situation, and we just need to pass the same data array to the axis (I will show you how soon). We pass the same data array to the chart and to the axis.

  2. When we had to construct objects[]. We already did that many times in this tutorial. For example when we were creating LineChart with the average value:

    export const composeDataWithAverageValue = (
    valuesArray: number[],
    averageValuesArray: number[]
    ) => {
      return [
        {
         data: valuesArray,
         svg: { strokeWidth: 3 },
        },
        {
         data: averageValuesArray,
         svg: { strokeWidth: 1.5, strokeDasharray: [8, 16] },
        },
      ]
    }
    const dataWithAverageValue = composeDataWithAverageValue(data2, averageValuesArray)

    Now the construction is more complicated, but what we have to do is very simple. We just need to pass to the axis, number[] which we used as a base array. In case above it was data2. All we have to do, is to pass this basic number[] to the axis (I will show you how soon).

What I have already explained is in fact the data props, we pass to the axis. So, let’s list and explain props we pass to the axis Y:

  • data - number[]. Array of basic values we provided to the chart (or eventually used, to create more complicated structure that was then passed to the chart)
  • formatLabel - function we pass to set, how exactly values on the axis Y should be displayed. For example if we want to show speed in km/h, we can pass the function “(value) => ${value} km”, and values on the axis Y will be displayed with the additional ‘km/h’. Of course, we can just do nothing and don’t pass our custom value. In that case we will get bare numbers on the axis Y.
  • numberOfTicks - default value - 10. Simply, number of the values displayed on the axis Y. If we set it for 2 just two values - max and nim will be displayed on the axis, without intermediate values. Of course, the axis is divided proportionally into the appropriate number of parts.
  • style - well known line-style prop. In this case it refers to the container for the axis Y.
  • svg - this prop is a style-prop for the axis itself. It can take several properties. A full list of them is available HERE
  • contentInset - object with four values: top, bottom, left and right. It sets distance between wrapping component and axis border.
  • min - works exactly the same as the gridMin prop in the charts. Sets the minimal value, of the axis. It HIGHLY RECOMMENDED to set here the same value, as we did for the gridMin in the chart, we want to display with the axis. In other case axis will be not proportional to the chart. Of course if we didn’t set gridMin for the chart, you also shouldn’t do that with min for the axis.
  • max - works on the same principle as min above, but with maximal value and gridMax.

HINT : If you put axisY above the chart component in the wrapper container, axisY will be displayed on the left side of the chart. If you do the opposite, it will be displayed on the right side of the chart.

With this knowledge, we can now take the previously prepared chart, put it in the container, and inject our axis Y component there:

import React from 'react'
import { data2 } from '@/data/data'
import { ChartContainer } from './BasicAxisY.styled'
import { YAxis } from 'react-native-svg-charts'
import { LineChartWithAverage } from '@/screens/LineChartComponent/LineChartWithAverage/LineChartWithAverage'

export const BasicAxisY = () => {
  return (
    <ChartContainer>
      <YAxis
        data={data2}
        contentInset={{ top: 20, bottom: 20 }}
        min={-50}
        max={150}
        svg={{
          fill: 'grey',
          fontSize: 11,
        }}
        style={{ marginRight: 5 }}
        formatLabel={(value) => `${value} km`}
      />
      <LineChartWithAverage />
    </ChartContainer>
  )
}

I think the settings above should be perfectly clear for us. fontSize property, used in the svg prop, of course refers to size of our values, displayed in the axis Y. Also we didn’t set numberOfTicks, because I wanted to leave the default value. Why we set the contentInset for { top: 20, bottom: 20 }? Because the chart have it set for the same values.
Also, I used the styled components here. To avoid confusion, you can find style attributes for the ChartContainer (which is in fact just styled View component), here:

import styled from 'styled-components/native'

export const ChartContainer = styled.View`
  flex-direction: row;
  margin-vertical: ${({ theme }) => theme.spacing.xl}px;
  position: relative;
`

The result is visible below:

basicAxisY

Axis Y Line

I’m aware that one question is in the air: “If it’s an axis… so where is the axis line…?“.
For sure that was my first question, when I used axisY from the react-native-scg-charts library for the first time.
The answer will probably not satisfy you, but as far I’m 99% sure, there is no props responsible for drawing it. Values just hang in the air.
What can we do then? We can simply draw our custom line and put it on the chart. I already did it for you, and you can find the solution below:

import React from 'react'
import { data2 } from '@/data/data'
import { ChartContainer } from './AxisYWithLine.styled'
import { YAxis } from 'react-native-svg-charts'
import { Arrow, AxisYLine } from '@/screens/Axes/AxisYWithLine/AxisYWithLine.styled'
import { LineChartWithAverage } from '@/screens/LineChartComponent/LineChartWithAverage/LineChartWithAverage'

export const AxisYWithLine = () => {
  return (
    <>
      <ChartContainer>
        <YAxis
          data={data2}
          contentInset={{ top: 20, bottom: 20 }}
          min={-50}
          max={150}
          svg={{
            fill: 'grey',
            fontSize: 11,
          }}
          style={{ marginRight: 5 }}
          numberOfTicks={5}
          formatLabel={(value) => `${value} km`}
        />
        <AxisYLine />
        <Arrow />
        <LineChartWithAverage horizontalGrid />
      </ChartContainer>
    </>
  )
}

Like you can see we inserted AxisYLine and Arrow to the container, between axisY and LineChartWithAverage component. Like I said I’m using styled components, but there is nothing to be scared of if you didn’t used it before.
Let’s take a look how the AxisYLine and Arrow elements are created:

import styled from 'styled-components/native'

export const ChartContainer = styled.View`
  flex-direction: row;
  margin-vertical: ${({ theme }) => theme.spacing.xl}px;
  position: relative;
`

export const AxisYLine = styled.View`
  height: 243px;
  width: 1px;
  position: absolute;
  left: 42px;
  bottom: 32px;
  background-color: lightgrey;
`

export const Arrow = styled.View`
  height: 5px;
  width: 5px;
  position: absolute;
  left: 40px;
  top: 23px;
  border-left-width: 1px;
  border-left-color: grey;
  border-top-width: 1px;
  border-top-color: grey;
  transform: rotate(45deg);
`

I hope I don’t need to explain style properties I used, but for those who never used styled components before:
I encourage you with all my heart, to use styled components because coding is so much more enjoyable with it, BUT YOU DON’T HAVE TO of course. In place of the AxisYLine in the AxisYWithLine component, you can just use View component and style it using your own method (line-styling, scss sheet, styleShit etc.)

What I should also mention is that I have set horizontal grid in the chart component, and numberOfTicks for 5. Let’s see what we got:

axisYWithLine

Axis X

The XAxis topic is very similar to the axisY topic. In fact, we have only few differences, and most important of them are very simple:

  1. Not the values, but indexes from the array are displayed on the XAxis
  2. We don’t have the min and the max props, because we display indexes here, so the values are hard.

Apart from the above, we use the same props for the XAxis as we did for the axisY.
We also create them in the same way:

import React from 'react'
import { data2 } from '@/data/data'
import { ChartContainer } from './BasicAxisX.styled'
import { XAxis } from 'react-native-svg-charts'
import { LineChartWithAverage } from '@/screens/LineChartComponent/LineChartWithAverage/LineChartWithAverage'

export const BasicAxisX = () => {
  return (
    <ChartContainer>
      <LineChartWithAverage />
      <XAxis
        style={{ marginHorizontal: -10 }}
        data={data2}
        contentInset={{ left: 10, right: 10 }}
        svg={{ fontSize: 10, fill: 'black' }}
      />
    </ChartContainer>
  )
}

The good practice is to set value of the contentInset for {{ left: 10, right: 10 }}. In other case, first and last values on the axis, will be not shown properly. To keep the proportion between the chart ans XAxis we have to set chart’s container horizontal padding for the 10px.
Our base XAxis is visible below:

basicAxisX

Axis X Line

We face the same problem, we had with the axisY: Where is the line? Of course, the solution is also the same, but like we know, the width of different devices can be really confusing. How to make a custom line, and make sure that the width of the line will always fit the axis and the chart’s width?
There are several ways to resolve that problem. I prefer to use onLayout event.
I will apply it to our new component and explain how it works below.
Just for fun I also inserted condition to the formatLabel prop. THanks to that, only 0 and indexes divisible by 4, will be displayed on the XAxis:

import React, { useState } from 'react'
import { data2 } from '@/data/data'
import { Arrow, AxisXLine, ChartContainer } from './AxisXWithLine.styled'
import { XAxis } from 'react-native-svg-charts'
import { LineChartWithAverage } from '@/screens/LineChartComponent/LineChartWithAverage/LineChartWithAverage'

export const AxisXWithLine = () => {
  const [componentWidth, setComponentWidth] = useState(0)

  return (
    <ChartContainer
      onLayout={(event) => {
        const { width } = event.nativeEvent.layout
        setComponentWidth(width)
      }}>
      <LineChartWithAverage />
      <XAxis
        style={{ marginHorizontal: -10, marginTop: 10 }}
        data={data2}
        formatLabel={(value, index) => {
          if (index % 4 === 0) {
            return index
          }
          return ''
        }}
        contentInset={{ left: 10, right: 10 }}
        svg={{ fontSize: 10, fill: 'black' }}
      />
      <AxisXLine width={componentWidth} />
      <Arrow />
    </ChartContainer>
  )
}

onLayout event can be very useful if we need to get information about the container we use in the application. For example, it’s width.
Because we haven’t set ChartContainer width, it takes up all the available space. Thanks to the onLayout we always get the current width. Now we just need to pass it to the AxisXLine component, set it as its width, and we can be sure, that line width will always fit our chart’s width:

interface LineProps {
  width: number
}

export const AxisXLine = styled.View<LineProps>`
  height: 1px;
  width: ${(props) => props.width}px;
  position: absolute;
  left: 0;
  bottom: 22px;
  background-color: lightgrey;
`

export const Arrow = styled.View`
  height: 5px;
  width: 5px;
  position: absolute;
  right: 0;
  bottom: 20px;
  border-left-width: 1px;
  border-left-color: grey;
  border-top-width: 1px;
  border-top-color: grey;
  transform: rotate(135deg);
`

The Arrow component don’t need any additional settings. Our new chart with XAxis:

axisXWithLine

HINT : If you put XAxis above the chart component in the wrapper container, XAxis will be displayed on the top of the chart. If you do the opposite, it will be displayed on the bottom of the chart. Usually the desired result is to display it below.

Axis X and Axis Y together

It is time to display both axes on the same graph. Of course, we can do it, but you need to know the trick if you want to do it properly.
I will first show the code, and then explain to you what exactly happened:

import { XAxis, YAxis } from 'react-native-svg-charts'
import { data2 } from '@/data/data'
import { LineChartWithAverage } from '@/screens/LineChartComponent/LineChartWithAverage/LineChartWithAverage'
import React, { useState } from 'react'
import {
  ChartContainer,
  HorizontalArrow,
  VerticalArrow,
  AxisXLine,
  AxisYLine,
} from './BothAxesWithLines.styled'
import { SafeAreaView } from 'react-native'

export const BothAxesWithLines = () => {
  const [componentWidth, setComponentWidth] = useState(0)

  return (
    <SafeAreaView
      style={{ flexDirection: 'row', flex: 1 }}
      onLayout={(event) => {
        const { width } = event.nativeEvent.layout
        setComponentWidth(width)
      }}>
      <YAxis
        data={data2}
        contentInset={{ top: 20, bottom: 20 }}
        min={-50}
        max={150}
        svg={{
          fill: 'grey',
          fontSize: 11,
        }}
        style={{ marginRight: 5, height: 300 }}
        numberOfTicks={10}
        formatLabel={(value) => `${value} km`}
      />
      <ChartContainer>
        <LineChartWithAverage />
        <XAxis
          style={{ marginHorizontal: -10, width: componentWidth, marginTop: 10 }}
          data={data2}
          formatLabel={(value, index) => index}
          contentInset={{ left: 10, right: 10 }}
          svg={{ fontSize: 10, fill: 'black' }}
        />
        <AxisXLine width={componentWidth} />
        <AxisYLine />
        <HorizontalArrow />
        <VerticalArrow />
      </ChartContainer>
    </SafeAreaView>
  )
}

Or main wrapper is now the SafeAreView. It the wrapper for the axisY and the ChartContainer. In turn the ChartContainer is the wrapper for the XAxis and chart itself.
Why? I will quote the authors’ explanation:

“Layout of an x-axis together with a y-axis is a problem that stems from flexbox. All react-native-svg-charts components support full flexbox and therefore all layout problems should be approached with the mindset “how would I layout regular Views with flex in this way”. In order for us to align the axes correctly we must know the height of the x-axis or the width of the x-axis and then displace the other axis with just as many pixels. Simple but manual.”

I will add from myself, that the height of YAxis have to be set for the same value as for the chart. In our example LineChart (LineChartWithAverage) and YAxis have the same height: 300px.
Also the width of the XAxis have to be set for the width of the main component. Best way is to use onLayout event, as we did in our example.
Otherwise, all values will be compressed into one point, and chart will be not displayed.

That’s how the full chart looks:

bothAxes

Summary

Like I said at the beginning of this article, you can find all the examples (and few more) in our repository:

React Native Chart Examples Library

As a bonus you will find there ScatteredChart section.
React-native-svg-charts is not offering this kind of solution for the users. That’s why i prepared my custom solutions especially for you.
Those examples and the functions provided for them, can be used in different situations, so I encourage you to check it by yourself.
I’m sure it will be useful for you in your work :)

I hope this article, and repository will help you with your work, and encourage you to use charts in the projects. My idea was to explain to you with details everything we used, because a good understanding of the topic, is basic to use something with confidence. I hope, now you’re able to make your own unique charts, and beautify the application with them.

Greetings from the TWG Team!


Written by Conrad Gauza.