admin管理员组文章数量:1024080
I have data like the examples. Instead of Category i have time instead for one whole day for each quarter. If a quarter doesnt have data there is no value for it. For example 08:30 doesnt exist in Series 1. Therefore when the chart renders 08:30 will e after 08:45 since only Series 2 has a value for it. But obviously i want it right after 08:15. Everything else is correct. Only solution that im thinking of is to populate first element (Series 1) with every missing timeframe and with 0 as value for it. But I am hoping theres a better solution for this.
const series = [
{
name: 'Series 1',
data: [
{ time: '08:00', value: Math.random() },
{ category: '08:15', value: Math.random() },
{ category: '08:45', value: Math.random() },
],
},
{
name: 'Series 2',
data: [
{ category: '08:00', value: Math.random() },
{ category: '08:15', value: Math.random() },
{ category: '08:30', value: Math.random() },
],
},
];
Heres the relevant code as requested. Datakey is just a string to select which data to show. Because i have multiple "value" fields for the Y-Axis.
<ResponsiveContainer>
<LineChart>
<CartesianGrid strokeDasharray="2 2" />
<XAxis
dataKey="endTime"
type="category"
allowDuplicatedCategory={false}
/>
<YAxis dataKey={dataKey} />
<Tooltip />
<Legend />
{chartData.map((irvMachine, i) => (
<Line
data={irvMachine.data}
name={irvMachine.irvMachine}
dataKey={dataKey}
stroke={colors[i]}
activeDot={{ r: 4 }}
type="monotone"
/>
))}
</LineChart>
</ResponsiveContainer>
I have data like the examples. Instead of Category i have time instead for one whole day for each quarter. If a quarter doesnt have data there is no value for it. For example 08:30 doesnt exist in Series 1. Therefore when the chart renders 08:30 will e after 08:45 since only Series 2 has a value for it. But obviously i want it right after 08:15. Everything else is correct. Only solution that im thinking of is to populate first element (Series 1) with every missing timeframe and with 0 as value for it. But I am hoping theres a better solution for this.
const series = [
{
name: 'Series 1',
data: [
{ time: '08:00', value: Math.random() },
{ category: '08:15', value: Math.random() },
{ category: '08:45', value: Math.random() },
],
},
{
name: 'Series 2',
data: [
{ category: '08:00', value: Math.random() },
{ category: '08:15', value: Math.random() },
{ category: '08:30', value: Math.random() },
],
},
];
Heres the relevant code as requested. Datakey is just a string to select which data to show. Because i have multiple "value" fields for the Y-Axis.
<ResponsiveContainer>
<LineChart>
<CartesianGrid strokeDasharray="2 2" />
<XAxis
dataKey="endTime"
type="category"
allowDuplicatedCategory={false}
/>
<YAxis dataKey={dataKey} />
<Tooltip />
<Legend />
{chartData.map((irvMachine, i) => (
<Line
data={irvMachine.data}
name={irvMachine.irvMachine}
dataKey={dataKey}
stroke={colors[i]}
activeDot={{ r: 4 }}
type="monotone"
/>
))}
</LineChart>
</ResponsiveContainer>
Share
Improve this question
edited Nov 5, 2021 at 15:21
Super Kai - Kazuya Ito
1
asked Nov 4, 2021 at 14:56
HodlHodl
931 gold badge3 silver badges12 bronze badges
2
- Can you include some of the code for the ponent? – Henry Commented Nov 4, 2021 at 16:48
- Thanks for the answer. I have added the relevant code in the post. – Hodl Commented Nov 5, 2021 at 9:26
2 Answers
Reset to default 2You can transform your data a bit to get a single series of data where "Series 1" and "Series 2" would be the value keys and sort on the "category" key. This way all categories show up in the desired order and any missing values for a single subseries are just a missing key for that entry.
Here's a sample function:
function transformSeries(series) {
const chartDataObj = {};
for (let i = 0; i < series.length; i++) {
const seriesName = series[i].name;
for (let j = 0; j < series[i].data.length; j++) {
const category = series[i].data[j].category;
const value = series[i].data[j].value;
if (!chartDataObj.hasOwnProperty(category)) {
chartDataObj[category] = { category: category };
}
chartDataObj[category][seriesName] = value;
if (!chartDataObj[category].hasOwnProperty("maxVal")) {
chartDataObj[category].maxVal = value;
} else {
chartDataObj[category].maxVal = Math.max(chartDataObj[category].maxVal, value);
}
}
}
return Object.values(chartDataObj).sort((a, b) => (a.category > b.category ? 1 : -1));
}
The result of calling this function on the data you provided is:
[
{category: "08:00", "Series 1": 0.7467901762604093, "Series 2": 0.47855212989392215, maxVal: 0.7467901762604093},
{category: "08:15", "Series 1": 0.2311522761588818, "Series 2": 0.12893275264478166, maxVal: 0.2311522761588818},
{category: "08:30", "Series 2": 0.924208327780883, maxVal: 0.924208327780883},
{category: "08:45", "Series 1": 0.8633031302477523, maxVal: 0.8633031302477523}
]
This also includes a maxVal
key to provide to the YAxis
ponent (since it doesn't currently support multiple keys).
Then you can render like this:
export function MyChart() {
const chartData = transformSeries(series);
return (
<LineChart width={800} height={450} data={chartData}>
<CartesianGrid strokeDasharray="2 2" />
<XAxis dataKey="category" type="category" allowDuplicatedCategory={false} />
<YAxis dataKey="maxVal" />
<Tooltip />
<Legend />
{series.map((s) => (
<Line key={s.name} dataKey={s.name} />
))}
</LineChart>
);
}
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: '08:00' },
{ category: '08:15' },
{ category: '08:30' },
{ category: '08:45' }
]
}
<ResponsiveContainer>
<LineChart>
<CartesianGrid strokeDasharray="2 2" />
<XAxis
dataKey="endTime"
type="category"
allowDuplicatedCategory={false}
/>
<YAxis dataKey={dataKey} />
<Tooltip />
<Legend />
<Line data={labelSeries.data} /> // This line will sort the x-axis label
{chartData.map((irvMachine, i) => (
<Line
data={irvMachine.data}
name={irvMachine.irvMachine}
dataKey={dataKey}
stroke={colors[i]}
activeDot={{ r: 4 }}
type="monotone"
/>
))}
</LineChart>
</ResponsiveContainer>
I have data like the examples. Instead of Category i have time instead for one whole day for each quarter. If a quarter doesnt have data there is no value for it. For example 08:30 doesnt exist in Series 1. Therefore when the chart renders 08:30 will e after 08:45 since only Series 2 has a value for it. But obviously i want it right after 08:15. Everything else is correct. Only solution that im thinking of is to populate first element (Series 1) with every missing timeframe and with 0 as value for it. But I am hoping theres a better solution for this.
const series = [
{
name: 'Series 1',
data: [
{ time: '08:00', value: Math.random() },
{ category: '08:15', value: Math.random() },
{ category: '08:45', value: Math.random() },
],
},
{
name: 'Series 2',
data: [
{ category: '08:00', value: Math.random() },
{ category: '08:15', value: Math.random() },
{ category: '08:30', value: Math.random() },
],
},
];
Heres the relevant code as requested. Datakey is just a string to select which data to show. Because i have multiple "value" fields for the Y-Axis.
<ResponsiveContainer>
<LineChart>
<CartesianGrid strokeDasharray="2 2" />
<XAxis
dataKey="endTime"
type="category"
allowDuplicatedCategory={false}
/>
<YAxis dataKey={dataKey} />
<Tooltip />
<Legend />
{chartData.map((irvMachine, i) => (
<Line
data={irvMachine.data}
name={irvMachine.irvMachine}
dataKey={dataKey}
stroke={colors[i]}
activeDot={{ r: 4 }}
type="monotone"
/>
))}
</LineChart>
</ResponsiveContainer>
I have data like the examples. Instead of Category i have time instead for one whole day for each quarter. If a quarter doesnt have data there is no value for it. For example 08:30 doesnt exist in Series 1. Therefore when the chart renders 08:30 will e after 08:45 since only Series 2 has a value for it. But obviously i want it right after 08:15. Everything else is correct. Only solution that im thinking of is to populate first element (Series 1) with every missing timeframe and with 0 as value for it. But I am hoping theres a better solution for this.
const series = [
{
name: 'Series 1',
data: [
{ time: '08:00', value: Math.random() },
{ category: '08:15', value: Math.random() },
{ category: '08:45', value: Math.random() },
],
},
{
name: 'Series 2',
data: [
{ category: '08:00', value: Math.random() },
{ category: '08:15', value: Math.random() },
{ category: '08:30', value: Math.random() },
],
},
];
Heres the relevant code as requested. Datakey is just a string to select which data to show. Because i have multiple "value" fields for the Y-Axis.
<ResponsiveContainer>
<LineChart>
<CartesianGrid strokeDasharray="2 2" />
<XAxis
dataKey="endTime"
type="category"
allowDuplicatedCategory={false}
/>
<YAxis dataKey={dataKey} />
<Tooltip />
<Legend />
{chartData.map((irvMachine, i) => (
<Line
data={irvMachine.data}
name={irvMachine.irvMachine}
dataKey={dataKey}
stroke={colors[i]}
activeDot={{ r: 4 }}
type="monotone"
/>
))}
</LineChart>
</ResponsiveContainer>
Share
Improve this question
edited Nov 5, 2021 at 15:21
Super Kai - Kazuya Ito
1
asked Nov 4, 2021 at 14:56
HodlHodl
931 gold badge3 silver badges12 bronze badges
2
- Can you include some of the code for the ponent? – Henry Commented Nov 4, 2021 at 16:48
- Thanks for the answer. I have added the relevant code in the post. – Hodl Commented Nov 5, 2021 at 9:26
2 Answers
Reset to default 2You can transform your data a bit to get a single series of data where "Series 1" and "Series 2" would be the value keys and sort on the "category" key. This way all categories show up in the desired order and any missing values for a single subseries are just a missing key for that entry.
Here's a sample function:
function transformSeries(series) {
const chartDataObj = {};
for (let i = 0; i < series.length; i++) {
const seriesName = series[i].name;
for (let j = 0; j < series[i].data.length; j++) {
const category = series[i].data[j].category;
const value = series[i].data[j].value;
if (!chartDataObj.hasOwnProperty(category)) {
chartDataObj[category] = { category: category };
}
chartDataObj[category][seriesName] = value;
if (!chartDataObj[category].hasOwnProperty("maxVal")) {
chartDataObj[category].maxVal = value;
} else {
chartDataObj[category].maxVal = Math.max(chartDataObj[category].maxVal, value);
}
}
}
return Object.values(chartDataObj).sort((a, b) => (a.category > b.category ? 1 : -1));
}
The result of calling this function on the data you provided is:
[
{category: "08:00", "Series 1": 0.7467901762604093, "Series 2": 0.47855212989392215, maxVal: 0.7467901762604093},
{category: "08:15", "Series 1": 0.2311522761588818, "Series 2": 0.12893275264478166, maxVal: 0.2311522761588818},
{category: "08:30", "Series 2": 0.924208327780883, maxVal: 0.924208327780883},
{category: "08:45", "Series 1": 0.8633031302477523, maxVal: 0.8633031302477523}
]
This also includes a maxVal
key to provide to the YAxis
ponent (since it doesn't currently support multiple keys).
Then you can render like this:
export function MyChart() {
const chartData = transformSeries(series);
return (
<LineChart width={800} height={450} data={chartData}>
<CartesianGrid strokeDasharray="2 2" />
<XAxis dataKey="category" type="category" allowDuplicatedCategory={false} />
<YAxis dataKey="maxVal" />
<Tooltip />
<Legend />
{series.map((s) => (
<Line key={s.name} dataKey={s.name} />
))}
</LineChart>
);
}
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: '08:00' },
{ category: '08:15' },
{ category: '08:30' },
{ category: '08:45' }
]
}
<ResponsiveContainer>
<LineChart>
<CartesianGrid strokeDasharray="2 2" />
<XAxis
dataKey="endTime"
type="category"
allowDuplicatedCategory={false}
/>
<YAxis dataKey={dataKey} />
<Tooltip />
<Legend />
<Line data={labelSeries.data} /> // This line will sort the x-axis label
{chartData.map((irvMachine, i) => (
<Line
data={irvMachine.data}
name={irvMachine.irvMachine}
dataKey={dataKey}
stroke={colors[i]}
activeDot={{ r: 4 }}
type="monotone"
/>
))}
</LineChart>
</ResponsiveContainer>
本文标签: javascriptReact RechartsHow to sort XAxis with timeStack Overflow
版权声明:本文标题:javascript - React Recharts - How to sort X-Axis with time? - Stack Overflow 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://it.en369.cn/questions/1745593289a2158014.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论