Recharts won't automatically calculate YAxis ticks - javascript

I'm trying to add a chart using recharts with the latest exchange rates of some currencies. Data is shown correctly, but the chart always starts at 0 and goes to a bit above the max value.
The chart is correct, however it doesn't need to start at 0, because doing this, it is almost a line.
Here is the picture of the chart:
I'd like that recharts could calculate automatically the ticks, so it would begin a little bit below the minimum value from the data and finish a little bit above the maximum value.
Here is my code:
import React, { useEffect, useState } from "react";
import { StyledCurrencyChart } from "./styles";
import {
AreaChart,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
Area,
ResponsiveContainer
} from "recharts";
import useExchangeRateProvider from "../../hooks/useExchangeRateProvider";
import api from "../../services/api";
import theme from "../../styles/customMuiTheme";
import moment from "moment";
function Chart({ data }) {
return (
<ResponsiveContainer width="100%" height={200}>
<AreaChart
width="100%"
height={250}
data={data}
margin={{ top: 10, right: 30, left: 0, bottom: 0 }}
>
<defs>
<linearGradient id="colorUv" x1="0" y1="0" x2="0" y2="1">
<stop
offset="5%"
stopColor={theme.palette.secondary.main}
stopOpacity={0.8}
/>
<stop
offset="95%"
stopColor={theme.palette.secondary.main}
stopOpacity={0}
/>
</linearGradient>
</defs>
<XAxis
dataKey="date"
tickFormatter={formatDate}
style={{ fill: "#ffffff" }}
/>
<YAxis tickFormatter={formatRate} style={{ fill: "#ffffff" }} />
<CartesianGrid
strokeDasharray="3 3"
fill="rgba(255, 255, 255, 0.3)"
/>
<Tooltip />
<Area
type="monotone"
dataKey="rate"
stroke={theme.palette.secondary.main}
fillOpacity={1}
fill="url(#colorUv)"
/>
</AreaChart>
</ResponsiveContainer>
);
}
// function to format date
function formatDate(tickItem) {
return moment(tickItem).format("MMM Do YY");
}
// function to format rate
function formatRate(tickItem) {
return parseFloat(tickItem).toLocaleString("en-US");
}
export default function CurrencyChart() {
// selected country
const exchangeRateProvider = useExchangeRateProvider();
const country = exchangeRateProvider.state.exchangeRateProvider.country;
// state
const [values, setValues] = useState({
loading: true,
error: false,
data: {}
});
// update chart on country change
useEffect(() => {
async function updateChart() {
try {
const { data } = await api.get(
`/public/rates/history/${country}`
);
setValues({ loading: false, error: false, data });
} catch (e) {
setValues({ loading: false, error: true, data: {} });
}
}
updateChart();
}, [country]);
return (
<StyledCurrencyChart>
<Chart data={values.data} />
</StyledCurrencyChart>
);
}
How can I achieve it? I tried messing around with interval and ticks props under the <YAxis>, but I couldn't make it work.
Thanks in advance

Use the yAxis domain prop:
<YAxis type="number" domain={[0, 1000]}/> // set to whatever you want [yMix, yMax]

For calculating automatically you can use something like these
<YAxis type="number" domain={['dataMin', 'dataMax']} />
<YAxis type="number" domain={[0, 'dataMax']} />
<YAxis type="number" domain={['auto', 'auto']} />
Please make sure to use integer numbers for the values, If you use a string as a value for YAxis it can not recognize the max value correctly.

Related

How to only show one label using Labellist in Recharts?

