React Recharts Dynamic charts - lines not sharing x-axis values - reactjs

I am trying to build a chart in react with Recharts. The lines are not sharing the x-axis values and overlapping... I want the two charts to share the x-axis values like this: https://recharts.org/en-US/examples/SimpleLineChart
My data comes dynamically from an API call
Have created a sandbox here:
https://codesandbox.io/s/rechart-stackoverflow-forked-lucfl?file=/src/BarGraph.js
Code:
import React, { Component } from "react";
import {
BarChart,
Bar,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
Legend,
LineChart,
Line
} from "recharts";
import _ from "underscore";
class BarGraph extends Component {
state = {
channels: [],
data: []
};
componentDidMount() {
let data = {
channels: ["219180924-2", "219180924-1"],
data: [
{ period: 10, "219180924-2": 0 },
{ period: 11, "219180924-2": 0 },
{ period: 12, "219180924-2": 0 },
{ period: 13, "219180924-2": 0 },
{ period: 14, "219180924-2": 0 },
{ period: 15, "219180924-2": 0 },
{ period: 16, "219180924-2": 0.01 },
{ period: 17, "219180924-2": 0.33 },
{ period: 18, "219180924-2": 0.14 },
{ period: 19, "219180924-2": 0.22 },
{ period: 20, "219180924-2": 0.69 },
{ period: 10, "219180924-1": 0.12 },
{ period: 11, "219180924-1": 0.19 },
{ period: 12, "219180924-1": 0.2 },
{ period: 13, "219180924-1": 0.22 },
{ period: 14, "219180924-1": 0.29 },
{ period: 15, "219180924-1": 1.51 },
{ period: 16, "219180924-1": 0.03 },
{ period: 17, "219180924-1": 0 },
{ period: 18, "219180924-1": 0 },
{ period: 19, "219180924-1": 0 },
{ period: 20, "219180924-1": 0 }
]
};
this.setState({
channels: data.channels,
data: data.data
});
}
render() {
return (
<LineChart
width={600}
height={300}
data={this.state.data}
margin={{ top: 5, right: 30, left: 20, bottom: 5 }}
>
<CartesianGrid strokeDasharray="1 " />
<XAxis dataKey={'period'}/>
<YAxis />
<Tooltip />
<Legend />
{this.state.channels.map((channel) => (
<Line dataKey={channel} />
))}
</LineChart>
);
}
}
export default BarGraph;

actually have resolved with
<XAxis dataKey={'period'} allowDuplicatedCategory={false}/>

Related

Cannot find a way to correctly use chartjs annotation plugin with react

