Я ищу график, который имеет 3 измерения (x, y и z) и использует D3.js.
Пожалуйста, подскажите, есть ли какой-либо сайт по визуализации данных, где я могу найти такой график, или есть на самом сайте d3js.org, где я не смог его найти.
Вот такая вот попытка изобразить перспективу на чистом js+svg:
let f = (x, z) => Math.cos(z/20)*20 + Math.sin(x/10)*10 + x/3*Math.atan2(z,x);
let cos = Math.cos, sin = Math.sin, xyz = 'xyz'.split(''),
k = 500, a1 = 0, a2 = 0, far = 300, p, w, h, a,
points = [], lines = [], s = 100;
for (var x = -s; x < s; x += 5)
for (var z = -s; z < s; z += 5)
points.push({x, z, r:2});
for (var i = 0; i < 6; i++) lines.push([
{x:-s, y:-s, z:-s, color:`hsl(${i*120},55%,55%)`, state:{}},
{x:i%3==0?s:-s, y:i%3==1?s:-s, z:i%3==2?s:-s, state:{}}
]);
points.forEach(d=>d.state={fill:`rgb(${d.x+s},${(d.y=f(d.x,d.z))+s},${d.z+s})`});
pointsGroup.innerHTML=points.map((d,i)=>`<circle ind="${i}"></circle>`).join('');
linesGroup.innerHTML=lines.map(d=>`<path stroke="${d[0].color}"></path>`).join('');
let circles = pointsGroup.querySelectorAll('circle');
let paths = linesGroup.querySelectorAll('path');
function project(p) {
let x = p.x*cos(a1) + p.z*sin(a1);
let z = p.z*cos(a1) - p.x*sin(a1);
let y = p.y*cos(a2) + z*sin(a2);
let d = z*cos(a2) - p.y*sin(a2) + far;
p.state.cx = (k/d)*x + w/2;
p.state.cy = (k/d)*y + h/2;
p.state.r = far/d*p.r;
}
function render() {
if (a) for (var i=0; i<3; i++)
xyz.forEach((c, j) => lines[i][0][c] = i==j ? -s : (lines[i][1]=a)[c]);
points.forEach(project);
points.sort((a, b) => a.state.r - b.state.r);
lines.forEach(line => line.forEach(project));
points.forEach((d, i) => Object.entries(d.state)
.forEach(e => circles[i].setAttribute(...e)));
lines.forEach((l, i) => paths[i].setAttribute('d',
`M${l[0].state.cx} ${l[0].state.cy} L${l[1].state.cx} ${l[1].state.cy}`));
}
let evt = (t, f) => addEventListener(t, e => render(f(e)));
evt('click', e => a = points[e.target.getAttribute('ind')])
evt('wheel', e => k *= 1 - Math.sign(e.deltaY)*0.1);
evt('mouseup', e => p = null);
evt('mousedown', e => p = {x: e.x, y: e.y, a1, a2});
evt('mousemove', e => p && (a1 = p.a1-(e.x-p.x)/100) + (a2 = p.a2-(e.y-p.y)/100));
evt('resize', e=>svg.setAttribute('viewBox',`0 0 ${w=innerWidth} ${h=innerHeight}`));
dispatchEvent(new Event('resize'));
<svg id="svg" stroke-width="2"><g id="pointsGroup"></g><g id="linesGroup"></g></svg>
Почти тот же график, но уже на канве
let f = (x, z) => Math.cos(z/20)*20 + Math.sin(x/10)*10 + x/3*Math.atan2(z,x);
let ctx = canvas.getContext('2d');
let cos = Math.cos, sin = Math.sin, xyz = 'xyz'.split(''),
k = 500, a1 = 0, a2 = 0, far = 300, p, w, h, a,
points = [], lines = [], s = 100;
for (var x = -s; x < s; x += 5)
for (var z = -s; z < s; z += 3)
points.push({x, y: f(x,z), z, r:2, state:{}});
points.forEach(d => d.color = `rgb(${d.x+s},${(d.y=f(d.x,d.z))+s},${d.z+s})`)
for (var i = 0; i < 3; i++) lines.push([
{x:-s, y:-s, z:-s, color:`hsl(${i*120},55%,55%)`, state:{}},
{x:i%3==0?s:-s, y:i%3==1?s:-s, z:i%3==2?s:-s, state:{}}
]);
function project(p) {
let x = p.x*cos(a1) + p.z*sin(a1);
let z = p.z*cos(a1) - p.x*sin(a1);
let y = p.y*cos(a2) + z*sin(a2);
let d = z*cos(a2) - p.y*sin(a2) + far;
p.state.cx = (k/d)*x + w/2;
p.state.cy = (k/d)*y + h/2;
p.state.r = far/d*p.r;
}
function render() {
points.forEach(project);
points.sort((a, b) => a.state.r - b.state.r);
lines.forEach(line => line.forEach(project));
ctx.clearRect(0,0,w,h)
points.forEach(drawPoint);
lines.forEach(drawLine);
}
function drawPoint(p){
ctx.beginPath();
ctx.arc(p.state.cx, p.state.cy, p.state.r, 0, 2 * Math.PI);
ctx.fillStyle = p.color;
ctx.fill();
}
function drawLine(l){
ctx.beginPath();
ctx.moveTo(l[0].state.cx, l[0].state.cy);
ctx.lineTo(l[1].state.cx, l[1].state.cy);
ctx.strokeStyle = l[0].color;
ctx.stroke();
}
let evt = (t, f) => addEventListener(t, e => render(f(e)));
evt('wheel', e => k *= 1 - Math.sign(e.deltaY)*0.1);
evt('mouseup', e => p = null);
evt('mousedown', e => p = {x: e.x, y: e.y, a1, a2});
evt('mousemove', e => p && (a1 = p.a1-(e.x-p.x)/100) + (a2 = p.a2-(e.y-p.y)/100));
evt('resize', e => (w=canvas.width=innerWidth-20)+(h=canvas.height=innerHeight-20));
dispatchEvent(new Event('resize'));
<canvas id="canvas"></canvas>
Трехмерные графики рассеяния, ссылки, на которые даны VividD
и Lars Kotthoff
, вероятно, является лучшим примером того, что вы просите, но я собираюсь предположить, что, возможно, вы задаете не тот вопрос.
Попытка симулировать три пространственных измерения на плоском экране всегда будет несовершенной и затруднит чтение данных.
Однако в D3
очень легко отобразить три разных измерения данных. Допустим,вы используете горизонтальные и вертикальные макеты для двух ваших переменных данных, а затем размер, форму, цвет или затенение для своей третьей переменной.
Если все три ваши переменные данные лучше всего представлены непрерывными числами, тогда лучше всего использовать диаграмму разброса пузырьков, где ваши три измерения отображения - это горизонтальное положение, вертикальное положение и размер пузырька.
Bubble Scatterplot -- click for original
Вы сказали, что ваши три измерения - это Customer
, Product
и content
. Я не знаю, какое значение имеет content
(число или категория), но я почти уверен, что Customer
и Product
- это категории.
Вот пример, где используются два категориальных измерения. Чтобы расположить таблицу, каждая ячейка таблицы содержит круг, измеренный третьим, числовым измерением.
Если ваша третья переменная является категорией, вы можете использовать форму, чтобы указать, какой тип «контента» (если есть) соответствует каждой паре «клиент» и «продукт»:
d3-bubble-matrix
Вот еще одно приложение, где третье измерение показано цветом, а не размером. Цвета представляют непрерывную переменную, но вы можете легко выбрать набор высоко контрастных цветов для представления категорий:
Day / Hour Heatmap
Конечно, простая старая гистограмма с накоплением - это еще один способ показать две категории и числовое значение:
Stacked Bar Graphs
И вам не нужно останавливаться на трех переменных данных. Если две из переменных данных являются категориями или числами, которые вы не возражаете сгруппировать в категории, вы можете построить график четырех переменных с помощью метода «нескольких кратных», где вы создадите таблицу, представляющую категориальные переменные, а затем повторите график две другие переменные внутри каждой ячейки таблицы.
Как здесь:
Scatterplot Matrix
Или это приложение (где неделя и день недели - это два измерения данных, а категория / сумма - два других):
Pie Chart Small Multiples
Я надеюсь, что это дало вам много идей ...
Источник ответа:@AmeliaBR
3D Surface Plot in D3.js
3D Vector Field in D3.js
Источник ответа:@aturc
Вот один пример, который напоминает то, что вы ищете:
3D scatter plot
Обратите внимание, что в этом примере используется X3DOM, довольно новая попытка стандартизировать 3D-рендеринг в HTML, которая поддерживается не всеми браузерами.
Ищите также X3DOM в группе Google D3.
Showing GPS tracks in 3D with three.js and d3.js
В целом, D3.js
больше ориентирован на визуализацию данных, чем на научную визуализацию, это означает, что он не имеет широкой поддержки для отображения трехмерного пространства (за исключением отображения географических 3D-данных, которые D3.js
поддерживает превосходным образом, но это не то, что нужно).
Например (этот пример не связан напрямую с вашими примерами, он просто для пояснения): D3 предоставляет алгоритм для 2D-рисования деревьев, но не предоставляет никакого устройства для 3D-размещения деревьев и последующей визуализации такого размещения на 2D-экране.
Если вы не ограничены D3.js, возможно, вы могли бы достичь тех же целей проще и быстрее с другими библиотеками, написанными специально для целей, аналогичных вашим. Например, вы можете использовать Pre3D
Посмотрите на этот пример не использует X3DOM
, просто рендеринг HTML на 2D-холсте. Я думаю, что анимация - вращение его трехмерных графиков, более плавная, чем в первом примере D3/X3DOM
.
Источник ответа:@VividD
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
подскажите как проверить ширину bar, и если она например меньше нужного значения добавить к этому элементу класс а остальные оставить как...
Пытаюсь сделать минимальный рабочий пример с веб-сокетамиНа стороне сервера использую Spring Framework, клиент - JavaScript
Как сделать, чтобы <input type="datetime-local" > имел максимальное значение даты и времени, сегодняЧерез JS