Я опенсорснул grafar — свою библиотеку для визуализации. Основная часть кода написана в 2013–2016 годах для моего диплома. Следующие 5 лет проект пролежал в столе — я был не вполне доволен АПИ, было много классных функций, которые я мог добавить, работа засасывала, и ещё тысяча причин не выпускать его пока, ну вы знаете. В конце концов, на свете есть столько людей поумнее меня, и они точно придумают что-то получше, правда же?

На прошлой неделе мне на глаза снова попался этот прекрасный код, пылящийся на гитхабе — я подумал, что это всё еще выглядит классно, и, уверен, сэкономит кому-нибудь кучу времени. Так что я снабдил проект документацией мирового класса, обновил сборку и запустил хайп-режим.

Буду честен — это первый публичный релиз графара. В нём, скорее всего, есть баги, и я не могу пообещать полную стабильность АПИ навсегда. Но всё же я уверен, что вам стоит обратить внимание на графар, и вот почему:

Простое API. Всего 10 строк кода — и вы построили поверхность прямо в браузере. API заточено на работу с математическими объектами — кривыми, поверхностями, точками — и использует остроумную модель топологии объектов, чтобы все работало как ожидается.

Эффективная работа с большими массивами данных. Я залез по уши в кеш-локальность, инлайинг и кодогенерацию, чтобы вычисления происходили настолько быстро, насколько возможно, и получается неплохо — 1 миллион точек на среднем железе анимируется с 30FPS. WebGL позаботится о том, чтобы эти данные быстро отрисовались.

У нас еcть 3D и 2D. Спасибо ThreeJS, любой график можно построить в интерактивном 3D — я не знаю других библиотек, в которых это было бы так просто. Но можно строить графики и в 2D, не выходя из привычной модели.

Реактивная интерактивность. Grafar — библиотека для интерактивной визуализации с реактивными вычислениями (чем-то похоже на MobX). Библиотека сама запоминает зависимости ваших отображений, и при изменении пересчитывает только то, что правда изменилось.

Строим параметрическую поверхность

Посмотрим, как просто построить график параметрической поверхности, на примере винтовой поверхности. Можете играть с примером в codesandbox.

Поверхность — объект с двумя степенями свободы. Создадим по параметру для каждой из них:

const p = grafar.range(-2, 2, 500).select();
const q = grafar.range(0, 1, 2).select();

Каждая из переменных моделирует отрезок ([-2, 2] для p, [0, 1] для q) числовым массивом и знает, что при отрисовке соседние точки нужно соединить.

Теперь отобразим параметры в декартовы координаты (x,y,z):

const xp = grafar.map([p, q], (p, q) => Math.cos(8 * p) * q);
const yp = grafar.map([p, q], (p, q) => Math.sin(8 * p) * q);

В этот момент происходит две интересных вещи. Во-первых, графар догадывается, что p и q — независимые переменные, и вызывает функцию для каждого сочетания точек в них. Во-вторых, графар запоминает зависимости xp и yp — если мы изменим p или q, xp и yp автоматически обновятся.

Наконец, остается построить сам график — для этого мы создаём панель и прикрепляем данные на неё:

const container = document.getElementById("app");
const panel = grafar.panel(container);
grafar.pin([xp, yp, p], panel);

Вот что мы получаем за 7 строк кода:


Конечно, параметрические поверхности — не всё, что умеет grafar. Вот несколько других примеров:

Я планирую развивать функции для визуализации данных. Это более широкая ниша, чем математическая визуализация, но библиотеки для нее страдают от тех же проблем. При этом паттерны работы с данными отличаются — нужно будет поддержать динамические размеры таблиц, добавить хелперы для импорта данных и дискретную фильтрацию.

Если вас заинтересовала библиотека, посмотрите документацию (пока только на английском). На гитхабе доступен полный код библиотеки. В ишьюс можно пожаловаться на баг, запросить фичу или даже поучаствовать в разработке (мне не помешает помощь).

В любом случае, надеюсь, вам было интересно. Удачи с графиками!