Как делаются красивые цветные графики и диаграммы?

Как делаются красивые цветные графики и диаграммы?

Сегодня я расскажу о том, как можно сделать цветные диаграммы или графики. По сути, это просто трехмерные графики в двумерном виде.

Кстати, у меня есть замечательная школа математики для программистов – Академия вектозавров. Первую, бесплатную, главу пройти обязательно всем! :)

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



А мне хотелось добиться примерно такого результата:



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

Способ представления цвета. Система RGB и HEX


Начнём с того, как мы будем представлять цвет. Самыми популярными форматами хранения цветов является RGB (Red, Green, Blue) и HTML таблица цветов. Нам будет удобнее работать с форматом RGB. RGB – это аддитивная модель хранения цвета с помощью трех основных цветов. Выбор основных цветов, вообще то говоря, произвольный. Красный, зелёный и желтый выбраны из-за наших особенностей восприятия цвета. На каждый цвет приходится по одному байту (число от \(0\) до \(255\)). С помощью \(3\)х байт таким способом удастся закодировать \(256*256*256 = 16777216\) цветов! Такого количества оттенков хватает с головой для любых целей.



По сути, цвета в RGB – это трёхмерные векторы:

$$
Color = [a_1, a_2, a_3]
$$
Где \(a_1, a_2\) и \(a_3\) – это оттенки красного, зелёного и синего цветов соответственно, суть числа от \(0\) до \(255\).
HTML таблица цветов предлагает способ хранения в виде шестнадцатеричных чисел. Между цветами одной системы и другой есть правило перевода (Существует биективное отображение).

Принцип сопоставления цветов с числами


Нам нужен такой алгоритм, который бы принимал число от нуля до единицы (нормированный параметр), а возвращал соответствующий цвет. Для того, чтобы понять, как построить такой алгоритм нужно просто посмотреть на весь спектр цветов и понять, как меняются числа \(a_1, a_2\) и \(a_3\):




Видно, что чтобы пройтись по всем цветам нужно поочередно непрерывно изменять компоненты \([a_1, a_2, a_3]\) вектора цвета.

В зависимости от того, какой параметр дан на вход возвращаем нужный цвет:



function color_interpolate(progress) {
var result_color = [0, 0, 255]; // Вектор цвета RGB

if((progress <= 0) || (progress >= 1)) // Случаи, когда параметр меньше 0 или больше 1
return (progress <= 0) ? "rgb(0,0,255)" : "rgb(255,0,0)";

if(progress < 0.25) // Синий -> Голубой
result_color = [0, (progress/0.25)*255, 255];
else if(progress < 0.5) // Голубой -> Зелёный
result_color = [0, 255, 255*(1-(progress-0.25)/0.25)];
else if(progress < 0.75) // Зелёный -> Жёлтый
result_color = [255*(progress-0.5)/0.25, 255, 0];
else // Жёлтый -> Красный
result_color = [255, 255*(1-(progress-0.75)/0.25), 0];

return "rgb(" + result_color[0]
+ "," + result_color[1]
+ "," + result_color[2] + ")"; // Возвращаем готовый цвет
}

Можно уменьшить функцию color_interpolate, если последовательно изменять цвет - начнем с синего цвета и доберёмся до нужного:



function color_interpolate(progress) {
var result_color = [0, 0, 255];

if((progress <= 0) || (progress >= 1))
return (progress <= 0) ? "rgb(0,0,255)" : "rgb(255,0,0)";

for(var i = 0; progress > (i+1)/4; i++)
result_color[(i+1)%3] = (i%2 == 0) ? 255 : 0;

result_color[(i+1)%3] = (i%2 == 0) ? (4*progress - i)*255 : (1 + i-4*progress)*255;
return "rgb(" + result_color[0]
+ "," + result_color[1]
+ "," + result_color[2] + ")";
}

То же самое, но на C++:



