Displaying in the tooltip each value along the y axis on hover - reactjs

Recently started using Recharts for charting.
Here is the data that comes from the server. They need to display Barchart.
[
{
"channel_number": 1,
"data": [
{
"date": 100000,
"consumption": 1231
},
{
"date": 200000,
"consumption": 1234
},
{
"date": 300000,
"consumption": 1234
}
]
},
{
"channel_number": 2,
"data": [
{
"date": 100000,
"consumption": 800
},
{
"date": 200000,
"consumption": 823
},
{
"date": 300000,
"consumption": 1233
}
]
}
]
I need to display each consumption value on the y-axis. That is, so that when hovering over with the mouse, it shows each value. Like this for example
I get a tooltip where only the total value of consumption is displayed
My code:
<ResponsiveContainer width="100%" height={385}>
<BarChart height={300} data={newBar}>
<CartesianGrid vertical={false} />
<XAxis
height={32}
dataKey="date"
allowDuplicatedCategory={false}
tickFormatter={(tick) => convertTimestampToDate(tick, 'dd.MM')}
angle={90}
tick={{ fontSize: '12px', color: '#626C77' }}
textAnchor="start"
/>
<YAxis tick={{ fontSize: '12px', color: '#626C77' }} />
<Tooltip cursor={false} labelFormatter={() => ''} />
<Legend
align="right"
verticalAlign="top"
iconSize={6}
formatter={(value, entry, index) => (
<span style={{ color: '#969FA8' }}>{value}</span>
)}
wrapperStyle={{ fontSize: '12px', top: -51 }}
payload={data?.channel_consumption.map((item: any, index: any) => ({
id: item.channel_number,
value: `${item.id_channel}`,
color: PIE_COLORS[index],
}))}
/>
{newBar.map((el: any, index: any) => (
<Bar
dataKey="consumption"
data={el.data}
key={el.channel_number}
fill={PIE_COLORS[index]}
barSize={8}
radius={71.5}
></Bar>
))}
</BarChart>
</ResponsiveContainer>
Does anyone have any ideas? How to display each value when hovering over a bar? Probably do something with the coordinates, I can't figure it out

Related

Error in showing the tooltip for Scatter chart (React ApexCharts)