I am currently trying to use the plugin chartjs-plugin-annotation in my react project.
Unfortunately, it is not working...
He is my implementation :
import React, { Component } from "react";
//import "./css/tideComponent.css";
import jsonData from "./ressources/tideOostende2023.json";
import "chart.js/auto";
import { Chart } from "react-chartjs-2";
import * as ChartAnnotation from "chartjs-plugin-annotation";
class Tide extends Component {
state = {
dayDate: new Date().toJSON().slice(5, 10),
highTide: "",
highTide2: "",
lowTide: "",
lowTide2: "",
};
async componentDidMount() {
const index = jsonData.findIndex(
(item) => item.date === this.state.dayDate
);
//TODO store tide in an array(using split method) & filter low to high to have a correct graph
this.setState({
highTide: jsonData[index].highTide,
highTide2: jsonData[index].highTide2,
lowTide: jsonData[index].lowTide,
lowTide2: jsonData[index].lowTide2,
});
}
timeToNumeric(tideTime) {
const tideTimeSplitted = tideTime.split(":");
return tideTimeSplitted[0] * 1 + tideTimeSplitted[1] / 60;
}
handleTideData() {
if (
this.timeToNumeric(this.state.highTide) <
this.timeToNumeric(this.state.lowTide)
)
return [
{ x: -2, y: 0.5 },
{ x: this.timeToNumeric(this.state.highTide), y: 1.5 },
{ x: this.timeToNumeric(this.state.lowTide), y: 0.5 },
{ x: this.timeToNumeric(this.state.highTide2), y: 1.5 },
{ x: this.timeToNumeric(this.state.lowTide2), y: 0.5 },
{ x: 26, y: 1.5 },
];
return [
{ x: -2, y: 1.5 },
{ x: this.timeToNumeric(this.state.lowTide), y: 0.5 },
{ x: this.timeToNumeric(this.state.highTide), y: 1.5 },
{ x: this.timeToNumeric(this.state.lowTide2), y: 0.5 },
{ x: this.timeToNumeric(this.state.highTide2), y: 1.5 },
{ x: 26, y: 0.5 },
];
}
render() {
const data = {
datasets: [
{
data: this.handleTideData(),
fill: false,
backgroundColor: "rgb(35, 71, 89, 0.88)",
borderColor: " rgb(35, 71, 79, 0.88)",
tension: 0.4,
},
],
};
const options = {
annotation: {
annotations: [
{
type: "line",
mode: "horizontal",
scaleID: "x",
value: 1,
borderColor: "white",
borderWidth: 2,
},
],
},
scales: {
x: { min: 0, max: 24, ticks: { stepSize: 1 } },
y: { min: 0, max: 2.2, display: false },
},
showLine: true,
pointStyle: false,
plugins: {
legend: { display: false },
},
};
return (
<div className="tideContainer">
<Chart
type="scatter"
data={data}
options={options}
plugins={ChartAnnotation}
/>
</div>
);
}
}
export default Tide;`
I tried different things but still not working. I also reviewed multiple question on SO but cannot find my solution. Chart Js is correctly working with my implementation, it is only the plugin that does not work.
Thank you in advance for your great help !!!
I think plugins property in react-chartjs-2 should be an array, I guess.
<Chart
type="scatter"
data={data}
options={options}
plugins={[ChartAnnotation]}
/>
The options config for annotation plugin is not in the right node.
It must be added in options.plugins node.
const options = {
plugins: { // <-- to add, was missing
annotation: {
annotations: [
{
type: "line",
mode: "horizontal",
scaleID: "x",
value: 1,
borderColor: "white",
borderWidth: 2,
},
],
},
}

How can I add padding bottom after the x-axis label using apexchart

I am having this Apex chart in my react app ,
What I want to do is add more space between the x-axis label which is the month labels and the series name below it (Session Duration, Page Views, Total Visits). How can I achieve that
This is my code below
............................................................................................................................
class ApexChart extends React.Component {
constructor(props) {
super(props);
this.state = {
series: [{
name: "Session Duration",
data: [45, 52, 38, 24, 33, 26, 21, 20, 6, 8, 15, 10]
},
{
name: "Page Views",
data: [35, 41, 62, 42, 13, 18, 29, 37, 36, 51, 32, 35]
},
{
name: 'Total Visits',
data: [87, 57, 74, 99, 75, 38, 62, 47, 82, 56, 45, 47]
}
],
options: {
chart: {
height: 350,
type: 'line',
zoom: {
enabled: false
},
},
dataLabels: {
enabled: false
},
stroke: {
width: [5, 7, 5],
curve: 'straight',
dashArray: [0, 8, 5]
},
title: {
text: 'Page Statistics',
align: 'left'
},
legend: {
tooltipHoverFormatter: function(val, opts) {
return val + ' - ' + opts.w.globals.series[opts.seriesIndex][opts.dataPointIndex] + ''
}
},
markers: {
size: 0,
hover: {
sizeOffset: 6
}
},
xaxis: {
categories: ['01 Jan', '02 Jan', '03 Jan', '04 Jan', '05 Jan', '06 Jan', '07 Jan', '08 Jan', '09 Jan',
'10 Jan', '11 Jan', '12 Jan'
],
},
tooltip: {
y: [
{
title: {
formatter: function (val) {
return val + " (mins)"
}
}
},
{
title: {
formatter: function (val) {
return val + " per session"
}
}
},
{
title: {
formatter: function (val) {
return val;
}
}
}
]
},
grid: {
borderColor: '#f1f1f1',
}
},
};
}
render() {
return (
<div id="chart">
<ReactApexChart options={this.state.options} series={this.state.series} type="line" height={350} />
</div>
);
}
}
Based on some fiddling around with the Appchart demo, found 2 options that seem to provide result here.
Both use the legend key inside options, which you have in your code
You can add specific height to the legend container
legend: {
height: 100
}
This will allow you to add margin to each legend.
legend: {
itemMargin: {
horizontal: 20
}
}
Hopefully someone with more experience with AppChart can provide a better solution but till then you can look into these.

Add a custom style to victory chart bar

I want to create a custom bar chart with Victory like this:
How can I add a horizontal line in the graph every 10%?
This is my sample code:
const data = [
{ day: 1, data: 0 },
{ day: 2, data: 1 },
{ day: 3, data: 2 },
{ day: 4, data: 2 },
{ day: 5, data: 0 },
];
const BarChart = () => {
return (
<VictoryChart domainPadding={20} theme={VictoryTheme.material}>
<VictoryAxis
tickFormat={(x) => `${x.toFixed(0)}`}
style={{
grid: { stroke: "none" },
ticks: { size: 0 },
}}
/>
<VictoryAxis
dependentAxis
tickFormat={(x) => `${x}`}
style={{
grid: { stroke: "none" },
ticks: { size: 0 },
}}
/>
<VictoryStack>
<VictoryBar data={data} style={{ data: { fill: '#379F4B' } }} x="day" y="data" />
</VictoryStack>
</VictoryChart>
);
};
Have you tried to use tickValues? Example:
<VictoryAxis dependentAxis
tickValues={[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]}
...other stuff...
/>

React Recharts - dynamic line chart only showing data for one line

I have a sample chart here:
https://codesandbox.io/s/rechart-stackoverflow-forked-ev1tt?file=/src/BarGraph.js
It is a dynamically created line chart (dynamic number of lines) but the tooltip is only showing the data for one of the lines.
Am wondering how to get the other dynamically created lines' data in the tooltip...
Code:
import React, { Component } from "react";
import {
BarChart,
Bar,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
Legend,
LineChart,
Line
} from "recharts";
import _ from "underscore";
class BarGraph extends Component {
state = {
channels: [],
data: []
};
componentDidMount() {
let data = {
channels: ["219180924-2", "219180924-1"],
data: [
{ period: 10, "219180924-2": 0 },
{ period: 11, "219180924-2": 0 },
{ period: 12, "219180924-2": 0 },
{ period: 13, "219180924-2": 0 },
{ period: 14, "219180924-2": 0 },
{ period: 15, "219180924-2": 0 },
{ period: 16, "219180924-2": 0.01 },
{ period: 17, "219180924-2": 0.33 },
{ period: 18, "219180924-2": 0.14 },
{ period: 19, "219180924-2": 0.22 },
{ period: 20, "219180924-2": 0.69 },
{ period: 10, "219180924-1": 0.12 },
{ period: 11, "219180924-1": 0.19 },
{ period: 12, "219180924-1": 0.2 },
{ period: 13, "219180924-1": 0.22 },
{ period: 14, "219180924-1": 0.29 },
{ period: 15, "219180924-1": 1.51 },
{ period: 16, "219180924-1": 0.03 },
{ period: 17, "219180924-1": 0 },
{ period: 18, "219180924-1": 0 },
{ period: 19, "219180924-1": 0 },
{ period: 20, "219180924-1": 0 }
]
};
this.setState({
channels: data.channels,
data: data.data
});
}
render() {
return (
<LineChart
width={600}
height={300}
data={this.state.data}
margin={{ top: 5, right: 30, left: 20, bottom: 5 }}
>
<CartesianGrid strokeDasharray="1 " />
<XAxis dataKey={"period"} allowDuplicatedCategory={false} />
<YAxis />
<Tooltip />
<Legend />
{this.state.channels.map((channel) => (
<Line dataKey={channel} name={channel} strokeWidth={2} />
))}
</LineChart>
);
}
}
export default BarGraph;

how to create Biaxial LineChart using .map function in recharts

so basically i have this data:
const bodyWeightAndFatData = [
{
name: 'salim',
style:'#57c0e8',
category:'Body Weight',
data: [
{ day: 23, value: 100 },
{ day: 24, value: 101 },
{ day: 25, value: 104 },
{ day: 26, value: 107 },
{ day: 27, value: 108 },
{ day: 28, value: 105 },
{ day: 29, value: 106 },
{ day: 30, value: 107 },
{ day: 31, value: 107 },
],
},
{
name: 'salim',
style:'pink',
category:'Fat Percentage',
data: [
{ day: 23, value: 134 },
{ day: 24, value: 135 },
{ day: 25, value: 131 },
{ day: 26, value: 133 },
{ day: 27, value: 137 },
{ day: 28, value: 131 },
{ day: 29, value: 130 },
{ day: 30, value: 139 },
{ day: 31, value: 138 },
],
},
];
coming from one component. and i'm drawing a rechart from another component like this:
<div className={styles.outer}>
<div className={styles.inner}>
<p className={styles.title}>Average Measurments</p>
<ResponsiveContainer width="95%" height={300}>
<LineChart >
<CartesianGrid strokeDasharray="5 0" vertical={false} tickSize={10} padding={{ left: 20 }}/>
<XAxis yAxisId="right" tickLine={false} axisLine={false} dataKey="day" allowDuplicatedCategory={false} />
<YAxis tickCount={5} axisLine={false} dx={-15} dataKey="value"/>
<Tooltip/>
<Legend
layout="horizontal" verticalAlign="top" align="center"
payload={
props.data.map(
item => ({
type: "circle",
id: item.name,
color: item.style,
value: `${item.category}`
})
)
}/>
{props.data.map(s => (
<Line dataKey="value" data={s.data} name={s.name} key={s.category} stroke={s.style}/>
))}
</LineChart>
</ResponsiveContainer>
</div>
</div>
the result is working great its drawing the data and everything, but what i'm stuck on is that i need two Y axis to be shown instead of just one which is present. i have looked it up but i don't know how to create it using .map can anyone help?
Here is how I did it.
const bodyWeightAndFatData = [
{
name: 'salim',
style:'#57c0e8',
category:'Body Weight',
data: [
{ day: 23, value: 100 },
{ day: 24, value: 101 },
{ day: 25, value: 104 },
{ day: 26, value: 107 },
{ day: 27, value: 108 },
{ day: 28, value: 105 },
{ day: 29, value: 106 },
{ day: 30, value: 107 },
{ day: 31, value: 107 },
],
},
{
name: 'salim',
style:'pink',
category:'Fat Percentage',
data: [
{ day: 23, value: 134 },
{ day: 24, value: 135 },
{ day: 25, value: 131 },
{ day: 26, value: 133 },
{ day: 27, value: 137 },
{ day: 28, value: 131 },
{ day: 29, value: 130 },
{ day: 30, value: 139 },
{ day: 31, value: 138 },
],
},
];
export default function App() {
return (
<div >
<div >
<p>Average Measurments</p>
<ResponsiveContainer width="95%" height={300}>
<LineChart >
<CartesianGrid strokeDasharray="5 0" vertical={false} tickSize={10} padding={{ left: 20 }}/>
<XAxis tickLine={false} axisLine={true} dataKey="day" allowDuplicatedCategory={false} />
<YAxis yAxisId="left" tickCount={5} dx={-15} dataKey="value"/>
<YAxis yAxisId="right" orientation="right" tickCount={5} dx={-15} dataKey="value"/>
<Tooltip/>
<Legend
layout="horizontal" verticalAlign="top" align="center"
payload={
bodyWeightAndFatData.map(
item => ({
type: "circle",
id: item.name,
color: item.style,
value: `${item.category}`
})
)
}/>
{bodyWeightAndFatData.map(s => (
<Line yAxisId="left" dataKey="value" data={s.data} name={s.name} key={s.category} stroke={s.style}/>
))}
{bodyWeightAndFatData.map(s => (
<Line yAxisId="right" dataKey="value" data={s.data} name={s.name} key={s.category} stroke={s.style}/>
))}
</LineChart>
</ResponsiveContainer>
</div>
</div>
);
}
Two axis one on left and one on right.

Resources