具有非时间 x 轴的 D3 多系列折线图
Posted
技术标签:
【中文标题】具有非时间 x 轴的 D3 多系列折线图【英文标题】:D3 Multi Series Line chart with non time x axis 【发布时间】:2019-05-07 23:43:14 【问题描述】:我的应用程序中实现了多系列折线图。这里给出了示例代码https://jsfiddle.net/yasirunilan/hevdy5kp/3/
在该图表中,X 轴值是月份名称。但由于本地化问题,我需要将月份名称更改为不同的语言。然后问题就来了,因为 xAsis 是时间序列,它在图表中给出了错误。有没有办法可以将此图表 x 轴转换为非时间序列。这样我就可以将月份名称用作字符串,这样我就可以对月份名称进行修改而不必担心 x 轴格式。
var data = [
name: "USA",
values: [
date: "January",
price: "100"
,
date: "February",
price: "110"
,
date: "March",
price: "145"
,
date: "April",
price: "241"
,
date: "May",
price: "101"
,
date: "June",
price: "90"
,
date: "July",
price: "120"
,
date: "August",
price: "135"
,
date: "September",
price: "99"
,
date: "October",
price: "105"
,
date: "November",
price: "101"
,
date: "December",
price: "106"
]
,
name: "UK",
values: [
date: "January",
price: "130"
,
date: "February",
price: "120"
,
date: "March",
price: "115"
,
date: "April",
price: "220"
,
date: "May",
price: "100"
,
date: "June",
price: "140"
,
date: "July",
price: "90"
,
date: "August",
price: "235"
,
date: "September",
price: "160"
,
date: "October",
price: "86"
,
date: "November",
price: "201"
,
date: "December",
price: "140"
]
];
const margin = 80;
const width = 1000 - 2 * margin;
const height = 550 - 2 * margin;
var duration = 250;
var lineOpacity = "0.25";
var lineOpacityHover = "0.85";
var otherLinesOpacityHover = "0.1";
var lineStroke = "1.5px";
var lineStrokeHover = "2.5px";
var circleOpacity = '0.85';
var circleOpacityOnLineHover = "0.25"
var circleRadius = 3;
var circleRadiusHover = 6;
/* Format Data */
var parseDate = d3.time.format("%B");
data.forEach(function(d)
d.values.forEach(function(d)
d.date = parseDate.parse(d.date);
d.price = +d.price;
);
);
/* Scale */
var xScale = d3.time.scale()
.domain(d3.extent(data[0].values, d => d.date))
.range([0, width - margin]);
var yScale = d3.scale.linear()
.domain([0, d3.max(data[0].values, d => d.price)])
.range([height - margin, 0]);
// var color = d3.scale.ordinal(d3.schemeCategory10);
var color = d3.scale.category10();
/* Add SVG */
var svg = d3.select("svg")
.attr("width", (width + margin) + "px")
.attr("height", (height + margin) + "px")
.append('g')
.attr("transform", `translate($margin, $margin)`);
/* Add line into SVG */
var line = d3.svg.line()
.x(d => xScale(d.date))
.y(d => yScale(d.price));
let lines = svg.append('g')
.attr('class', 'lines');
lines.selectAll('.line-group')
.data(data).enter()
.append('g')
.attr('class', 'line-group')
.on("mouseover", function(d, i)
svg.append("text")
.attr("class", "title-text")
.style("fill", color(i))
.text(d.name)
.attr("text-anchor", "middle")
.attr("x", (width - margin) / 2)
.attr("y", 5);
)
.on("mouseout", function(d)
svg.select(".title-text").remove();
)
.append('path')
.attr('class', 'line')
.attr('d', d => line(d.values))
.style('stroke', (d, i) => color(i))
.style('opacity', lineOpacity)
.on("mouseover", function(d)
d3.selectAll('.line')
.style('opacity', otherLinesOpacityHover);
d3.selectAll('.circle')
.style('opacity', circleOpacityOnLineHover);
d3.select(this)
.style('opacity', lineOpacityHover)
.style("stroke-width", lineStrokeHover)
.style("cursor", "pointer");
)
.on("mouseout", function(d)
d3.selectAll(".line")
.style('opacity', lineOpacity);
d3.selectAll('.circle')
.style('opacity', circleOpacity);
d3.select(this)
.style("stroke-width", lineStroke)
.style("cursor", "none");
);
/* Add circles in the line */
lines.selectAll("circle-group")
.data(data).enter()
.append("g")
.style("fill", (d, i) => color(i))
.selectAll("circle")
.data(d => d.values).enter()
.append("g")
.attr("class", "circle")
.on("mouseover", function(d)
d3.select(this)
.style("cursor", "pointer")
.append("text")
.attr("class", "text")
.text(`$d.price`)
.attr("x", d => xScale(d.date) + 5)
.attr("y", d => yScale(d.price) - 10);
)
.on("mouseout", function(d)
d3.select(this)
.style("cursor", "none")
.transition()
.duration(duration)
.selectAll(".text").remove();
)
.append("circle")
.attr("cx", d => xScale(d.date))
.attr("cy", d => yScale(d.price))
.attr("r", circleRadius)
.style('opacity', circleOpacity)
.on("mouseover", function(d)
d3.select(this)
.transition()
.duration(duration)
.attr("r", circleRadiusHover);
)
.on("mouseout", function(d)
d3.select(this)
.transition()
.duration(duration)
.attr("r", circleRadius);
);
var xAxis = d3.svg.axis().scale(xScale)
.orient("bottom").tickFormat(d3.time.format("%B")).tickSize(1);
var yAxis = d3.svg.axis().scale(yScale)
.orient("left").tickSize(1);
svg.append("g")
.attr("class", "x axis")
.attr("transform", `translate(0, $height-margin)`)
.call(xAxis.ticks(d3.time.months));
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append('text')
.attr("y", 15)
.attr("transform", "rotate(-90)")
.attr("fill", "#000")
.attr('text-anchor', 'middle')
.text("No. of Employees");
【问题讨论】:
如果您知道所有行都有所有数据点,您可以使用 Ordinal 刻度之一 @rioV8 你能用我的示例代码给我看一个例子吗 【参考方案1】:在尝试了其他人建议的不同方法后找到了解决方案。 https://jsfiddle.net/yasirunilan/8y3f09xb/4/
var data = [
name: "USA",
values: [
date: "January",
price: "100"
,
date: "February",
price: "110"
,
date: "March",
price: "145"
,
date: "April",
price: "241"
,
date: "May",
price: "101"
,
date: "June",
price: "90"
,
date: "July",
price: "120"
,
date: "August",
price: "135"
,
date: "September",
price: "99"
,
date: "October",
price: "105"
,
date: "November",
price: "101"
,
date: "December",
price: "106"
]
,
name: "UK",
values: [
date: "January",
price: "130"
,
date: "February",
price: "120"
,
date: "March",
price: "115"
,
date: "April",
price: "220"
,
date: "May",
price: "100"
,
date: "June",
price: "140"
,
date: "July",
price: "90"
,
date: "August",
price: "235"
,
date: "September",
price: "160"
,
date: "October",
price: "86"
,
date: "November",
price: "201"
,
date: "December",
price: "140"
]
];
const margin = 80;
const width = 1000 - 2 * margin;
const height = 550 - 2 * margin;
var duration = 250;
var lineOpacity = "0.25";
var lineOpacityHover = "0.85";
var otherLinesOpacityHover = "0.1";
var lineStroke = "1.5px";
var lineStrokeHover = "2.5px";
var circleOpacity = '0.85';
var circleOpacityOnLineHover = "0.25"
var circleRadius = 3;
var circleRadiusHover = 6;
/* Format Data */
data.forEach(function(d)
d.values.forEach(function(d)
d.date = d.date;
d.price = +d.price;
);
);
/* Scale */
var xScale = d3.scale.ordinal()
.domain(data[0].values.map(function(d)
return d.date;
))
.rangePoints([0, width], 0.9);
var yScale = d3.scale.linear()
.domain([0, d3.max(data[0].values, d => d.price)])
.range([height - margin, 0]);
// var color = d3.scale.ordinal(d3.schemeCategory10);
var color = d3.scale.category10();
/* Add SVG */
var svg = d3.select("svg")
.attr("width", (width + margin) + "px")
.attr("height", (height + margin) + "px")
.append('g')
.attr("transform", `translate($margin, $margin)`);
/* Add line into SVG */
var line = d3.svg.line()
.x(d => xScale(d.date))
.y(d => yScale(d.price));
let lines = svg.append('g')
.attr('class', 'lines');
lines.selectAll('.line-group')
.data(data).enter()
.append('g')
.attr('class', 'line-group')
.on("mouseover", function(d, i)
svg.append("text")
.attr("class", "title-text")
.style("fill", color(i))
.text(d.name)
.attr("text-anchor", "middle")
.attr("x", (width - margin) / 2)
.attr("y", 5);
)
.on("mouseout", function(d)
svg.select(".title-text").remove();
)
.append('path')
.attr('class', 'line')
.attr('d', d => line(d.values))
.style('stroke', (d, i) => color(i))
.style('opacity', lineOpacity)
.on("mouseover", function(d)
d3.selectAll('.line')
.style('opacity', otherLinesOpacityHover);
d3.selectAll('.circle')
.style('opacity', circleOpacityOnLineHover);
d3.select(this)
.style('opacity', lineOpacityHover)
.style("stroke-width", lineStrokeHover)
.style("cursor", "pointer");
)
.on("mouseout", function(d)
d3.selectAll(".line")
.style('opacity', lineOpacity);
d3.selectAll('.circle')
.style('opacity', circleOpacity);
d3.select(this)
.style("stroke-width", lineStroke)
.style("cursor", "none");
);
/* Add circles in the line */
lines.selectAll("circle-group")
.data(data).enter()
.append("g")
.style("fill", (d, i) => color(i))
.selectAll("circle")
.data(d => d.values).enter()
.append("g")
.attr("class", "circle")
.on("mouseover", function(d)
d3.select(this)
.style("cursor", "pointer")
.append("text")
.attr("class", "text")
.text(`$d.price`)
.attr("x", d => xScale(d.date) + 5)
.attr("y", d => yScale(d.price) - 10);
)
.on("mouseout", function(d)
d3.select(this)
.style("cursor", "none")
.transition()
.duration(duration)
.selectAll(".text").remove();
)
.append("circle")
.attr("cx", d => xScale(d.date))
.attr("cy", d => yScale(d.price))
.attr("r", circleRadius)
.style('opacity', circleOpacity)
.on("mouseover", function(d)
d3.select(this)
.transition()
.duration(duration)
.attr("r", circleRadiusHover);
)
.on("mouseout", function(d)
d3.select(this)
.transition()
.duration(duration)
.attr("r", circleRadius);
);
var xAxis = d3.svg.axis().scale(xScale)
.orient("bottom").tickSize(1);
var yAxis = d3.svg.axis().scale(yScale)
.orient("left").tickSize(1);
svg.append("g")
.attr("class", "x axis")
.attr("transform", `translate(0, $height-margin)`)
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append('text')
.attr("y", 15)
.attr("transform", "rotate(-90)")
.attr("fill", "#000")
.attr('text-anchor', 'middle')
.text("No. of Employees");
【讨论】:
以上是关于具有非时间 x 轴的 D3 多系列折线图的主要内容,如果未能解决你的问题,请参考以下文章