#javascript #svg #d3.js
#javascript #svg #d3.js
Вопрос:
Для изучения того, как использовать d3.js , я пытался использовать набор данных titanic для обучения, доступный на kaggle.
Я пытаюсь достичь цели:
-
Создайте диаграмму рассеяния возраста и тарифа с возрастом по оси x и тарифом по оси y
-
Используйте столбец пола, чтобы на диаграмме рассеяния мужчина был квадратным, а женщина — кругами
-
Имейте непрозрачность, чтобы указать условие — выжил или не выжил.
Я использовал следующий код:
// set the dimensions and margins of the graph
var margin = {
top: 10,
right: 30,
bottom: 30,
left: 60
},
width = 460 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
// append the svg object to the body of the page
var svg = d3.select("#my_dataviz")
.append("svg")
.attr("width", width margin.left margin.right)
.attr("height", height margin.top margin.bottom)
.append("g")
.attr("transform",
"translate(" margin.left "," margin.top ")");
//Read the data
d3.csv("https://gist.githubusercontent.com/michhar/2dfd2de0d4f8727f873422c5d959fff5/raw/fa71405126017e6a37bea592440b4bee94bf7b9e/titanic.csv", function(data) {
// Add X axis
var x = d3.scaleLinear()
.domain([0, 80])
.range([0, width]);
svg.append("g")
.attr("transform", "translate(0," height ")")
.call(d3.axisBottom(x));
// Add Y axis
var y = d3.scaleLinear()
.domain([0, 600])
.range([height, 0]);
svg.append("g")
.call(d3.axisLeft(y));
// Add dots
svg.append('g')
.selectAll("dot")
.data(data)
.enter()
.append("circle")
.attr("cx", function(d) {
return x(d.age);
})
.attr("cy", function(d) {
return y(d.fare);
})
.attr("r", 1.5)
.style("fill", "#69b3a2")
})
<script src="https://d3js.org/d3.v4.js"></script>
<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>
Условие, которое я хочу реализовать, это:
if(d.sex == "female"){
return d3.symbolCircle;
} else if (d.sex == "male"){
return d3.symbolSquare;
}
Но, будучи абсолютным новичком в синтаксисе, я не понимаю, как это сделать. Кроме того, как иметь два цвета для 3-й цели указания выжившего против мертвого.
Кто-нибудь может мне помочь, пожалуйста. Я действительно заранее благодарю вас.
В случае, если у вас нет набора данных, его также можно найти здесь.
Ответ №1:
Во-первых, вам нужно посмотреть на свои данные. Все ваши свойства указаны в верхнем регистре, а чтение CSV-файла всегда означает, что вам нужно проанализировать ваши строки: числа и даты по-прежнему являются строками, вам нужно использовать их как таковые:
// set the dimensions and margins of the graph
var margin = {
top: 10,
right: 30,
bottom: 30,
left: 60
},
width = 460 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
// append the svg object to the body of the page
var svg = d3.select("#my_dataviz")
.append("svg")
.attr("width", width margin.left margin.right)
.attr("height", height margin.top margin.bottom)
.append("g")
.attr("transform",
"translate(" margin.left "," margin.top ")");
//Read the data
d3.csv("https://gist.githubusercontent.com/michhar/2dfd2de0d4f8727f873422c5d959fff5/raw/fa71405126017e6a37bea592440b4bee94bf7b9e/titanic.csv", function(rawData) {
// All values are strings here, so we need to parse some of them.
// You can do that using ` x` or `Number(x)`, where `x = "123"`
const data = rawData.map(function(d) {
return {
age: Number(d.Age),
// cabin: d.Cabin,
// embarked: e.Embarked,
fare: Number(d.Fare),
// name: d.Name,
// parch: Number(d.Parch),
// passengerId: Number(d.PassengerId)
// pclass: Number(Pclass),
sex: d.Sex,
// sibSp: Number(d.SibSp),
survived: d.Survived === "1"
// ticket: d.Ticket,
};
});
// Add X axis
var x = d3.scaleLinear()
.domain([0, 80])
.range([0, width]);
svg.append("g")
.attr("transform", "translate(0," height ")")
.call(d3.axisBottom(x));
// Add Y axis
var y = d3.scaleLinear()
.domain([0, 600])
.range([height, 0]);
svg.append("g")
.call(d3.axisLeft(y));
// Add dots
svg.append('g')
.selectAll("dot")
.data(data)
.enter()
.append("circle")
.attr("cx", function(d) {
return x(d.age);
})
.attr("cy", function(d) {
return y(d.fare);
})
.attr("r", 1.5)
.style("fill", "#69b3a2")
})
<script src="https://d3js.org/d3.v4.js"></script>
<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>
Во-вторых, круги могут быть только кругами. Чтобы рисовать как квадраты, так и круги, вам нужно использовать <path>
. Вы d3.symbol*
были правы, но вам нужно получить доступ к их .draw()
функции. d3.path
это генератор, позволяющий легко нарисовать d
атрибут пути:
// set the dimensions and margins of the graph
var margin = {
top: 10,
right: 30,
bottom: 30,
left: 60
},
width = 460 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
// append the svg object to the body of the page
var svg = d3.select("#my_dataviz")
.append("svg")
.attr("width", width margin.left margin.right)
.attr("height", height margin.top margin.bottom)
.append("g")
.attr("transform",
"translate(" margin.left "," margin.top ")");
//Read the data
d3.csv("https://gist.githubusercontent.com/michhar/2dfd2de0d4f8727f873422c5d959fff5/raw/fa71405126017e6a37bea592440b4bee94bf7b9e/titanic.csv", function(rawData) {
// All values are strings here, so we need to parse some of them.
// You can do that using ` x` or `Number(x)`, where `x = "123"`
const data = rawData.map(function(d) {
return {
age: Number(d.Age),
// cabin: d.Cabin,
// embarked: e.Embarked,
fare: Number(d.Fare),
// name: d.Name,
// parch: Number(d.Parch),
// passengerId: Number(d.PassengerId)
// pclass: Number(Pclass),
sex: d.Sex,
// sibSp: Number(d.SibSp),
survived: d.Survived === "1"
// ticket: d.Ticket,
};
});
// Add X axis
var x = d3.scaleLinear()
.domain([0, 80])
.range([0, width]);
svg.append("g")
.attr("transform", "translate(0," height ")")
.call(d3.axisBottom(x));
// Add Y axis
var y = d3.scaleLinear()
.domain([0, 600])
.range([height, 0]);
svg.append("g")
.call(d3.axisLeft(y));
// Add dots
svg.append('g')
.selectAll("path")
.data(data)
.enter()
.append("path")
.attr("transform", function(d) {
return "translate(" [x(d.age), y(d.fare)] ")";
})
.attr("d", function(d) {
const path = d3.path();
const shape = d.sex == "female" ? d3.symbolCircle : d3.symbolSquare;
shape.draw(path, 8);
return path.toString();
})
.style("fill", "#69b3a2")
})
<script src="https://d3js.org/d3.v4.js"></script>
<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>
(Кроме того, вы также могли бы нарисовать rect
s для обоих, но учитывая, что женские закругленные углы с rx
атрибутом).
Наконец, вы можете использовать цветовую шкалу для заливки с d3.scaleOrdinal
помощью , но если у вас есть только два цвета и вы не используете ее для окрашивания нескольких объектов (например, линейной диаграммы и легенды), просто используйте оператор if:
// set the dimensions and margins of the graph
var margin = {
top: 10,
right: 30,
bottom: 30,
left: 60
},
width = 460 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
// append the svg object to the body of the page
var svg = d3.select("#my_dataviz")
.append("svg")
.attr("width", width margin.left margin.right)
.attr("height", height margin.top margin.bottom)
.append("g")
.attr("transform",
"translate(" margin.left "," margin.top ")");
//Read the data
d3.csv("https://gist.githubusercontent.com/michhar/2dfd2de0d4f8727f873422c5d959fff5/raw/fa71405126017e6a37bea592440b4bee94bf7b9e/titanic.csv", function(rawData) {
// All values are strings here, so we need to parse some of them.
// You can do that using ` x` or `Number(x)`, where `x = "123"`
const data = rawData.map(function(d) {
return {
age: Number(d.Age),
// cabin: d.Cabin,
// embarked: e.Embarked,
fare: Number(d.Fare),
// name: d.Name,
// parch: Number(d.Parch),
// passengerId: Number(d.PassengerId)
// pclass: Number(Pclass),
sex: d.Sex,
// sibSp: Number(d.SibSp),
survived: d.Survived === "1"
// ticket: d.Ticket,
};
});
// Add X axis
var x = d3.scaleLinear()
.domain([0, 80])
.range([0, width]);
svg.append("g")
.attr("transform", "translate(0," height ")")
.call(d3.axisBottom(x));
// Add Y axis
var y = d3.scaleLinear()
.domain([0, 600])
.range([height, 0]);
svg.append("g")
.call(d3.axisLeft(y));
// Add dots
svg.append('g')
.selectAll("path")
.data(data)
.enter()
.append("path")
.attr("transform", function(d) {
return "translate(" [x(d.age), y(d.fare)] ")";
})
.attr("d", function(d) {
const path = d3.path();
const shape = d.sex == "female" ? d3.symbolCircle : d3.symbolSquare;
shape.draw(path, 8);
return path.toString();
})
.style("fill", function(d) {
return d.survived ? "#69b3a2" : "#ddd";
})
})
<script src="https://d3js.org/d3.v4.js"></script>
<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>
Комментарии:
1. Спасибо за вашу помощь. Я хотел спросить еще одну вещь: в style мы устанавливаем «заливку» для цвета, но я прочитал и обнаружил, что непрозрачность отличается от цвета. Если мы хотим заменить заливку непрозрачностью, можем ли мы продолжить с той же логикой?
2. Да, вы можете использовать любой атрибут. Для непрозрачности вам нужно вернуть число от 0 до 1. В SVG у вас есть
opacity
, но также более конкретныеfill-opacity
иstroke-opacity
. Посмотрите, что вам нужно3. Большое спасибо. Итак, концепция непрозрачности подобна вероятности, имеющей значение от 0 до 1.
4. Да, 0 — это кусок стекла, 1 — кирпичная стена
Ответ №2:
Одна интересная вещь в SVG заключается в том, что a <rect>
с атрибутами rx
and ry
, равными половине его ширины или высоты (они, конечно, одинаковы), фактически становится кругом.
Итак, предположим, у вас есть
var diameter = 3;
Все, что вам нужно, это:
.attr("rx", function(d) {
return d.Sex === "male" ? 0 : diameter / 2
})
.attr("ry", function(d) {
return d.Sex === "male" ? 0 : diameter / 2
})
И, конечно, вычтите позиции x
и y
на половину диаметра (т. Е. Радиуса).
Это похоже на взлом, но преимущество такого подхода заключается в том, что довольно легко перейти от квадрата к «кругу», просто изменив значения rx / ry (можно переходить по путям, но это немного сложнее). Взгляните на этот переход с преувеличенным радиусом и ограниченным доменом:
// set the dimensions and margins of the graph
var margin = {
top: 10,
right: 30,
bottom: 10,
left: 60
},
width = 660 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var diameter = 12;
// append the svg object to the body of the page
var svg = d3.select("#my_dataviz")
.append("svg")
.attr("width", width margin.left margin.right)
.attr("height", height margin.top margin.bottom)
.append("g")
.attr("transform",
"translate(" margin.left "," margin.top ")");
//Read the data
d3.csv("https://gist.githubusercontent.com/michhar/2dfd2de0d4f8727f873422c5d959fff5/raw/fa71405126017e6a37bea592440b4bee94bf7b9e/titanic.csv", row, function(data) {
// Add X axis
var x = d3.scaleLinear()
.domain([0, 80])
.range([0, width]);
svg.append("g")
.attr("transform", "translate(0," height ")")
.call(d3.axisBottom(x));
// Add Y axis
var y = d3.scaleLinear()
.domain([0, 300])
.range([height, 0]);
svg.append("g")
.call(d3.axisLeft(y));
// Add dots
svg.append('g')
.selectAll("dot")
.data(data)
.enter()
.append("rect")
.attr("x", function(d) {
return x(d.Age) - diameter / 2;
})
.attr("y", function(d) {
return y(d.Fare) - diameter / 2;
})
.attr("width", diameter)
.attr("height", diameter)
.style("fill", "#69b3a2")
.transition()
.duration(2000)
.attr("rx", function(d) {
return d.Sex === "male" ? 0 : diameter / 2
})
.attr("ry", function(d) {
return d.Sex === "male" ? 0 : diameter / 2
})
.style("fill", function(d) {
return d.Survived ? "#69b3a2" : "tan"
});
})
function row(d) {
d.Age = d.Age;
d.Fare = d.Fare;
return d;
}
<script src="https://d3js.org/d3.v4.js"></script>
<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>
Комментарии:
1. Спасибо за вашу помощь. Я хотел спросить еще одну вещь: в style мы устанавливаем «заливку» для цвета, но я прочитал и обнаружил, что непрозрачность отличается от цвета. Если мы хотим заменить заливку непрозрачностью, можем ли мы продолжить с той же логикой, если мы используем то же условие изменения непрозрачности в соответствии с выжившим или нет?
2. @KC да, вы можете.