#d3.js
#d3.js
Вопрос:
Я пытаюсь очень быстро освоить d3, и я сильно зацикливаюсь на выборе и объединении.
Я хочу иметь возможность рисовать ось с точками для каждого элемента массива. Некоторые элементы массива имеют одинаковое значение x, но я все равно хочу видеть столько точек, сколько есть с этим значением. Мой массив (в реакции с useState) выглядит так:
const [data, setData] = useState(
[
{x: 2020, colour: "purple", y1: 0.001, y2: 0.63},
{x: 2027, colour: "red", y1: 0.003, y2: 0.84},
{x: 2031, colour: "yellow", y1: 0.024, y2: 0.56},
{x: 2031, colour: "green", y1: 0.054, y2: 0.22},
{x: 2040, colour: "blue", y1: 0.062, y2: 0.15},
{x: 2050, colour: "orange", y1: 0.062, y2: 0.15}
]
);
Вы можете видеть, что для 2031 есть два значения, и я хочу нарисовать желтую точку, затем фиолетовую точку ниже, на галочке оси x с надписью «2031».
Итак, я группирую свои данные с помощью этой функции уменьшения (украденной из SO):
const dot = data.reduce(
(r, v, _, __, k = v.x) => ((r[k] || (r[k] = [])).push(v), r),
{}
);
… что приводит к этому:
{ 2020: [{x: 2020, colour: "purple", y1: 0.001, y2: 0.63}],
2027: [...] }
Я инициирую свою ось x и создаю для нее заполнитель:
const g = d3.axisBottom( scX ).tickValues(
data.map(d => {
return d.x
})
)
svg.append( "g" )
.attr( "transform", "translate(" 25 "," pxY/2 ")")
.call( g )
.selectAll(".tick")
И затем я хочу вызвать свою переменную dot и выполнить итерацию по вложенным массивам:
svg
.selectAll(".tick")
.call( dot )
.append("circle")
.attr("cx", 0)
.attr("cy", 0)
.attr("r", 5)
.attr("fill", dot.colour)
Что я хотел бы сделать, так это нарисовать круг для каждого из вложенных массивов с заливкой цвета, указанного в этом массиве — это не работает?
Кто-нибудь может объяснить?
Ответ №1:
Нет необходимости группировать ваши данные. Вы можете просто видеть data
как массив, где каждый элемент будет соответствовать одному кругу. Может существовать несколько кругов с одинаковым x
значением, ничто не гарантирует, что они не могут.
Также нет необходимости устанавливать такие тики оси, d3, скорее всего, сделает все за вас. d3-axis
это абсолютное удобство — вы должны настраивать значения по умолчанию, а не создавать все с нуля.
Вам нужно узнать о соединениях данных, поскольку вы, по-видимому, также не знаете, что вы можете получить доступ к данным элемента, используя function(d, i) { ... }
или (d, i) => ...
для установки цвета таким образом.
const data = [{
x: 2020,
colour: "purple",
y1: 0.001,
y2: 0.63
},
{
x: 2027,
colour: "red",
y1: 0.003,
y2: 0.84
},
{
x: 2031,
colour: "yellow",
y1: 0.024,
y2: 0.56
},
{
x: 2031,
colour: "green",
y1: 0.054,
y2: 0.22
},
{
x: 2040,
colour: "blue",
y1: 0.062,
y2: 0.15
},
{
x: 2050,
colour: "orange",
y1: 0.062,
y2: 0.15
}
];
const width = 600,
height = 300;
var svg = d3.select("svg")
.attr("width", width)
.attr("height", height);
const x = d3.scaleLinear()
.domain(d3.extent(data, d => d.x))
.range([50, 550]);
const y1 = d3.scaleLinear()
.domain(d3.extent(data, d => d.y1))
.range([275, 25]);
const y2 = d3.scaleLinear()
.domain(d3.extent(data, d => d.y2))
.range([3, 10]);
svg.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("fill", d => d.colour)
.attr("cx", d => x(d.x))
.attr("cy", d => y1(d.y1))
.attr("r", d => y2(d.y2));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg></svg>