std::vector<int> colorInterpolate(double progress) {
std::vector<int> result_color = {0, 0, 255};
if((progress <= 0) || (progress >= 1))
return (progress <= 0) ? result_color : std::vector<int>{255,0,0};
int i = 0;
for(i = 0; progress > (double)(i+1)/4; i++)
result_color[(i+1)%3] = (i%2 == 0) ? 255 : 0;
result_color[(i+1)%3] = (i%2 == 0) ? (4*progress - i)*255 : (1 + i-4*progress)*255;

return result_color;
}

Теперь протестируем полученную функцию на примерах.

Примеры использования


Для начала построим графики некоторых функций.
Функция
$$
z = x+y
$$
будет выглядеть следующим образом:




Как и следовало ожидать мы получили простой градиент.
Попробуем что-нибудь поинтереснее:



$$
z = cos\left(\frac{10x}{y}\right)
$$



$$
z = cos(sin(cos(xy)y))
$$



$$
z = cos(x sin(y cos(xy)))
$$



$$
z = sin\left(\frac{x}{y}\right) sin\left(\frac{y}{x}\right)
$$



$$
z = sin(x) + sin(y)
$$



$$
z = sin(x) cos(sin(x) y)
$$



$$
z = \frac{sin(x)}{sin(y)}
$$




Кулоновский потенциал заряда выражается следующим образом:

$$
\varphi = \frac{q}{r}
$$
Имея распределение зарядов можно посчитать потенциал во всех точках:



Черными линиями обозначены направления электрического поля (силовые линии). Если проводить замкнутые кривые, перпендикулярные силовым линиям в каждой точке, мы получим так называемые эквипотенциали (линии вдоль которых потенциал не меняется, а значит цвет остаётся постоянным)


Друзья! Я очень благодарен вам за то, что вы интересуетесь моими работами, ведь каждый пост на сайте даётся очень непросто. Я буду рад любому отклику и поддержке с вашей стороны.







Если у вас остались вопросы или пожелания, то вы можете оставить комментарий (регистрироваться не нужно)

__xXx_Nagibator_3000_xXx__:

Проблемы с вёрсткой на мобиле, видимо, будут всегда. Наверное, это тот ещё геморрой. Некоторые числа и формулы, а также блоки кода имеют очень маленький шрифт по сравнению с текстом.
А так норм тема, полезно
P.S: ещё мне кажется, что можно устроить инъекцию кода через комментарии, но я, конечно же, это доказывать не буду
-------------------------------------------
У меня там "инновационные" mysql_real_escape_string стоят, должно сработать говорили С:


Дата: 22-01-2019 в 22:57

GreyKey:

Сделайте страницу на github'e, со всеми вашими успешными програмами. Как и вам, так и вашим читателям это пойдет на пользу. С уважением грейкей


Дата: 23-01-2019 в 17:15

Анонимно:

Привет, подскажи, пожалуйста, как ты через функции получал такие графики? Например Z = x + y. Я не могу понять как ты ее реализовал.


Дата: 02-04-2020 в 18:16

Анонимно:

привет


Дата: 18-11-2020 в 20:18


Мои курсовые | 30.11.2019: Выложил мои курсовые в открытый доступ. Теперь они отображаются в колонке слева под новостями.

Для будущих авторов | 12.10.18: Если вы хотите стать автором статей на сайте и получить подтвержденный аккаунт, то обращайтесь на почту! support@ilinblog.ru

Обновления | 21.08.18: Добавлена возможность комментировать статьи. Сайт адаптирован под мобильные устройства.

Обновления | 19.01.18: Добавлена возможность добавления математических формул в статьи посредством языка latex. Пример использования тут. Также добавлена возможность редактирования статей.

Информация о пользователях | 28.10.17: Расширена функциональность страницы пользователей, теперь можно добавить статус и личную информацию.

Мои статьи и исследования:

Измерение спектра квантовой эффективности полупроводникового фотокатода на основе арсенида галлия (курсовая)
Исследование индукционного метания цилиндрических проводников импульсным магнитным полем (курсовая)
Броуновское движение
Температура и методы её измерения
Исследование механики движения мячей