我是D3.js
的新手(我是R
程序员)。
我正在尝试创建散点图,并在右下角添加图例。但是,它与图表区域重叠。
我一直在尝试举一些互联网上的例子,但并不幸运。 当我尝试将其向右移动时,名称和/或符号不可见。
我想将图例放置在图表框架之外,因此不会重叠。
感谢您的帮助。
这是我到目前为止尝试过的:
d3.csv('https://gist.githubusercontent.com/netj/8836201/raw/6f9306ad21398ea43cba4f7d537619d0e07d5ae3/iris.csv', function(data) {
// CSV section
var body = d3.select('body')
var selectData = [{
"text": "sepal.length"
},
{
"text": "sepal.width"
},
{
"text": "petal.length"
},
{
"text": "petal.width"
},
]
// setup fill color
var colors = ['#575757', '#5FB1B9', '#C94257'];
var symbol = d3.svg.symbol()
.type('circle')
.size("160")
var cValue = function(d) {
return d.variety;
},
color = d3.scale.ordinal()
.range(colors);
// Select Y-axis Variable
var span = body.append('span')
.text('Select Y-Axis variable: ')
var yInput = body.append('select')
.attr('id', 'ySelect')
.on('change', yChange)
.selectAll('option')
.data(selectData)
.enter()
.append('option')
.attr('value', function(d) {
return d.text
})
.text(function(d) {
return d.text;
})
body.append('br')
// Select X-axis Variable
var span = body.append('span')
.text('Select X-Axis variable: ')
var yInput = body.append('select')
.attr('id', 'xSelect')
.on('change', xChange)
.selectAll('option')
.data(selectData)
.enter()
.append('option')
.attr('value', function(d) {
return d.text
})
.text(function(d) {
return d.text;
})
body.append('br')
// Variables
var body = d3.select('body')
var margin = {
top: 50,
right: 50,
bottom: 50,
left: 50
}
var h = 500 - margin.top - margin.bottom
var w = 500 - margin.left - margin.right
// var formatPercent = d3.format('.2%')
// Scales
// var colorScale = d3.scale.category20()
var xScale = d3.scale.linear()
.domain([
d3.min([0, d3.min(data, function(d) {
return d['sepal.length']
})]),
d3.max([0, d3.max(data, function(d) {
return d['sepal.length']
})])
])
.range([0, w])
var yScale = d3.scale.linear()
.domain([
d3.min([0, d3.min(data, function(d) {
return d['sepal.length']
})]),
d3.max([0, d3.max(data, function(d) {
return d['sepal.length']
})])
])
.range([h, 0])
// SVG
var svg = body.append('svg')
.attr('height', h + margin.top + margin.bottom)
.attr('width', w + margin.left + margin.right)
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
// X-axis
var xAxis = d3.svg.axis()
.scale(xScale)
// .tickFormat(formatPercent)
.ticks(6)
.outerTickSize(0)
.tickSize(0)
.orient('bottom')
// Y-axis
var yAxis = d3.svg.axis()
.scale(yScale)
// .tickFormat(formatPercent)
.ticks(6)
.tickSize(-w)
.outerTickSize(0)
.orient('left')
// Circles
var circles = svg.selectAll('circle')
.data(data)
.enter()
.append('circle')
.attr('cx', function(d) {
return xScale(d['sepal.length'])
})
.attr('cy', function(d) {
return yScale(d['sepal.length'])
})
.attr('r', '10')
// .attr('stroke', 'black')
.attr('stroke-width', 0.2)
.attr("fill", function(d) {
return color(cValue(d));
})
.attr('fill-opacity', 0.8)
// .attr('fill', function(d, i) {
// return colorScale(i)
// })
.on('mouseover', function() {
d3.select(this)
.transition()
.duration(300)
.ease('elastic')
.attr('r', 15)
.attr('stroke-width', 1)
.attr('fill-opacity', 1)
})
.on('mouseout', function() {
d3.select(this)
.transition()
.duration(100)
.attr('r', 10)
.attr('stroke-width', 0.5)
})
.append('title') // Tooltip
.text(function(d) {
return d.variety +
'\nSepal Length: ' + d['sepal.length'] +
'\nSepal Width: ' + d['sepal.width'] +
'\nPetal Length: ' + d['petal.length'] +
'\nPetal Width: ' + d['petal.width']
})
// X-axis
svg.append('g')
.attr('class', 'axis')
.attr('id', 'xAxis')
.attr('transform', 'translate(0,' + h + ')')
.call(xAxis)
.append('text') // X-axis Label
.attr('id', 'xAxisLabel')
.attr('y', -25)
.attr('x', w)
.attr('dy', '.71em')
.style('text-anchor', 'end')
.text('Sepal Length')
// labels distance from xaxis
svg.selectAll(".axis text")
.attr("dy", 15);
// Y-axis
svg.append('g')
.attr('class', 'axis')
.attr('id', 'yAxis')
.call(yAxis)
.append('text') // y-axis Label
.attr('id', 'yAxisLabel')
.attr('transform', 'rotate(-90)')
.attr('x', 0)
.attr('y', 5)
.attr('dy', '.71em')
.style('text-anchor', 'end')
.text('Sepal Length')
function yChange() {
var value = this.value // get the new y value
yScale // change the yScale
.domain([
d3.min([0, d3.min(data, function(d) {
return d[value]
})]),
d3.max([0, d3.max(data, function(d) {
return d[value]
})])
])
yAxis.scale(yScale) // change the yScale
d3.select('#yAxis') // redraw the yAxis
.transition().duration(500)
.call(yAxis)
d3.select('#yAxisLabel') // change the yAxisLabel
.text(value)
d3.selectAll('circle') // move the circles
.transition().duration(500)
.delay(function(d, i) {
return i * 10
})
.attr('cy', function(d) {
return yScale(d[value])
})
}
function xChange() {
var value = this.value // get the new x value
xScale // change the xScale
.domain([
d3.min([0, d3.min(data, function(d) {
return d[value]
})]),
d3.max([0, d3.max(data, function(d) {
return d[value]
})])
])
xAxis.scale(xScale) // change the xScale
d3.select('#xAxis') // redraw the xAxis
.transition().duration(500)
.call(xAxis)
d3.select('#xAxisLabel') // change the xAxisLabel
.transition().duration(500)
.text(value)
d3.selectAll('circle') // move the circles
.transition().duration(500)
.delay(function(d, i) {
return i * 10
})
.attr('cx', function(d) {
return xScale(d[value])
})
}
// create legend
var legend = svg.selectAll(".legend")
.data(color.domain())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) {
return "translate(0," + i * 25 + ")";
});
// draw legend colored rectangles
legend.append("path")
.attr('d', symbol)
.attr("transform", "translate(434, 313)") //much easier approach to position the symbols
// .attr("x", w + 34)
// .attr("y", h - 97)
// .attr("width", 18)
// .attr("height", 18)
.style("fill", color);
// draw legend text
legend.append("text")
.attr("transform", "translate(422, 311)")
// .attr("x", w + 24)
// .attr("y", h - 89)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) {
return d;
})
})
body {
font-size: 16px;
}
/*
circle {
fill: steelblue;
} */
circle:hover {
fill: orange;
}
.axis text {
font-size: 13px;
/* font-weight: bold; */
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
stroke-width: 0.02px;
}
/* .circle {
fill: orange;
} */
label {
position: absolute;
top: 10px;
right: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.10/d3.min.js"></script>
<body></body>
答案 0 :(得分:1)
为什么不只是将图例呈现为HTML并使用CSS来帮助布局?
d3.csv('https://gist.githubusercontent.com/netj/8836201/raw/6f9306ad21398ea43cba4f7d537619d0e07d5ae3/iris.csv', function(data) {
// CSV section
var body = d3.select('body')
var selectData = [{
"text": "sepal.length"
},
{
"text": "sepal.width"
},
{
"text": "petal.length"
},
{
"text": "petal.width"
},
]
// setup fill color
var colors = ['#575757', '#5FB1B9', '#C94257'];
var symbol = d3.svg.symbol()
.type('circle')
.size("160")
var cValue = function(d) {
return d.variety;
},
color = d3.scale.ordinal()
.range(colors);
var controls = body.append('div').attr('class', 'controls')
// Select Y-axis Variable
var yControls = controls.append('div')
var span = yControls.append('span')
.text('Select Y-Axis variable: ')
var yInput = yControls.append('select')
.attr('id', 'ySelect')
.on('change', yChange)
.selectAll('option')
.data(selectData)
.enter()
.append('option')
.attr('value', function(d) {
return d.text
})
.text(function(d) {
return d.text;
})
// Select X-axis Variable
var xControls = controls.append('div')
var span = xControls.append('span')
.text('Select X-Axis variable: ')
var yInput = xControls.append('select')
.attr('id', 'xSelect')
.on('change', xChange)
.selectAll('option')
.data(selectData)
.enter()
.append('option')
.attr('value', function(d) {
return d.text
})
.text(function(d) {
return d.text;
})
// Variables
var body = d3.select('body')
var margin = {
top: 50,
right: 50,
bottom: 50,
left: 50
}
var h = 500 - margin.top - margin.bottom
var w = 500 - margin.left - margin.right
var xScale = d3.scale.linear()
.domain([
d3.min([0, d3.min(data, function(d) {
return d['sepal.length']
})]),
d3.max([0, d3.max(data, function(d) {
return d['sepal.length']
})])
])
.range([0, w])
var yScale = d3.scale.linear()
.domain([
d3.min([0, d3.min(data, function(d) {
return d['sepal.length']
})]),
d3.max([0, d3.max(data, function(d) {
return d['sepal.length']
})])
])
.range([h, 0])
// SVG
var svgContainer = body.append('div').attr('class', 'svg-container')
var svg = svgContainer.append('svg')
.attr('height', h + margin.top + margin.bottom)
.attr('width', w + margin.left + margin.right)
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
// X-axis
var xAxis = d3.svg.axis()
.scale(xScale)
// .tickFormat(formatPercent)
.ticks(6)
.outerTickSize(0)
.tickSize(0)
.orient('bottom')
// Y-axis
var yAxis = d3.svg.axis()
.scale(yScale)
// .tickFormat(formatPercent)
.ticks(6)
.tickSize(-w)
.outerTickSize(0)
.orient('left')
// Circles
var circles = svg.selectAll('circle')
.data(data)
.enter()
.append('circle')
.attr('cx', function(d) {
return xScale(d['sepal.length'])
})
.attr('cy', function(d) {
return yScale(d['sepal.length'])
})
.attr('r', '10')
// .attr('stroke', 'black')
.attr('stroke-width', 0.2)
.attr("fill", function(d) {
return color(cValue(d));
})
.attr('fill-opacity', 0.8)
// .attr('fill', function(d, i) {
// return colorScale(i)
// })
.on('mouseover', function() {
d3.select(this)
.transition()
.duration(300)
.ease('elastic')
.attr('r', 15)
.attr('stroke-width', 1)
.attr('fill-opacity', 1)
})
.on('mouseout', function() {
d3.select(this)
.transition()
.duration(100)
.attr('r', 10)
.attr('stroke-width', 0.5)
})
.append('title') // Tooltip
.text(function(d) {
return d.variety +
'\nSepal Length: ' + d['sepal.length'] +
'\nSepal Width: ' + d['sepal.width'] +
'\nPetal Length: ' + d['petal.length'] +
'\nPetal Width: ' + d['petal.width']
})
// X-axis
svg.append('g')
.attr('class', 'axis')
.attr('id', 'xAxis')
.attr('transform', 'translate(0,' + h + ')')
.call(xAxis)
.append('text') // X-axis Label
.attr('id', 'xAxisLabel')
.attr('y', -25)
.attr('x', w)
.attr('dy', '.71em')
.style('text-anchor', 'end')
.text('Sepal Length')
// labels distance from xaxis
svg.selectAll(".axis text")
.attr("dy", 15);
// Y-axis
svg.append('g')
.attr('class', 'axis')
.attr('id', 'yAxis')
.call(yAxis)
.append('text') // y-axis Label
.attr('id', 'yAxisLabel')
.attr('transform', 'rotate(-90)')
.attr('x', 0)
.attr('y', 5)
.attr('dy', '.71em')
.style('text-anchor', 'end')
.text('Sepal Length')
function yChange() {
var value = this.value // get the new y value
yScale // change the yScale
.domain([
d3.min([0, d3.min(data, function(d) {
return d[value]
})]),
d3.max([0, d3.max(data, function(d) {
return d[value]
})])
])
yAxis.scale(yScale) // change the yScale
d3.select('#yAxis') // redraw the yAxis
.transition().duration(500)
.call(yAxis)
d3.select('#yAxisLabel') // change the yAxisLabel
.text(value)
d3.selectAll('circle') // move the circles
.transition().duration(500)
.delay(function(d, i) {
return i * 10
})
.attr('cy', function(d) {
return yScale(d[value])
})
}
function xChange() {
var value = this.value // get the new x value
xScale // change the xScale
.domain([
d3.min([0, d3.min(data, function(d) {
return d[value]
})]),
d3.max([0, d3.max(data, function(d) {
return d[value]
})])
])
xAxis.scale(xScale) // change the xScale
d3.select('#xAxis') // redraw the xAxis
.transition().duration(500)
.call(xAxis)
d3.select('#xAxisLabel') // change the xAxisLabel
.transition().duration(500)
.text(value)
d3.selectAll('circle') // move the circles
.transition().duration(500)
.delay(function(d, i) {
return i * 10
})
.attr('cx', function(d) {
return xScale(d[value])
})
}
// create legend
var legendContainer = body.append('div')
.attr('class', 'legend-container')
var legend = legendContainer.selectAll(".legend")
.data(color.domain())
.enter().append("div")
.attr("class", "legend")
// draw legend colored rectangles
legend.append("span")
.attr("class", "legend-color")
.style("background-color", color);
// draw legend text
legend.append("span")
.text(function(d) {
return d;
})
})
body {
font-size: 16px;
display: flex;
flex-wrap: wrap;
}
.controls {
flex: 1 1 100%;
}
.legend-container {
align-items: center;
flex: 0 1 auto;
align-self: center;
margin: 0 auto;
}
circle:hover {
fill: orange;
}
.axis text {
font-size: 13px;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
stroke-width: 0.02px;
}
label {
position: absolute;
top: 10px;
right: 10px;
}
.legend {
margin-bottom: 0.5em;
}
.legend-color {
width: 20px;
height: 20px;
display: inline-block;
border-radius: 50%;
vertical-align: middle;
margin-right: 1em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.10/d3.min.js"></script>
<body></body>
使用这种方法,您最终得到的结构如下:
body
.controls
.svg-container
svg
.legend-container
使用CSS可以使响应式布局特别容易。