d3js多线散点图缩放
d3js multi-line scatterplot zoom
我正在使用 d3 v6 绘制带缩放的多线散点图。我是 d3 的新手,根据不同的示例,我可以使 images/points 的缩放功能正常工作。问题是线条没有缩放。我查看了许多类似的问题,但是 none 这些解决方案对我有用。
我使用的代码:
var margin = {
top: 50,
right: 30,
bottom: 30,
left: 210,
};
var svg = d3.select("svg"),
width = 1410 - margin.left - margin.right,
height = 620 - margin.top - margin.bottom;
svg
.append("defs")
.append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
d3.csv("CSV_files/NSW_pathway.csv").then(function (data1) {
var groupData = d3.group(data1, (d) => d.pathway_name);
var xScale = d3.scaleLinear().domain([0, 1]).range([0, width]);
var yScale = d3.scaleLinear().domain([0, 1]).range([height, 0]);
var xAxis = d3.axisBottom(xScale).ticks(0).tickSize(-height);
var yAxis = d3.axisLeft(yScale).ticks(0).tickSize(-width);
var gX = svg
.append("g")
.attr(
"transform",
"translate(" + margin.left + "," + (margin.top + height) + ")"
)
.call(xAxis);
var gY = svg
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(yAxis);
var focus = svg
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.attr("class", "line")
.attr("clip-path", "url(#clip)");
const color = d3
.scaleOrdinal()
.range(["#e41a1c", "#377eb8", "#4daf4a", "#984ea3"]);
var points_g = svg
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.attr("clip-path", "url(#clip)")
.classed("points_g", true);
var label = svg
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.attr("class", "label")
.attr("clip-path", "url(#clip)");
var div = d3
.select("body")
.append("div")
.attr("class", "tooltip")
.style("opacity", 0);
const mouseover = function (event, d) {
div.style("opacity", 1);
};
const mousemove = function (event, d) {
div
.html(function (d1) {
if (d.type != "learner")
return `The resource name is ${d.resource_name}`;
else return `This is ${d.name}`;
})
.style("position", "absolute")
.style("left", event.pageX + 15 + "px")
.style("top", event.pageY + 15 + "px");
};
const mouseleave = function (event, d) {
div.transition().duration(200).style("opacity", 0);
};
var points = points_g.selectAll("point").data(data1);
points = points
.enter()
.append("image")
.attr("xlink:href", function (d) {
if (d.type == "video") return "Images/3.jpg";
else if (d.type == "pdf") return "Images/4.png";
else if (d.type == "none") return "Images/5.png";
})
.attr("x", function (d) {
return xScale(+d.x) - 10;
})
.attr("y", function (d) {
return yScale(+d.y) - 10;
})
.attr("width", 20)
.attr("height", 20)
.on("mouseover", mouseover)
.on("mousemove", mousemove)
.on("mouseleave", mouseleave);
label
.selectAll(".text")
.data(data1)
.enter()
.append("text")
.text(function (d) {
return d.topic;
})
.attr("x", function (d) {
return xScale(+d.x) + 10;
})
.attr("y", function (d) {
return yScale(+d.y) + 10;
});
focus
.selectAll("line")
.data(groupData)
.enter()
.append("path")
.attr("fill", "none")
.attr("stroke", function (d) {
return color(d[0]);
})
.attr("stroke-width", 1)
.attr("d", function (d) {
return d3
.line()
.curve(d3.curveMonotoneX)
.x(function (d) {
return xScale(+d.x);
})
.y(function (d) {
return yScale(+d.y);
})(d[1]);
});
var zoom = d3
.zoom()
.scaleExtent([0.5, 20])
.extent([
[0, 0],
[width, height],
])
.on("zoom", zoomed);
svg
.append("rect")
.attr("width", width)
.attr("height", height)
.style("fill", "none")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.lower();
svg.call(zoom).call(zoom.transform, d3.zoomIdentity);
function zoomed({ transform }) {
var new_xScale = transform.rescaleX(xScale);
var new_yScale = transform.rescaleY(yScale);
gX.call(xAxis.scale(new_xScale));
gY.call(yAxis.scale(new_yScale));
points
.data(data1)
.attr("x", function (d) {
return new_xScale(d.x) - 10;
})
.attr("y", function (d) {
return new_yScale(d.y) - 10;
});
label
.selectAll("text")
.data(data1)
.attr("x", function (d) {
return new_xScale(d.x) + 15;
})
.attr("y", function (d) {
return new_yScale(d.y) + 15;
});
focus.selectAll("line").attr("d", function (d) {
return d3
.line()
.curve(d3.curveMonotoneX)
.x(function (d) {
return xScale(+d.x);
})
.y(function (d) {
return yScale(+d.y);
})(d[1]);
});
}
});
csv 文件样本:
x,y,name,type,topic,resource_name,pathway_name
0,0,start,none,Sponsored Search Markets,Networks Crowd and Markets_NCMch15.pdf,pathwayOne
0,0,start,none,Sponsored Search Markets,Networks Crowd and Markets_NCMch15.pdf,pathwayTwo
0.086511627906977,0.16,horse,pdf,Graphs,Networks Crowd and Markets_NCMch2.pdf,pathwayOne
0.12,0.283768436578171,choice,pdf,Network Centrality,Notes_CGT BASED network CENTRALITY - L2.pdf,pathwayTwo
0.32,0.27217943628424,plex,video,Network Models,Network Analysis_LNch13.pdf,pathwayOne
0.775398773006135,0.33,social,pdf,Clustering,Network Analysis_LNch8.pdf,pathwayTwo
1,1,end,none,Allocation in Networks,Notes_Allocation in networks with DON-L3.pdf,pathwayOne
1,1,end,none,Allocation in Networks,Notes_Allocation in networks with DON-L3.pdf,pathwayTwo
感谢您的帮助。
我没有你的 csv 文件的样本,所以这没有经过测试,但如果你想缩放整个图表,只需在你的 svg 和 transform
之后添加父级 g
那..
...
svg
.append("defs")
.append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
// NEW - add g
.append('g')
// NEW - adjust scaleExtent to your needs
const zoom = d3.zoom()
.scaleExtent([1, 8])
.on('zoom', updateChart)
svg.call(zoom)
function updateChart(event) {
svg.attr('transform', event.transform)
}
请注意,这也会添加平移,但如果您只想缩放,则可以使用:
let scale = 1
...
function updateChart(event) {
if(event.transform.k === scale) { return }
svg.attr('transform', event.transform)
scale = event.transform.k
}
它不是在缩放整个页面,而是在缩放整个 svg,您的大边距超出了制图区域。一种解决方案是不在您的 svg 上添加 g
元素,而只在您的图表区域添加。
但是使用您的代码,有两件事阻止了您的线条缩放。
1:您的选择是空的 - 行是一个 d3 抽象,returns 一个路径
function zoomed() {
...
// empty selection
console.log(focus.selectAll('line'))
// try instead
console.log(focus.selectAll('path'))
}
2:简单的错误 - 您使用的是旧秤而不是新秤
function zoomed() {
...
focus.selectAll('path').attr('d', d => {
return d3.line()
// using old scale
.x(di => xScale(+di.x))
// change to
.x(di => new_xScale(+di.x))
})
}
我正在使用 d3 v6 绘制带缩放的多线散点图。我是 d3 的新手,根据不同的示例,我可以使 images/points 的缩放功能正常工作。问题是线条没有缩放。我查看了许多类似的问题,但是 none 这些解决方案对我有用。
我使用的代码:
var margin = {
top: 50,
right: 30,
bottom: 30,
left: 210,
};
var svg = d3.select("svg"),
width = 1410 - margin.left - margin.right,
height = 620 - margin.top - margin.bottom;
svg
.append("defs")
.append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
d3.csv("CSV_files/NSW_pathway.csv").then(function (data1) {
var groupData = d3.group(data1, (d) => d.pathway_name);
var xScale = d3.scaleLinear().domain([0, 1]).range([0, width]);
var yScale = d3.scaleLinear().domain([0, 1]).range([height, 0]);
var xAxis = d3.axisBottom(xScale).ticks(0).tickSize(-height);
var yAxis = d3.axisLeft(yScale).ticks(0).tickSize(-width);
var gX = svg
.append("g")
.attr(
"transform",
"translate(" + margin.left + "," + (margin.top + height) + ")"
)
.call(xAxis);
var gY = svg
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(yAxis);
var focus = svg
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.attr("class", "line")
.attr("clip-path", "url(#clip)");
const color = d3
.scaleOrdinal()
.range(["#e41a1c", "#377eb8", "#4daf4a", "#984ea3"]);
var points_g = svg
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.attr("clip-path", "url(#clip)")
.classed("points_g", true);
var label = svg
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.attr("class", "label")
.attr("clip-path", "url(#clip)");
var div = d3
.select("body")
.append("div")
.attr("class", "tooltip")
.style("opacity", 0);
const mouseover = function (event, d) {
div.style("opacity", 1);
};
const mousemove = function (event, d) {
div
.html(function (d1) {
if (d.type != "learner")
return `The resource name is ${d.resource_name}`;
else return `This is ${d.name}`;
})
.style("position", "absolute")
.style("left", event.pageX + 15 + "px")
.style("top", event.pageY + 15 + "px");
};
const mouseleave = function (event, d) {
div.transition().duration(200).style("opacity", 0);
};
var points = points_g.selectAll("point").data(data1);
points = points
.enter()
.append("image")
.attr("xlink:href", function (d) {
if (d.type == "video") return "Images/3.jpg";
else if (d.type == "pdf") return "Images/4.png";
else if (d.type == "none") return "Images/5.png";
})
.attr("x", function (d) {
return xScale(+d.x) - 10;
})
.attr("y", function (d) {
return yScale(+d.y) - 10;
})
.attr("width", 20)
.attr("height", 20)
.on("mouseover", mouseover)
.on("mousemove", mousemove)
.on("mouseleave", mouseleave);
label
.selectAll(".text")
.data(data1)
.enter()
.append("text")
.text(function (d) {
return d.topic;
})
.attr("x", function (d) {
return xScale(+d.x) + 10;
})
.attr("y", function (d) {
return yScale(+d.y) + 10;
});
focus
.selectAll("line")
.data(groupData)
.enter()
.append("path")
.attr("fill", "none")
.attr("stroke", function (d) {
return color(d[0]);
})
.attr("stroke-width", 1)
.attr("d", function (d) {
return d3
.line()
.curve(d3.curveMonotoneX)
.x(function (d) {
return xScale(+d.x);
})
.y(function (d) {
return yScale(+d.y);
})(d[1]);
});
var zoom = d3
.zoom()
.scaleExtent([0.5, 20])
.extent([
[0, 0],
[width, height],
])
.on("zoom", zoomed);
svg
.append("rect")
.attr("width", width)
.attr("height", height)
.style("fill", "none")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.lower();
svg.call(zoom).call(zoom.transform, d3.zoomIdentity);
function zoomed({ transform }) {
var new_xScale = transform.rescaleX(xScale);
var new_yScale = transform.rescaleY(yScale);
gX.call(xAxis.scale(new_xScale));
gY.call(yAxis.scale(new_yScale));
points
.data(data1)
.attr("x", function (d) {
return new_xScale(d.x) - 10;
})
.attr("y", function (d) {
return new_yScale(d.y) - 10;
});
label
.selectAll("text")
.data(data1)
.attr("x", function (d) {
return new_xScale(d.x) + 15;
})
.attr("y", function (d) {
return new_yScale(d.y) + 15;
});
focus.selectAll("line").attr("d", function (d) {
return d3
.line()
.curve(d3.curveMonotoneX)
.x(function (d) {
return xScale(+d.x);
})
.y(function (d) {
return yScale(+d.y);
})(d[1]);
});
}
});
csv 文件样本:
x,y,name,type,topic,resource_name,pathway_name
0,0,start,none,Sponsored Search Markets,Networks Crowd and Markets_NCMch15.pdf,pathwayOne
0,0,start,none,Sponsored Search Markets,Networks Crowd and Markets_NCMch15.pdf,pathwayTwo
0.086511627906977,0.16,horse,pdf,Graphs,Networks Crowd and Markets_NCMch2.pdf,pathwayOne
0.12,0.283768436578171,choice,pdf,Network Centrality,Notes_CGT BASED network CENTRALITY - L2.pdf,pathwayTwo
0.32,0.27217943628424,plex,video,Network Models,Network Analysis_LNch13.pdf,pathwayOne
0.775398773006135,0.33,social,pdf,Clustering,Network Analysis_LNch8.pdf,pathwayTwo
1,1,end,none,Allocation in Networks,Notes_Allocation in networks with DON-L3.pdf,pathwayOne
1,1,end,none,Allocation in Networks,Notes_Allocation in networks with DON-L3.pdf,pathwayTwo
感谢您的帮助。
我没有你的 csv 文件的样本,所以这没有经过测试,但如果你想缩放整个图表,只需在你的 svg 和 transform
之后添加父级 g
那..
...
svg
.append("defs")
.append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
// NEW - add g
.append('g')
// NEW - adjust scaleExtent to your needs
const zoom = d3.zoom()
.scaleExtent([1, 8])
.on('zoom', updateChart)
svg.call(zoom)
function updateChart(event) {
svg.attr('transform', event.transform)
}
请注意,这也会添加平移,但如果您只想缩放,则可以使用:
let scale = 1
...
function updateChart(event) {
if(event.transform.k === scale) { return }
svg.attr('transform', event.transform)
scale = event.transform.k
}
它不是在缩放整个页面,而是在缩放整个 svg,您的大边距超出了制图区域。一种解决方案是不在您的 svg 上添加 g
元素,而只在您的图表区域添加。
但是使用您的代码,有两件事阻止了您的线条缩放。
1:您的选择是空的 - 行是一个 d3 抽象,returns 一个路径
function zoomed() {
...
// empty selection
console.log(focus.selectAll('line'))
// try instead
console.log(focus.selectAll('path'))
}
2:简单的错误 - 您使用的是旧秤而不是新秤
function zoomed() {
...
focus.selectAll('path').attr('d', d => {
return d3.line()
// using old scale
.x(di => xScale(+di.x))
// change to
.x(di => new_xScale(+di.x))
})
}