My scatter chart is rendered correctly. I have a problem with the custom tooltip function I have created to show the details of the data points on the chart. When I hover the tooltip, it shows an error as
"Uncaught TypeError: Cannot read properties of undefined "
I get the response data for the selected dates from my server using api call and my chart is rendered accordingly. From the received response I have created a dropdown with all employeeName as options to select. When selecting an employeeName I want to show the data point of that person in the scatter chart. My code is working fine for all these functions. But the problem is with the chart options configured. I have given the property type="numeric" for both the x-axis and y-axis in the options object.
If this type="numeric" property is specified, my chart is working fine when I select individual employees from the dropdown but the tooltip shows the error as I mentioned.
If the type="numeric" property is not specified, my chart does not show the data points correctly when I select the employee name, but the tooltip works fine. When I hover over the tooltip for the shown data points does not throw any error.
Below I have given sample data.
import React, { useState, useEffect } from "react";
import axios from "axios";
import ApexCharts from "react-apexcharts";
import "./styles.css";
const ScatterChart = () => {
const[chartData,setChartData]=useState([]);
const [employeeName, setEmployeeName] = useState("");
const [employeeNames, setEmployeeNames] = useState([]);
const [filteredData, setFilteredData] = useState([]);
const data = [
{
employeeName: "John Doe",
percentageOfTasksCompleted: 35,
percentageOfTasksCompletedInTime: 25
},
{
employeeName: "Jane Doe",
percentageOfTasksCompleted: 45,
percentageOfTasksCompletedInTime: 30
},
{
employeeName: "Bob Smith",
percentageOfTasksCompleted: 55,
percentageOfTasksCompletedInTime: 40
}
];
const newData = data.map((d) => {
return {
x: d.percentageOfTasksCompleted,
y: d.percentageOfTasksCompletedInTime,
employeeName: d.employeeName,
};
});
const employeeNames = [...new Set(newData.map((d) => d.employeeName))];
setEmployeeNames(employeeNames);
setChartData(newData);
};
useEffect(() => {
setFilteredData(
employeeName !== null && employeeName !== ""
? chartData.filter((d) => d.employeeName === employeeName)
: chartData
);
}, [employeeName, employeeNames, chartData]);
const options = {
chart: {
type: "scatter",
toolbar: {
show: true,
tools: {
download: true,
selection: false,
zoom: false,
zoomin: false,
zoomout: false,
pan: false,
reset: false | '<img src="/static/icons/reset.png" width="20">',
customIcons: [],
},
export: {
csv: {
filename: "Scatter plot by supervisor",
columnDelimiter: ",",
headerCategory: "category",
headerValue: "value",
dateFormatter(timestamp) {
return new Date(timestamp).toDateString();
},
},
svg: {
filename: "Scatter plot by supervisor",
},
png: {
filename: "Scatter plot by supervisor",
},
},
},
},
xaxis: {
title: {
text: "Percentage of Tasks Completed",
align: "center",
verticalAlign: "top",
floating: true,
offsetY: 100,
style: {
fontSize: "14px",
fontWeight: "bold",
color: "#666",
},
},
tickAmount: 6,
min: 0,
max: 100,
type: "numeric",
},
yaxis: {
title: {
text: "Percentage of Tasks Completed In Time",
align: "center",
verticalAlign: "top",
floating: true,
offsetX: -5,
style: {
fontSize: "14px",
fontWeight: "bold",
color: "#666",
},
},
tickAmount: 6,
min: 0,
max: 100,
type: "numeric",
},
tooltip: {
custom: function ({ dataPointIndex }) {
return (
'<div class="tooltip">' +
"<p class='employee-name'>Employee Name : " +
filteredData[dataPointIndex].employeeName +
"</p>" +
"<p class='percentage-complete'>Percentage of Tasks Completed : " +
filteredData[dataPointIndex].x +
"%</p>" +
"<p class='percentage-in-time'>Percentage of Tasks Completed In Time : " +
filteredData[dataPointIndex].y +
"%</p>" +
"</div>"
);
},
},
};
return (
<div>
<div style={{ display: "flex", alignItems: "center", padding: "10px" }}>
<input
type="date"
value={fromDate}
onChange={(e) => setFromDate(e.target.value)}
style={{ marginRight: "10px", padding: "5px" }}
/>
<input
type="date"
value={toDate}
onChange={(e) => setToDate(e.target.value)}
style={{ marginRight: "10px", padding: "5px" }}
/>
<select
id="employee-name"
value={employeeName}
onChange={(e) => setEmployeeName(e.target.value)}
style={{ marginRight: "10px", padding: "5px" }}
>
<option value="">All</option>
{employeeNames.map((name) => (
<option key={name} value={name}>
{name}
</option>
))}
</select>
<button
onClick={() => {
handleRefresh();
setEmployeeName("");
}}
style={{ padding: "5px 10px" }}
>
Refresh
</button>
</div>
{filteredData !== undefined && filteredData !== null ? (
<ApexCharts
options={options}
series={[{ data: filteredData }]}
type="scatter"
width="600"
height="500"
/>
) : null}
</div>
);
};
export default ScatterChart;

how to use if-else inside the map return react js