I am using Recharts and using labellist to add label on top of every stacked bar chart, but instead of only one label for every stacked chart it is creating a label for stack (every stack) and my custom render events looks like:
const renderCustomizedEvent = (props) => {
const { x, y, width, height, value } = props;
const radius = 20;
if (!value) return null;
return (
<g>
<rect
x={x + width / 2 - 30}
y={y - radius - 10}
width="60"
height="20"
style={{ strokeWidth: 3, fill: "#203557" }}
/>
<text
x={x + width / 2}
y={y - radius}
fill="#fff"
textAnchor="middle"
dominantBaseline="middle"
style={{ fontSize: "10px" }}
>
data
</text>
</g>
);
};
and my data looks like:
const data = [
{
Date: "2022-12",
Electricity: 220.129804,
Gas: 90,
Net_Carbon_Impact: 90,
EventType: "Event_Gas"
},
{
Date: "2022-11",
Electricity: 220.129804,
Gas: 0.023072,
Net_Carbon_Impact: 220.15287600000002
}
]
<ResponsiveContainer width={width} height={400}>
<ComposedChart
data={data}
stackOffset="sign"
margin={{ left: 20, bottom: 60 }}
barSize={40}
barCategoryGap={40}
>
<CartesianGrid color="#E1E2E1" vertical={false} />
<XAxis
dataKey="Date"
axisLine={false}
tickLine={false}
scale="band"
tick={customizedGroupTick}
interval={0}
/>
<YAxis
tickLine={false}
color="#E1E2E1"
tickSize={1}
tickCount={uniquelabels.length + 1}
label={{ value: "tCO2-e", angle: -90, position: "insideLeft" }}
tickFormatter={(e) => {
return Math.abs(e) >= 1000000000
? `${e / 1000000000}b`
: Math.abs(e) >= 1000000
? `${e / 1000000}m`
: Math.abs(e) >= 1000
? `${e / 1000}k`
: e;
}}
/>
<Tooltip content={customizedTooltip} cursor={false} />
<Legend
layout="horizontal"
verticalAlign="top"
content={renderLegend}
align="left"
/>
{uniquelabels.map((item: string) => (
<Bar
key={item}
dataKey={item}
stackId="a"
fill={renderColor(item)}
width="30px"
>
<LabelList
position="top"
dataKey="EventType"
content={renderCustomizedEvent}
/>
</Bar>
))}
<Line
strokeWidth={3}
type="monotone"
dataKey="Net_Carbon_Impact"
stroke="#FFE81C"
dot={{ strokeWidth: 8, fill: "#FFE81C" }}
/>
</ComposedChart>
</ResponsiveContainer>
how it looks like now is like the picture attached, and as it is shown in the picture also Jan2023 has two events (Gas and Electricity(is is hidden behind the bar chart)) but i only want one of them which is gas. any help will be appreciate. Thank you in advance

Date is not displayed from props in rechart react

I'm using rechart line chart to display the date, I have the dates as props from the Api and when I try to format it shows no value but the values are shown in the custom tooltip.
I tried to console log the value and it shows no value,I'm not sure why !!
My component is
import React from 'react'
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts';
import moment from 'moment';
import CustomTooltip from './tooltip/CustomTooltip';
const COLORS = ['#0088FE', '#00C49F', '#FFBB28', '#FF8042'];
const CustomLineChart = (props) => {
const formatXAxis = tickItem => {
return moment.unix(Number(tickItem.toString())).format('D MMM');
}
console.log('line', props.data)
const data = props.data
return (
<div style={{ width: '100%', height: 500 }}>
<ResponsiveContainer >
<LineChart
width={700}
height={400}
data={data}
>
<CartesianGrid strokeDasharray="3 3" />
<XAxis padding={{ left: 20 }}
dataKey='time' name='time' tickFormatter={formatXAxis}
onClick={(item) => console.log('insidex', item)}
/>
{/* <YAxis label={{ value: 'Number of Users', angle: -90, position: 'insideLeft' }} /> */}
<YAxis />
<Tooltip wrapperStyle={{ border: 'none', outline: 'none' }} content={<CustomTooltip header={props.datakey[0]} content={props.datakey} />} />
<Legend />
{props.datakey.map((key, index) => {
if (index !== 0) {
return <Line type="monotone" dataKey={key} stroke={COLORS[index]} activeDot={{ r: 8 }} />
}
})}
</LineChart>
</ResponsiveContainer>
</div>
)
}
export default CustomLineChart
my data is something like this :

Recharts - Draw a trend line on top of a barchart

Hi I am creating a barchart using the Recharts library. I am wanting to draw a trend line on top of the barchart like so:
I am using the following to draw the barchart:
<BarChart data={transformedDataByCategory}>
<CartesianGrid strokeDasharray="3 3" vertical={false} />
<XAxis
dataKey="category"
interval={0}
tickLine={false}
tick={(e) => {
const { payload: { value } } = e;
e.fill = theme.colors.onfCategory[value].base;
e.fontSize = '11px';
e.fontWeight = 'bold';
return <ChartText {...e}>{value}</ChartText>;
}}
/>
<YAxis />
<Legend />
<Tooltip cursor={{ fill: '#f1f1f1' }} />
{years.map((year, i) => <>
<Bar key={`year_${i}`} dataKey={year} fill={yearColours[i]}/>
</>)}
</BarChart>
I have tried using the ReferenceLine component to draw on top of the graph but have had no luck. Any help would be great thanks!

Customize ReChart bar chart labels and colors for each Bar

