Let’s change the shape of our line for the steps. A full list of shapes can be found HERE .
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 exactly? Let’s take a look at the chart below:
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 the elements inside to their own dimensions.That’s how we use it inside the chart component:
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?
ClipPath
- a container for the svg
element Rect
. It also holds the ID which is a key to invoke this structure. We used it in the svg
props clipPath
property. It puts to use the old JS rule, according to which we can call an element using its ID.Rect
- svg
basic element which creates a rectangleIf 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). It’s now set to 0, which means it sticks to the left border of the chart.y
- position on the axis Y (in px). It’s now 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, it’s 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. It’s now set at 100%, so the rectangle covers the entire height of the chart.Why does it affect only the line? Because it’s injected inside the chart. Grid
and Gradient
are separated components. That’s the magic that goes on behind the scene :)
We can also add DashedLine
component to cover the shadow. There is not much to explain here, 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!
Now we need to put few different data lines on one chart. To complicate things a bit, we will also add the decorators to all points at the lines. Like you’ve probably guessed, we need to work with our data array again. In fact, we need to create the combined array. Combined of what? The data arrays.
We can imagine we’ve got four number[]
:
We need to create an object from each of them, and push them into our combined data array:
So what happened?
We took each data array and created an object which contains:
svg
props for each arrayWe 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, probably to compare them, 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:
With one exception…
What is MultipleLinesChartDecorator
, and how does it work?
It’s a variation of well know Dots
component. I’ve already explained it in the part Line, circle decorators and grid .
Let’s see:
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 pulled from the chart’s lexical scope. Now we work on the data we passed ourselves. The effect is visible below:
If we need to display multiple data on one chart, that is a very good way to do it.
Now we have all those great examples above, and I hope they will come in really useful for 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 one by ourselves just like we have done it many times before.
We need an extra line for the average value. If we want to display a line on the chart, we need a data array. One that is filled with the average value. Let’s prepare a function for that:
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 too long for the full width, but the average line will take only half of that width. That’s not what we’re after. Let’s remember that the average line should have the same number of elements in the array as the original data array.
The next step is to create a combined data array as we’ve done in the previous example. We can also make a function for that:
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:
The result is visible below:
The example with Multiple Line Chart with averages is available in the repository.
Let’s summarize the props that we already used in Line charts:
data
- array of arbitrary data. For example, it can be array of numbers or objects.style
- a well-known line-style prop. In this case it’s a style for the chart CONTAINER – not the chart itself. Height is set at a default 0, so we need to pass the expected height by ourselves. Always. Here, we can treat the container not like a box, but more like a canvas to write on. If we do not set the height, there will be nothing to 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 HEREgridMin
- minimal visible chart value. By default, it’s set at the minimal value of the data. We can set the value by ourselves too, but if we set it at a higher value than the minimal data value, the system will take the minimal data value. For example if the min value in data array is -20 and we set it to 0, then the system will set it at -20. But if we set it to -40, the system will set it at -40. In other words, the system always compares our value with the lowest value in the array, and sets the lower one.gridMax
- maximal visible chart value. It works exactly the same as gridMin, but in the opposite manner. 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 border and chart border. For example if we set { botom: 30 }, then the distance between the component’s bottom border and the chart’s bottom border will be 30px. We can consider it as a padding for chart.curve
- the shape of our area chart. The d3 library has been used here to allow the chart to take many different shapes. All the possibilities are listed HERE . You can also read more about the d3 library there. To pull some shape from the library, we need to import the main object from it and rename it. shape
will be a good choice. Now just pull the 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 a more complicated data structure and choose the value we want to use from the keys in objects array (used for axis X) - we will use this props later for other charts, so you will become familiar with ityScale
- A function that determines the scale of axis Y. As said in the documentation it’s not very well testedxScale
- A function that determines the scale of axis X. As said in the documentation it’s not very well testedxMin
- the minimal visible value of axis X. Not really useful if you are looking to use all the available space to show data. Let’s imagine your data starts at 0. If you set it to -10, you will get an empty white space on the left side. If you set it at 10, then part of your data will be invisible. Mobile devices are usually narrow. I recommend using the available space to the maximum to increase readabilityxMax
- maximal visible value of axis X. Same situation as with xMinyMin
- minimal visible value of axis Y. We can get the same effect using gridMinyMax
- maximal visible value of axis Y. We can get the same effect using gridMannumberOfTicks
- the number of lines visible on the background grid (of course only when we use an additional component Grid)(Remember that some props are available only in a specific types of charts. For example, you cannot use start
in the LineChart
)
The pie chart is very useful for demonstrating percentage participation. We will create a few examples to get through props and give you something nice and ready to use.
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’ve done it before’. Every object in the array of objects needs to have a specific structure. Let’s take a look at the PieChartData
interface:
svg
- a well known style props for svg elements. We can check the full list of possible properties HEREkey
- ID of each slice of the pievalue
- the value of each slice of the piearc
- 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 pieEven 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 not be 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
- requiredvalue
With that knowledge, we can create our most basic PieChart
.
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
:
Now we can create our component:
The result of our work is visible below:
Looks pretty nice, doesn’t it? But of course, we will not stop at the base form.
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 the slices are arranged from the smallest to the largest one. That’s the default behavior, but we can change it using this prop.Once again, we will reach for getPieChartData
function and props listed above to create another example:
We set innerRadius
and padAngle
(angle between slices) to 0
. Slices now are sorted by the key, and not by the value like before:
The result is not a donut, but literally a pie :)
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 by adding the cornerRadius
property:
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 the 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:
Another step is to create Labels
component:
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 the chart. slices[]
is composed of objects that contain:
labelCentroid
- the array with 2 coordinates: [x, y]
that determines the center of the labelpieCentroid
- the array with 2 coordinates: [x, y]
that determines the center of the pie slicedata
- object with information about the sliceWe already know that G
component is a wrapper for 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 passed 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 we would 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
that we made before:
I hope you agree that the final effect looks interesting ;) :
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:
We set the outerRadius
of two slices to 120%
. It’s useful if we want to highlight particular data. The effect is visible below:
We can also create a function which will make each slice in the pie smaller than the previous one:
Thanks to that, we can prepare examples like this one:
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 the getPieChartData
function again:
Like I said before, we manipulate circles innerRadius
and outerRadius
. Every subsequent pieChart’s innerRadius
is 15px wider. The same goes for outerRadius
. Another 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 that of the nested pieChart
. We would get 7 exactly the same pieCharts. But we’re already aware of that, so we didn’t make this mistake. We got just the result that we expected:
Let’s summarize the props that we already used in the Pie charts
data
- an array of arbitrary data. For example, it can be an array of numbers or objects.style
- a well known line-style prop. In this case, it’s a style for the chart’s CONTAINER - not the chart itself. Height is set at a default 0, so we need to pass the expected height by ourselves. Always. Here, we can treat the container not as a box, but more like a canvas to write on. If we do not set the height, there will be nothing to 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 HEREouterRadius
- 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 the 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 the slices. That said, it has an important function: if you set it to ‘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. The 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 the radians of the entire pieendAngle
- the end angle in the radians of the entire pievalueAccessor
- 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.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 it’s a fact that the progress circle is used very often.
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:
The first difference that we should notice is that we have no data array. The reason is simple - the progress circle displays no data. It displays… 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.Now it looks like this:
Quite simple, but often it’s enough for us.
Anyway, let’s have a little fun with that.
Like you’ve probably guessed, we can change the place, where the progress bar starts and ends on the circle. We have two props responsible for that.
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:
Now our progress bar looks like this (we’ve also changed the progress bar color):
As we know, we use Math.PI
to calculate the circle circumference. Nothing prevents us from reducing it a bit:
We reduced the circle’s circumference by 20% from each side. Let’s see what effect we have achieved:
Now we can make something still easy, but more complicated compared to the previous examples:
We’ve inserted the well-known Gradient
component and styled the Text
component. It’s nothing new for us. But we have two new props that we’ve already use above:
cornerRadius
- this prop is responsible for the angle of our linestrokeWidth
- it’s literally the width of our progress lineWhen you will take a closer look at the end of our progress line, you will notice that it’s rounded. That’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:
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:
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:
Here is our basic Speedometer:
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:
The result is visible below:
It’s very useful if we need to compare progress of the different actions, for example.
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
:
As you can see in each subsequent case we reduced startAngle
for 10%, and increased endAngle
for 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:
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:
At the end of the ProgressCircle
part, I just couldn’t resist to create Pac-man :) so here it is:
Let’s summarize the props we’ve already used in the Progress circle:
style
- like always we need to set the height, to put our svg elements on something. Of course, we can set a lot of other properties available in the CSS sheetsprogress
- 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 linestrokeWidth
- it’s literally the width of our progress linebackgroundColor
- 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:
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.
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:
number[]
to the chart. For example:objects[]
. We already did that many times in this tutorial. For example when we were creating LineChart
with the average value: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 HEREcontentInset
- 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:
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:
The result is visible below:
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:
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:
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:
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:
XAxis
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:
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:
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
:
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:
The Arrow
component don’t need any additional settings. Our new chart with XAxis
:
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.
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:
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:
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 will help you with your work and encourage you to use charts in your projects. My idea was to explain everything that we used, because a good understanding of the topic enables us to play with it according to our specific needs. I hope that you’re now able to make your own unique charts and ‘beautify’ the application with them.
Before we begin, I’d like to ask you just one question.
Have you ever used charts in your React Native project, especially with typescript?
If you did, then you know it’s not always easy, but you are also aware what impression it can make on users.
Writing about data in the block of text and showing it on a neat chart cannot be compared.l
Let me show you some detailed methods and examples.
If you’ve never used charts in your mobile app, this article will your step-by-step guide through the react-native-charts-svg library. It will also discuss some additional topics that I decided to touch upon. You will learn how to create really good-looking and useful charts simply, and most importantly – by yourself. You don’t need to worry about complicated parts, or blind spots when you have no idea what’s just happened. Why? Because I intend to make this topic plain and simple for anyone.
I’m pretty sure that the next time when you have to write about data in your project, you will use charts.
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!
First, we need to add the library to our project using npm:
or yarn
We are using typescript, so we also need to add types for it by npm:
or yarn
Now we can start creating our first chart!
Let’s start with the Area chart. First, we need to import it from the library:
If we implement it, just like that:
We cannot see a thing there. We need to add at least 3 props:
data
- an array of arbitrary data. It can be an array of numbers or objects. For now, let’s take it as an array of numbers.style
- a well-known line-style prop. In this case, it’s a style for the chart CONTAINER - not the chart itself. Height is set at a default 0, so we need to pass the expected height by ourselves. Always. Here we can treat the container not as a box, but more like a canvas, to write on. If we did not set the height, there is nothing to overlay the chart on.svg
- a style-prop for the chart. It can take several properties, but the most important one for the Area chart is fill
. If we do not insert it, then technically we have our area chart set, but… it’s not visible.With those 3 props:
It might not be the most beautiful, but at least it’s ready to go:
Now let’s add some more features to our new chart. Our current props of interest are:
gridMin
- minimal visible chart value. By default, it’s set for the minimal value of data. We can also set the value by ourselves, but if we set it a higher than the smallest data value, the system will take the minimal data value. For example, if the min value in the data array is -20, and we set it to 0, then the system will set it to -20. But if we set it at -40, then the system will set it to -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 value. It works the same as gridMin, but in the opposite manner. The system always compares the value provided by us with the highest value from the data array and sets the higher one.contentInset
- an object with four values: top, bottom, left, and right. It sets the distance between the component and the 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 3 additional components. Let’s call them ‘decorators’.
Even if the chart has the same height - 200px, it looks more flattened. That’s because the vertical range is no longer -80 to 95 (default min and max data values), but -100 to 120, just as we’ve set it. Also, we set the contentInset top and bottom for 30px.
The lines in the background are our Grid
, the 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:
One closer look at the code, and we can see that there’s something wrong.
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’s just happened, we can leave it at that and go ahead. Because it’s working! YES, it is!
Of course, the right question is: WHY? And that’s what typescript is doing. It’s asking:
“Hey buddy, it’s working, great. But can you tell me, how that’s possible? You need to pass this prop or explain this weird behavior to me”.
So with the component created like that:
We get errors from typescript:
Let’s first find out why it’s even working in the first place.
Like we can see, the Line
component is placed inside the chart component. We had a specific reason to do that. Charts in the react-native-svg-charts library have their own specific lexical scope.
This means, the 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 .
We finally know how it all works. So how can we handle it with typescript?
There are a few ways to do that, and the easiest one is to use Partial
.
First we create an interface, which will take function props for our Line
component.
We know that Path
props ‘d’ is in fact the line path, so it is for sure type string
. Thanks to the react-native-svg types we can also check it, to be sure:
Let’s create interface LineProps, pass it to the Line
component and make a type assertion.
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 linestroke
- color of the circle borderfill
- color of the circle backgroundBasic Dots
structure:
Like you’ve probably guessed, we’re facing the exact same problem as with the Line
component. Fortunately, the solution is also the same:
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 always be 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[]
. We have the circles on the chart. If we want to modify them, we need to know what props they are taking.
cx
- coordinate on the axis xcy
- coordinate on the axis yr
- radius of the single circlestroke
- color of the circle borderfill
- color of the circle backgroundIn 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 dramatically change the perception of our chart. 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:
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 to 120, and get a blue sky above our values:
In this example we will get rid of the Line
and Circles
components. And the start
prop too. You know we can use them anytime in the line charts, but the visibility of other features will be better without them on the board. As mentioned in the title, our new features will be curve and gradient. So, what are they all about?
The curve is another prop:
curve
- the shape of our area chart. The d3 library was used to allow the chart to take many different shapes. All the possibilities are listed HERE . There’s also plenty of information about the d3 library there. 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 the chosen shape from the shape
object. For example curve={shape.curveNatural}
.The Gradient is another additional component:
Gradient
- this additional component lets us change the color of the chart to the… gradient itself. Unfortunately inserting it inside the chart is not enough to make it work. We also need to remember to change the color of the fill property to '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:
There are no more acute angles. They have been beautifully rounded. Also, the color has been set to the gradient.
So how is the Gradient component built?
Here we use 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:
Another option worth knowing is interpenetration of the areas. We can easily achieve 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.
It can be useful sometimes, but I don’t recommend this kind of solution. If we want to compare data or other charts, like for example Line chart
(we will talk about it later in this article), will be a much better fit.
To prove that, let me show you the anti-pattern. I will put only 3 areas (3 data arrays) on the same chart:
It looks horrible even on the big screen, but on the phone it’s actually completely illegible.
Let’s summarize the props we’ve 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
- a well known line-style prop. In this case, it’s a style for the chart CONTAINER - not the chart itself. The height is set to a default 0, so we need to pass the expected height by ourselves. Always. Here we can treat the container not as a box, but more like a canvas, to write on. If we did not set the height, there is nothing we can put the chart on.svg
- a style-prop for the chart. It can take several properties, but the most important for the Area chart is fill
. If we do not adjust it, then technically we have our area chart set, but… it’s not visible.gridMin
- minimal visible chart value. By default, it’s set to the minimal value of data. We can set the value by ourselves too, but if we set it at 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 set it at 0, then the system will set it to -20. But if we set it at -40, then the system will set it to -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 value. It works the same as gridMin
, but in the opposite manner. 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 border and the chart border. For example, if we set { bottom: 30 }, then the distance between the component bottom border and the chart bottom border will be 30px. We can consider it as padding for the chart.curve
- the shape of our area chart. The d3 library has been used here to allow the chart to take many different shapes. All the possibilities are listed HERE . There’s also 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 the chosen shape from the shape
object. For example curve={shape.curveNatural}
.start
- number on the axis Y, from which the 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 choose 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 become familiar with itxAccessor
- thanks to that function, we can provide a more complicated data structure and choose 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 become familiar with ityScale
- A function that determines the scale of axis Y. As said in the documentation it’s not very well testedxScale
- A function that determines the scale of axis X. As said in the documentation it’s not very well testedxMin
- the minimal visible value of axis X. Rather redundant if you want to use all the available space to show data. Let’s imagine your data starts from 0. If you set it to -10, then you will get just empty white space on the left side. If you set it to 10, then part of your data will be invisible. Mobile devices are usually narrow. I recommend using the available space to the maximum to increase readabilityxMax
- the maximal visible value of axis X. The same situation like with xMinyMin
- the minimal visible value of axis Y. We can get the same effect using gridMinyMax
- the maximal visible value of axis Y. We can get the same effect using gridMannumberOfTicks
- number of lines visible on the background grid (of course only when we use additional component Grid)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 pretty straightforward - we put one value on another. For example, let’s say I have an orchard with apples, pears, cherries, and plums. I want to see how many kilograms of fruit I’ve picked’ 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.
First, we need to import StackedAreaChart
from the react-native-svg-charts:
To create the chart, we need data. The question is, – how do we get our hands on it? 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:
Obviously, we need to pass three values to make any chart visible: data, height, and fill (color). Now that we have our data, height is not a problem, but how do we handle different colors for different fruits?
We need to create an additional array with as many colors as here are keys (fruits in this case):
StackedAreaChart
requires 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:
Now we can create our chart:
Because colors are now picked from the array, handling them is the responsibility of different props. 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:
Thanks to what we’ve already 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 a few new things, but this chapter will mostly be base on the ready examples.
Let’s start with the first one.
First we need to import BarChart
from the react-native-svg-charts library:
Now we can create base BarChart
:
We have well known props:
style
gridMin
gridMax
data
svg
contentInset
Nothing new here. Let’s see our chart:
Now let me introduce you to two new props that occur only in the BarChart
:
-spacingInner
- space between the bars. Default set to 0.05 -spacingOuter
- space outside the bars. In other words from the right and left border of the chart. We can consider it as a kind of padding inside the chart.
We just set the space between the charts to 0.4, which means that we set it at 40% of the FULL bar width. The width that bar would take if the spacingInner
would be set to 0. Now the white space takes up 40% of that area and the bar takes up 60%. The same goes for spacingOuter
. Now we set the distance from the left and right border to 10% of the original bar chart width. We also injected Gradient
component which is literally the same as in Area chart:
As I mentioned when we were summing up props at the end of the Area chart part, we will now deal with the yAccessor
. But first, let me explain how to create data, which will let us assign different colors to 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 must 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 the sake of our example, let’s say it will be five:
yAccessor
will let us iterate over the chosen key. In this case, it will be the value. Now the svg prop will be taken automatically from each object. We will not pass it to the BarChart
component then.
Look for the props we pass. spacingOuter
wasn’t really necessary, so we removed it. The same is true for svg
. We don’t need it here, because each bar has its own svg object, and the chart will now take it from the objects.
The result looks like this:
We can now make a better definition for yAccessor
:
yAccessor
- we pass it a function that tells us - which key in the object array should be taken as a value to be displayed on the chart. In other words, we pass the object key the chart should iterate at. Another thing is that thanks to it, the chart iterating over the object’s array, can take other properties of the object (bar) and inject them into a specific bar.Sounds logical? I hope so.
Now, if the svg objects have a lot of properties to use, let’s have a bit of fun and create something unusual. Let me just remind you that the full list of svg
object properties is available HERE .
First please take a look at what we want to achieve:
It’s easier than you might expect. In fact, we don’t need to do a thing with the previously used BarChart
component (I just made the 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 expected effect:
What just happened?
In fact not much. We just added a few properties to the svg
objects:
fill
- background color of each bar. We set it as transparent because… it should be transparent.stroke
- this property is the borderline color.strokeWidth
- the borderline widthstrokeDasharray
- we use this only when we want to make our line dashed. This property gets an array with two numbers. The first one informs the chart about hte length of pieces of our borderline. The second one represents the length of spaces between them.Of course, you can get even more creative and create even more interesting examples using svg
possibilities.
For now, we will leave styling be, and focus on simple logic. We want to color our bars depending on the score or grade. Let’s stick 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 instead.
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’re putting together right now will be typed by us.
Here is it:
Like we can see, this function takes a number(value) as an argument and returns the prepared object. fill
property, is required because we always want to color our bar. But depending on the score, sometimes we want to give the bar a borderline. That’s why properties border
and borderWidth
are optional.
We depend on simple conditions:
else
)Now we can use this function and create the chart:
Using the map, we iterate over each value and transform it to the required object. When it’s done, we assign a new array of objects to the dataWithPickedColors
variable. The last step is simple - just pass it to the data prop. Here is the result:
Of course, you can make much more complicated functions and examples. In fact, you can do basically anything that you need at a particular moment.
Until now, we’ve made few examples with classic BarChart
. Another prop I want you to become acquainted 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 by 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}
.
There is nothing more to talk about here. It can be very useful, but it’s also super easy.
The rule is exactly the same as with Stacked Area Chart .
First, we need to create an array of objects with particular keys:
Next, arrays with colors and keys:
And pass them to proper props in the StackedBarChart
component:
Let’s summarize props we already used in Bar charts:
data
- an array of arbitrary data. It can be an array of numbers or objects.style
- a well known line-style prop. In this case, it’s a style for the chart CONTAINER - not the chart itself. Height is set at default 0, so we need to pass the expected height by ourselves. Always. Here we can treat the container not as a box, but more like a canvas, to write on. If we did not set the height, there is nothing we can put the chart on.svg
- a style-prop for the chart. It can take several properties. A full list is available HEREgridMin
- minimal visible chart value. By default, it’s set at the minimal value of the data. We can set the value by ourselves too, but if we set it at 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 to 0, then the system will set it to -20. But if we set it at -40, then the system will set it to -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 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 border and the 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 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 by 90 degrees.We can use also:
xAccessor
- thanks to this function, we can provide a more complicated data structure and choose the value we want to use from the keys in the objects array (used for axis X) - we will use this prop later for other charts, so you will get familiar with ityScale
- a function that determines the scale of axis Y. As said in the documentation it hasn’t been very well testedxScale
- a function that determines the scale of axis X. As said in the documentation it hasn’t been very well testedxMin
- the minimal visible value of axis X. Not really handy if you want to use all the available space to show data. Let’s imagine your data starts from 0. If you set it at -10, then you will get nothing more but an empty white space on the left side. If you set it to 10, then part of your data will not be visible. Mobile devices are usually narrow. I recommend using the available space to the maximum, to increase readabilityxMax
- the maximal visible value of axis X. The same situation as with xMinyMin
- the minimal visible value of axis Y. We can get the same effect using gridMinyMax
- the maximal visible value of axis Y. We can get the same effect using gridMannumberOfTicks
- number of lines visible on the background grid (of course only when we use an 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
)
The line chart is very straightforward, which is probably its greatest advantage. We can put many different lines on the chart, and it will still remain 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 our options :)
We already know most of the props that we have at our disposal. If you have some doubts, please check the summary section again. Our first Line Chart is a basic variant just with the Grid. Let’s import it from the react-native-svg-charts, add required props, and take a look at the result:
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.
Let’s add the shadow to our line. In order to do that we need to add another additional component - Shadow
.
Shadow
- this additional component lets us add the shadow to the Line chart. In fact, it’s another line made to look like a shadow.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.
Like I said before, Shadow
is a line. That’s how it’s built:
Once again we had to face the lexical scope of the chart component. Fortunately, we already know how to handle. 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 . So… what’s new?
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.
In this example, we will add Grid
and Gradient
components, and round the chart angles. Also, we will make the line a little wider to make the gradient more visible. Like I’ve said already, the stroke
property is responsible for color, so we have to inject url(#gradient)
there.