Code:-
{comments.map((comment) => {
//Display Hex to base64 image format
const base64 = Buffer.from(comment.Thumbnail, 'hex').toString('base64');
//console.log(base64);
return (
<tr key={comment.SlugName} ref={tbodyRef} tabIndex={0} className="border_bottom" onKeyDown={(e) => handleKeyDown(e, comment.idx)}>
<td style={{ color: "white", width: "200px" }}>
<img src={`data:image/jpeg;base64,${base64}`} alt="Clip Thumbnail" width="100%" />
</td>
<td style={{ color: "white", width: "440px" }}>{comment.ClipName}</td>
<td style={{ color: "white", width: "250px" }}>{comment.SlugName}</td>
<td style={{ color: "white", width: "250px" }}>{comment.ChannelName}</td>
<td style={{ color: "white", width: "140px" }}>
{
if (comment.Status === 1) {
<button type="submit">Play</button>
} else if(comment.Status === 2){
console.log(comment.Status);
} else if(comment.Status === 3){
console.log(comment.Status);
} else{
console.log(comment.Status);
}
}
</td>
<td style={{ color: "white" }}>
{comment.Mode === true ? <RiArrowLeftRightFill style={{ color: "white" }} /> : <RiArrowLeftRightFill style={{ color: "#363c44" }} />}
</td>
<td style={{ color: "white" }}>{comment.StartTime}</td>
<td style={{ color: "white" }}>{comment.Duration}</td>
</tr>
)
}
I want when comment. Status is 1 it displays a button in a webpage as a comment. Status is 2 also displays a button with name cue as goes on with comment. Status 3,4
how can I display the btn with comment status 1,2,3
API:-
[
{
"ClipName": "Evernote Hacked, Time t_STRA005R",
"Status": 1,
"ChannelName": "News Hindi",
"Mode": false,
"StartTime": "00:00:00:00",
"Duration": "00:00:06:11",
"idx": 0,
"Thumbnail": "9e728a2800a28a2800a28a2800add3d6b0aa7fb6dc7fcf4ffc745006b8a5158ff6db145145001451450014514500145145001451450014514500145145001451450014514500145145007fffd9",
"SlugName": "EU 'growth boost from US trade deal'"
},
{
"ClipName": "U.S. releases $250 mill_STRA005S",
"Status": 2,
"ChannelName": "News Hindi",
"Mode": false,
"StartTime": "00:00:00:00",
"Duration": "00:00:32:16",
"idx": 1,
"Thumbnail": "9e728a2800a28a2800a28a2800add3d6b0aa7fb6dc7fcf4ffc745006b8a5158ff6db145145001451450014514500145145001451450014514500145145001451450014514500145145007fffd9",
"SlugName": "Liverpool FC continues to make losses"
},
{
"ClipName": "SpaceX-2 Mission Launch_STRA005T",
"Status": 3,
"ChannelName": "News Hindi",
"Mode": false,
"StartTime": "00:00:00:00",
"Duration": "00:04:20:04",
"idx": 2,
"Thumbnail": "9e728a2800a28a2800a28a2800add3d6b0aa7fb6dc7fcf4ffc745006b8a5158ff6db145145001451450014514500145145001451450014514500145145001451450014514500145145007fffd9",
"SlugName": "Latvia applies to enter eurozone"
}
]
I want when comment. Status is 1 it displays a button in a webpage as a comment. Status is 2 also displays a button with name cue as goes on with comment. Status 3,4
how can I display the btn with comment status 1,2,3
You could create a function that uses a switch statement and return your output from that:
<div>
{data.map(({ status }) => {
const statusContent = () => {
if (status === 1) {
return <button>Option 1</button>;
} else if (status === 2) {
return <button>Option 2</button>;
} else if (status === 3) {
return <button>Option 3</button>;
} else {
return <button>Option 4</button>;
}
};
return <div>{statusContent()}</div>;
})}
</div>
Ideally, within JSX it's "cleaner" to a ternary operator. But in situations like this where there are multiple conditions, this would work fine.

How to create Histogram with grouped data in Victory (ReactJS)?

I'm trying to create a histogram with Value, Id and Group code. I need to group the Ids based on the group code and put the labels on top. I'm also trying to add a horizontal scroll bar. Can you help me with this?
I tried to do like in this picture but I couldn't.
My data is in the form of this object
{
id: 1,
value: 0.16882,
group_id: 'group_1',
fill: 'red',
}
const App = () => {
const sharedAxisStyles = {
tickLabels: {
fontSize: 10
},
axisLabel: {
padding: 39,
fontSize: 12,
},
grid: {
stroke: "#546E7A",
strokeWidth: 0.1,
}
};
return (
<VictoryChart
domainPadding={{
x: 20,
}}
containerComponent={(
<VictoryZoomContainer
allowZoom={false}
zoomDomain={{
x: [0, 22],
}}
/>
)}
>
<VictoryLabel
x={225}
y={30}
textAnchor="middle"
text="Group code"
/>
<VictoryBar
data={data}
x={(x) => `id_${x.id}`}
y="value"
barWidth={15.8}
style={{
data: {
fill: ({datum}) => datum.fill,
}
}}
/>
<VictoryAxis
tickCount={22}
tickLabelComponent={<VictoryLabel
angle={-90}
textAnchor="end"
style={[
{ fontSize: 3, fontWeight: 'bold', fill: '#78909C' },
]}
/>}
/>
<VictoryAxis
dependentAxis
label="Value"
tickFormat={(t) => {
return (
(t).toFixed(2)
);
}}
style={sharedAxisStyles}
/>
</VictoryChart>
);
};
When I write these codes, the output I get is like this:
you will need to use VictoryGroup : https://formidable.com/open-source/victory/docs/victory-group/
And use labels to add title for each group https://formidable.com/open-source/victory/docs/victory-group/#labels

React, sorting X-axis label in Rechart in from different data sources

I need help figuring how to sort X-Axis label values in ascending order in Rechart graphs.
currently, the data for the chart is gotten from two sources.
Below is the code presented.
const series = [
{ name: 'SourceA: ', data: reportsFromSourceA },
{ name: 'SourceB: ', data: reportsFromSourceB },
]
const selectedCategories= [...]
selectedCategories.map((category, i) => (
<ResponsiveContainer height={350} width='50%' key={category}>
<LineChart
margin={{ top: 40, right: 30, left: 70, bottom: 5 }}
syncId='category'
>
<XAxis dataKey='hour' allowDuplicatedCategory={false} />
<YAxis
label={{
value: category,
position: 'top',
fontSize: 18,
offset: 20,
fontWeight: 'bold',
fill: COLORS[i % 8]
}}
tickFormatter={formatUSD}
/>
<CartesianGrid strokeDasharray='3 3' />
<Tooltip formatter={formatUSD} />
{series.map((s, i) => (
<Line dataKey='rpc' stroke={COLORS[i % 2]} data={s.data[category]} name={s.name} key={s.name} />
))}
<ReferenceArea y2={0} stroke='red' color='red' strokeOpacity={0.5} />
</LineChart>
</ResponsiveContainer>
)))
I had a similar issue, but the solution is to:
first sort out the data coming from your database
or sort the entire array it by key value (in ascending or descending order)
The issue occurs due to some missing entries of the labels in the first data source which the second one has.
The simple solution can be to create an extra data source for labels only and we'll not draw a line for that source.
A relevant sandbox example is here
The full explanation is here
The following solution can solve the issue
const labelSeries = {data: [
{category: 01}, {category: 05}, {category: 09}, {category: 10}, {category: 11},
{category: 12}, {category: 13}, {category: 14},{category: 15}, {category: 16},
{category: 17}, {category: 18}, {category: 19}, {category: 20}, {category: 21},
{category: 22}
]}
const series = [
{ name: 'SourceA: ', data: reportsFromSourceA },
{ name: 'SourceB: ', data: reportsFromSourceB },
]
const selectedCategories= [...]
selectedCategories.map((category, i) => (
<ResponsiveContainer height={350} width='50%' key={category}>
<LineChart
margin={{ top: 40, right: 30, left: 70, bottom: 5 }}
syncId='category'
>
<XAxis dataKey='hour' allowDuplicatedCategory={false} />
<YAxis
label={{
value: category,
position: 'top',
fontSize: 18,
offset: 20,
fontWeight: 'bold',
fill: COLORS[i % 8]
}}
tickFormatter={formatUSD}
/>
<CartesianGrid strokeDasharray='3 3' />
<Tooltip formatter={formatUSD} />
<Line data={labelSeries.data} /> // This line will sort the x-axis label
{series.map((s, i) => (
<Line dataKey='rpc' stroke={COLORS[i % 2]} data={s.data[category]} name={s.name} key={s.name} />
))}
<ReferenceArea y2={0} stroke='red' color='red' strokeOpacity={0.5} />
</LineChart>
</ResponsiveContainer>
)))