I have a rechart bar chart that I would like to have the Labels like this...
And I want the colors to be like this...
The problem is that I can't seem to get them both at the same time. The second image is the closest I can get but it is bringing in the value instead of the name hence the int(85) instead of string(85%) and it is also not angles.
Here is my code. I commented out the part that allows for angled labels because it wont work when is there..
import { BarChart, Bar, LabelList, Cell } from "recharts";
import { colors } from "../../Colors/colors";
const data = [
{
name: `${85}%`,
uv: 85,
},
{
name: `${95}%`,
uv: 95,
},
{
name: `${80}%`,
uv: 80,
},
];
export default function MyBarChart(): JSX.Element {
return (
<BarChart width={150} height={400} data={data}>
<Bar
dataKey="uv"
fill={colors.blueTheme[0]}
radius={8}
label={{ position: "insideBottom", fill: "black" }}
name="name"
>
{/* <LabelList
dataKey="name"
position="insideBottom"
angle={270}
offset={25}
/> */}
{colors.blueTheme.map((entry, index) => (
<Cell key={`cell-${index}`} fill={colors.blueTheme[index % 20]} />
))}
</Bar>
</BarChart>
);
}
The colors.tsx
export const colors = {
blueTheme: ["#85A5FF", "#ADC6FF", "#D6E4FF"],
};
How can I get the angled labels with the color differences simultaneously?
I figured it out...
<BarChart width={150} height={400} data={data}>
<Bar dataKey="uv" radius={8}>
<LabelList
dataKey="name"
position="insideBottom"
angle={270}
offset={25}
fill="black"
/>
{colors.blueTheme.map((entry, index) => (
<Cell key={`cell-${index}`} fill={colors.blueTheme[index % 20]} />
))}
</Bar>
</BarChart>
If you update the data and add the color each bar needs to have, as follows:
const data = [
{
name: `${85}%`,
uv: 85,
color: "#85A5FF" // you may pass a value directly as string
},
{
name: `${95}%`,
uv: 95,
color: colors.blueTheme[1] // or colors.blueTheme by index
},
{
name: `${80}%`,
uv: 80,
color: colors.blueTheme[getIndex()] // or some custom logic to evaluate index
},
];
You can update the code as follows and it will work:
export default function MyBarChart(): JSX.Element {
return (
<BarChart width={300} height={400} data={data}>
<Bar
dataKey="uv"
fill="#85A5FF"
radius={8}
label={{
position: "insideBottom",
angle: -60,
fill: "black",
offset: 25
}}
>
<LabelList dataKey="name" />
{data.map((entry, index) => (
<Cell fill={entry.color} key={`cell-${index}`} />
))}
</Bar>
</BarChart>
);
}
Working example:
https://codesandbox.io/embed/bar-chart-with-customized-event-forked-4ygf7i?fontsize=14&hidenavigation=1&theme=dark

data.slice is not a function React

im trying to get api data into a chart in react js i was using a local array to use like sample values
now im trying to pass an api data to inside the chart but i get the data.slice is not a function error and i dont know why, someone here can help me?
PS: i call the function inside an use effect hook
function
const getPeso = async () => {
const jwt = sessionStorage.getItem('Token')
const user = jwtDecode(jwt)
const token = sessionStorage.getItem('Token')
console.log(token)
const response = await fetch("http://localhost:8080/animals/animal/client?clientId=" + user.id, {
method: "get",
headers: {
"Authorization": `${token}`,
},
})
const data = await response.json();
setPeso(data)
};
Chart
<div className='pesoGraph'>
<h1>Pesagem</h1>
<a>Mês</a>
<a style={Styles}>Ano</a>
<LineChart
width={650}
height={300}
data={setPeso}
margin={{
top: 20,
right: 50,
left: 50,
bottom: 70
}}
>
<CartesianGrid vertical={false} />
<XAxis dataKey="data" axisLine={false} tickLine={false} tickMargin={10} color={'#494949'} fontWeight={'500'} />
<YAxis dataKey='peso' domain={['dataMin', 'dataMax']} tickCount={4} axisLine={false} tickLine={false} tickMargin={10} color={'#494949'} fontWeight={'500'} />
<Tooltip />
<Line
type="monotone"
dataKey="peso"
stroke="#000000"
activeDot={{ r: 8 }}
/>
</LineChart>
</div>
From this line setPeso(data) it is clear that setPeso(data) is a function.
You are then passing it to the chart component:
<LineChart
width={650}
height={300}
data={setPeso} // <-- here
Based on the error message the chart component is expecting an array as data.
Your code should be something like
const [peso, setPeso] = useState([]);
// ... other code
<LineChart
width={650}
height={300}
data={peso}
where peso is an array in state.

Categories