I am trying to map the data I get back from an API in this format:
data={[
{ x: 0, y: 0 },
{ x: 1, y: 1 },
{ x: 2, y: 2 },
{ x: 3, y: 3 },
{ x: 4, y: 4 },
]}
I have a get call then I map each of the items to give me an x , y value:
getCryptoChartData('histohour', selectedCrypto, 24, 1).then(
cryptoChartData => {
//const response = cryptoChartData.Data.map(item => item.close);
const data = cryptoChartData.Data.map(item => {
[
{
x: item.time,
y: item.close,
},
];
});
return this.setState({cryptoChartData: data});
},
);
However, I notice that the data array is set to undefined:
<SlideAreaChart
data={this.state.cryptoChartData}
/>
Am I setting the data array correctly with the mapping?
Yes, it seems the problem is in mapping. You just forget to return the generated object:
const data = cryptoChartData.Data.map(item => {
return {
x: item.time,
y: item.close,
};
});
or
const data = cryptoChartData.Data.map(item => ({
x: item.time,
y: item.close,
}));
Final code of getCryptoChartData method will look like:
getCryptoChartData('histohour', selectedCrypto, 24, 1)
.then(cryptoChartData => {
const data = cryptoChartData.Data.map(item => ({
x: item.time,
y: item.close,
}));
this.setState({ cryptoChartData: data });
});
Related
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,
},
],
},
}
In a react-chartjs-2 bar chart: How do I customize all the information shown inside the tooltip when hovering over a bar?
I would expect something like data.datasets[x].tooltip.callback to be available, but I can't find anything useful/working.
Note: I prefer a more generalized answer over a very specific answer to the concrete situation I'm describing below. This would probably be more useful for other readers.
Concrete Situation
I'm plotting data in a bar graph.
X values are given as timestamps (milliseconds). Y values are numbers representing a percentage. Example:
data = [
{ x: timestamp(2022, 1, 1, 1, 15), y: 1 },
{ x: timestamp(2022, 1, 1, 1, 30), y: 2 },
// ...
]
X-axis ticks are formatted as 1:15, 1:30, ...
Y-axis ticks are formatted as 0 %, 0.5 %, 1%, ....
Problem
When I hover over a bar, it will show:
The timestamp in milliseconds
The label of the data
I want the tooltip to show:
The formatted version of the timestamp (like 1:15).
The formatted version of the y-value (like 2%).
No label at all
Complete Code of React Component
function timestamp(year: number, month: number, day: number, hour: number, minute: number) {
const timestamp = new Date(year, month - 1, day, hour, minute).valueOf();
return timestamp;
}
export const TimeGraph: React.FC = () => {
const data = [
{ x: timestamp(2022, 1, 1, 1, 15), y: 1 },
{ x: timestamp(2022, 1, 1, 1, 30), y: 2 },
{ x: timestamp(2022, 1, 1, 1, 45), y: 3 },
{ x: timestamp(2022, 1, 1, 2, 0), y: 4 },
{ x: timestamp(2022, 1, 1, 2, 15), y: 2 },
];
const xValues = data.map((value: any) => {
return value.x;
});
const yValues = data.map((value: any) => {
return value.y;
});
const options = {
scales: {
x: {
grid: {
display: false,
},
ticks: {
callback: (index: any) => {
const date = new Date(xValues[index]);
return date.getHours() + ':' + date.getMinutes();
},
},
},
yAxes: {
grid: {
display: false,
},
ticks: {
callback: (value: any) => {
return value + ' %';
},
},
},
},
plugins: {
legend: {
position: 'top' as const,
},
title: {
display: false,
},
},
};
const chartData = {
labels: xValues,
datasets: [
{
label: 'TODO: remove',
data: yValues,
},
],
};
return (
<>
<Bar options={options} data={chartData} height={150} />
</>
);
};
Answer for chart.js 3 (which is used by react-chartjs-2)
You can customize the tooltip via options.plugins.tooltip.callbacks (Reference)
const options = {
plugins: {
tooltip: {
callbacks: {
title: (xDatapoint) => {return formatXValue(xDatapoint.raw)},
label: (yDatapoint) => {return formatYValue(yDatapoint.raw)},
}
}
},
}
Note:
This will customize all tooltips for all datasets.
Take a look here if you'd like to use a completely customized tool tip
Side note: Remove label on top of diagram
This was not part of the question, but it showed up in the screenshot:
options.plugins.legend.display: false disables the legend.
I'd like to know how i can update object in array.
I asked this question before,
and I got the hint at the moment but i can't still figure it out how to update x and y ,
so here is my piece code :
const [data, setdata] = useState([
{ x: 1, y: 2 },
{ x: 1, y: 2 },
{ x: 1, y: 2 },
]);
const x= [3, 4, 5, 6, 7, 8, 9];
const y =[ 1,2,3,4,6,7];
const updateX = () => {
setdata((data) => data.map((d, i) => ({ ...d, x: newData[i] })));
setdata((data) => data.map((d, i) => ({ ...d, y: newData[i] })))
};
/////result ///
{ x: 3, y: 2 },
{ x: 4, y: 2 },
{ x: 5, y: 2 },
/// what i want ///
{ x: 3, y: 1 },
{ x: 4, y: 2 },
{ x: 5, y: 3 },
{ x: 6, y: 4 },
{ x: 7, y: 5 },
{ x: 8, y: 6 },
{ x: 9, y: 7 },
I don't quite understand why you are initializing the data object with those values.
The result you want, you can't get it by iterating the data object that you have initialized with 3 values.
Assuming that the arrays have these values and an equal length, you can try this:
const [data, setdata] = useState([
{ x: 1, y: 2 },
{ x: 1, y: 2 },
{ x: 1, y: 2 }
]);
const x = [3, 4, 5, 6, 7, 8, 9];
const y = [1, 2, 3, 4, 5, 6, 7];
const newData = x.reduce((acc, xVal, index) => {
const obj = { x: xVal, y: y[index] };
acc.push(obj);
return acc;
}, []);
setdata(newData)
I'd like to know how i can add object in array length.
I asked this question before,
and I got the hint at the moment but i can't still figure it out how to do it ,
so here is my piece code :
const [data, setdata] = useState([
{ x: 1, y: 2 },
{ x: 1, y: 2 },
{ x: 1, y: 2 },
]);
const newData = [3, 4, 5, 6, 7, 8, 9];
const updateX = () => {
setdata((data) => data.map((d, i) => ({ ...d, x: newData[i] })));
};
/////result ///
{ x: 3, y: 2 },
{ x: 4, y: 2 },
{ x: 5, y: 2 },
/// what i want ///
{ x: 3, y: 2 },
{ x: 4, y: 2 },
{ x: 5, y: 2 },
{ x: 6, y: 2 },
{ x: 7, y: 2 },
{ x: 8, y: 2 },
{ x: 9, y: 2 },
The problem here is that you are mapping over data which only has 3 elements. Therefore, the final result will only have 3 elements.
To create a new array from newData, then you must use newData.map() instead of data.map(). The simplest way would be to do it directly:
newData.map(item => {x: item, y: 2})
You can update like this:
const updateX = () => {
setdata(newData.map((item, i) => ({ x: item, y: data[i] ?? 2 })));
};
I'm relatively new to mongoose and nodejs. And i'm trying to hackup a quick server side script in nodejs.
I'm trying to retrieve data as array of objects from mongoDb using mongoose.
Here is what my Schema looks like -
var heatmapSchema = new Schema({
vuid: String
coordinates: [
{
x: Number,
y: Number,
c: Number,
timestamp: Number
}
]
}, {collection: collectionName} );
As you can see coordinates is an array of objects. I want to query mongoDb so I get an array of these coordinate objects, where c = 1 (c property in coordinate equals 1) i.e. -
[
{
x: 100,
y: 230,
c: 1,
timestamp: 1233312312
},
{
x: 120,
y: 240,
c: 1,
t: 1233313425
}
......
]
What would be the best way to achieve this in mongoose?
UPDATE
The closest I have gotten so far is using the below query -
heatmapModel.aggregate(
[
{
$unwind: '$coordinates'
},
{
$match: {
'coordinates.c': 1
}
},
{
$project: {
'_id': 0,
'coordinates.x': 1,
'coordinates.y': 1,
'coordinates.c': 1,
'coordinates.timestamp': 1
}
}
],
function (err, result) {
if (err) {
console.log(err);
process.exit(1);
}
console.log(result);
process.exit();
}
);
Which gives me the following output -
[ { coordinates: { x: 601, y: 165, c: 1, timestamp: 1438840800424 } },
{ coordinates: { x: 484, y: 192, c: 1, timestamp: 1438840801211 } },
{ coordinates: { x: 484, y: 192, c: 1, timestamp: 1438840801388 } },
{ coordinates: { x: 414, y: 394, c: 1, timestamp: 1438840802378 } },
.....
]
How do I get rid of the unwanted coordinates key in the json?
heatMap.find({'coordinates.c': 1}); should work.