Recharts - bar chart dynamic label position

How can I have dynamic label positions of Bars like is showing in the picture?
Here is my code till now
const data = [
{ currency: 'CHF', amount: 3, amountLabel: 3023.00 },
{ currency: 'GBP', amount: 6, amountLabel: 6275.00 },
{ currency: 'USD', amount: 10, amountLabel: 9999.00 },
{ currency: 'EUR', amount: 14, amountLabel: 14819.00 },
{ currency: 'LEK', amount: 24, amountLabel: 24023000.00 },
];
<BarChart
width={430}
height={170}
data={data}
layout="vertical">
<XAxis type="number" orientation="top" stroke="#285A64" />
<YAxis type="category" dataKey="currency" axisLine={false} dx={-5} tickLine={false}
style={{ fill: "#285A64" }} />
<Bar background dataKey="amount" fill="#285A64" barSize={{ height: 26 }}>
<LabelList dataKey="amountLabel" position="insideRight" style={{ fill: "white" }} />
</Bar>
</BarChart>
Find Sample code here jsfiddle
You should implement a React component to be injected into the prop content (LabelList)
For example (JSFiddle):
const {BarChart, Bar, XAxis, YAxis, LabelList} = Recharts;
const data = [
{ currency: 'CHF', amount: 3, amountLabel: 3023.00 },
{ currency: 'GBP', amount: 6, amountLabel: 6275.00 },
{ currency: 'USD', amount: 10, amountLabel: 9999.00 },
{ currency: 'EUR', amount: 14, amountLabel: 14819.00 },
{ currency: 'LEK', amount: 26, amountLabel: 26023000.00 },
];
const renderCustomizedLabel = (props) => {
const {
x, y, width, height, value,
} = props;
const fireOffset = value.toString().length < 5;
const offset = fireOffset ? -40 : 5;
return (
<text x={x + width -offset} y={y + height - 5} fill={fireOffset ? "#285A64" :"#fff"} textAnchor="end">
{value}
</text>
);
};
const VerticalBarChart = React.createClass({
render () {
return (
<BarChart
width={400}
height={170}
data={data}
layout="vertical">
<XAxis type="number" orientation="top" stroke="#285A64"/>
<YAxis type="category" dataKey="currency" axisLine={false} dx={-10} tickLine={false} style={{ fill: "#285A64" }} />
<Bar background dataKey="amount" fill="#285A64" barSize={{ height: 26 }}>
<LabelList dataKey="amountLabel" content={renderCustomizedLabel} position="insideRight" style={{ fill: "white" }} />
</Bar>
</BarChart>
);
}
})
ReactDOM.render(
<VerticalBarChart />,
document.getElementById('container')
);

Resources