209 lines
7.2 KiB
C++
209 lines
7.2 KiB
C++
// demos_scientific.cpp — demos para los 5 charts cientificos del issue 0034:
|
|
// treemap, sankey, chord, contour, voronoi.
|
|
|
|
#include "demos.h"
|
|
#include "demo.h"
|
|
|
|
#include "viz/treemap.h"
|
|
#include "viz/sankey.h"
|
|
#include "viz/chord.h"
|
|
#include "viz/contour.h"
|
|
#include "viz/voronoi.h"
|
|
|
|
#include <imgui.h>
|
|
#include <cmath>
|
|
#include <cstdlib>
|
|
#include <vector>
|
|
|
|
namespace gallery {
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// treemap
|
|
// ---------------------------------------------------------------------------
|
|
|
|
void demo_treemap() {
|
|
demo_header("treemap", "v1.0.0",
|
|
"Squarified treemap (Bruls et al.) para jerarquias planas con valores. "
|
|
"Algoritmo puro separado del render.");
|
|
|
|
section("Gastos por categoria");
|
|
{
|
|
std::vector<TreemapItem> items = {
|
|
{"vivienda", 950.0f, IM_COL32(180, 120, 200, 255)},
|
|
{"comida", 320.0f, IM_COL32(120, 180, 200, 255)},
|
|
{"transporte", 180.0f, IM_COL32(200, 180, 120, 255)},
|
|
{"ocio", 140.0f, IM_COL32(200, 120, 160, 255)},
|
|
{"salud", 90.0f, IM_COL32(120, 200, 160, 255)},
|
|
{"otros", 60.0f, IM_COL32(160, 160, 200, 255)},
|
|
};
|
|
treemap("##gastos", items, ImVec2(-1, 320));
|
|
}
|
|
|
|
code_block(
|
|
"std::vector<TreemapItem> items = {\n"
|
|
" {\"vivienda\", 950.0f, IM_COL32(180,120,200,255)},\n"
|
|
" {\"comida\", 320.0f, IM_COL32(120,180,200,255)},\n"
|
|
" ...\n"
|
|
"};\n"
|
|
"treemap(\"##gastos\", items, ImVec2(-1, 320));"
|
|
);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// sankey
|
|
// ---------------------------------------------------------------------------
|
|
|
|
void demo_sankey() {
|
|
demo_header("sankey", "v1.0.0",
|
|
"Sankey diagram para flujos source -> target. BFS topologico para columnas, "
|
|
"bandas curvas (bezier cubico) para los links. Asume DAG.");
|
|
|
|
section("Clientes -> productos -> categorias");
|
|
{
|
|
std::vector<SankeyNode> nodes = {
|
|
{"premium"}, {"basicos"},
|
|
{"laptops"}, {"phones"}, {"tablets"},
|
|
{"hardware"}, {"software"}, {"servicios"},
|
|
};
|
|
std::vector<SankeyLink> links = {
|
|
// clientes -> productos
|
|
{0, 2, 80}, {0, 3, 30}, {0, 4, 15},
|
|
{1, 3, 60}, {1, 4, 40}, {1, 2, 20},
|
|
// productos -> categorias
|
|
{2, 5, 70}, {2, 6, 30},
|
|
{3, 5, 50}, {3, 7, 40},
|
|
{4, 6, 35}, {4, 7, 20},
|
|
};
|
|
sankey("##flow", nodes, links, ImVec2(-1, 360));
|
|
}
|
|
|
|
code_block(
|
|
"std::vector<SankeyNode> nodes = {{\"premium\"}, {\"basicos\"}, ...};\n"
|
|
"std::vector<SankeyLink> links = {{0, 2, 80}, {0, 3, 30}, ...};\n"
|
|
"sankey(\"##flow\", nodes, links, ImVec2(-1, 360));"
|
|
);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// chord
|
|
// ---------------------------------------------------------------------------
|
|
|
|
void demo_chord() {
|
|
demo_header("chord", "v1.0.0",
|
|
"Chord diagram para matrices NxN. Arcos proporcionales a sum(row) + cuerdas "
|
|
"internas con bezier cubico.");
|
|
|
|
section("Flujos entre paises (matriz 6x6 simetrica)");
|
|
{
|
|
constexpr int N = 6;
|
|
// simetrica de "comercio" entre 6 paises
|
|
static float M[N * N] = {
|
|
0, 10, 6, 12, 4, 3,
|
|
10, 0, 14, 3, 8, 2,
|
|
6, 14, 0, 9, 11, 5,
|
|
12, 3, 9, 0, 7, 6,
|
|
4, 8, 11, 7, 0, 13,
|
|
3, 2, 5, 6, 13, 0,
|
|
};
|
|
static const char* labels[N] = {"ESP", "FRA", "ITA", "DEU", "PRT", "GBR"};
|
|
chord("##chord", M, N, labels, ImVec2(420, 420));
|
|
}
|
|
|
|
code_block(
|
|
"float M[N*N] = { // simetrica\n"
|
|
" 0, 10, 6, 12, 4, 3,\n"
|
|
" 10, 0, 14, 3, 8, 2,\n"
|
|
" ...\n"
|
|
"};\n"
|
|
"const char* labels[6] = {\"ESP\",\"FRA\",\"ITA\",\"DEU\",\"PRT\",\"GBR\"};\n"
|
|
"chord(\"##c\", M, 6, labels);"
|
|
);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// contour
|
|
// ---------------------------------------------------------------------------
|
|
|
|
void demo_contour() {
|
|
demo_header("contour", "v1.0.0",
|
|
"Contour plot 2D via marching squares. Para una gaussiana centrada los "
|
|
"contornos resultantes son aproximadamente concentricos.");
|
|
|
|
constexpr int N = 32;
|
|
static float grid[N * N];
|
|
static bool init = false;
|
|
if (!init) {
|
|
// Mezcla de 2 gaussianas (peak central + secundario)
|
|
for (int y = 0; y < N; y++) {
|
|
for (int x = 0; x < N; x++) {
|
|
float dx1 = x - N * 0.45f, dy1 = y - N * 0.5f;
|
|
float dx2 = x - N * 0.75f, dy2 = y - N * 0.3f;
|
|
float v = std::exp(-(dx1 * dx1 + dy1 * dy1) / 70.0f)
|
|
+ 0.55f * std::exp(-(dx2 * dx2 + dy2 * dy2) / 30.0f);
|
|
grid[y * N + x] = v;
|
|
}
|
|
}
|
|
init = true;
|
|
}
|
|
static const float levels[] = {0.15f, 0.30f, 0.50f, 0.70f, 0.90f};
|
|
contour("##gauss", grid, N, N, levels, 5, ImVec2(-1, 320));
|
|
|
|
code_block(
|
|
"constexpr int N = 32;\n"
|
|
"float grid[N*N];\n"
|
|
"for (int y = 0; y < N; y++)\n"
|
|
" for (int x = 0; x < N; x++) {\n"
|
|
" float dx = x - N/2.0f, dy = y - N/2.0f;\n"
|
|
" grid[y*N + x] = std::exp(-(dx*dx + dy*dy) / 80.0f);\n"
|
|
" }\n"
|
|
"float levels[] = {0.15f, 0.30f, 0.50f, 0.70f, 0.90f};\n"
|
|
"contour(\"##gauss\", grid, N, N, levels, 5);"
|
|
);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// voronoi
|
|
// ---------------------------------------------------------------------------
|
|
|
|
void demo_voronoi() {
|
|
demo_header("voronoi", "v1.0.0",
|
|
"Diagrama de Voronoi via raster brute-force (MVP). Tiles 4x4 px coloreados "
|
|
"por el seed mas cercano. Suficiente para N <= 200.");
|
|
|
|
constexpr int N = 30;
|
|
static ImVec2 seeds [N];
|
|
static ImU32 colors[N];
|
|
static bool init = false;
|
|
if (!init) {
|
|
unsigned seed = 7;
|
|
auto rnd = [&]() {
|
|
seed = seed * 1103515245u + 12345u;
|
|
return (float)((seed >> 16) & 0x7fff) / 32768.0f;
|
|
};
|
|
// El render escala automaticamente; las posiciones se asumen en coords del rect.
|
|
// Como no sabemos W/H aqui, usamos coords aproximadas para 600x300 y el clip
|
|
// dentro de voronoi se encarga de mantenerlas en rango.
|
|
for (int i = 0; i < N; i++) {
|
|
seeds [i] = ImVec2(rnd() * 600.0f, rnd() * 300.0f);
|
|
colors[i] = IM_COL32(40 + (int)(rnd() * 200),
|
|
40 + (int)(rnd() * 200),
|
|
60 + (int)(rnd() * 195),
|
|
230);
|
|
}
|
|
init = true;
|
|
}
|
|
voronoi("##v", seeds, N, colors, ImVec2(-1, 300));
|
|
|
|
code_block(
|
|
"ImVec2 seeds[30];\n"
|
|
"ImU32 colors[30];\n"
|
|
"for (int i = 0; i < 30; i++) {\n"
|
|
" seeds [i] = ImVec2(rnd() * 600.0f, rnd() * 300.0f);\n"
|
|
" colors[i] = IM_COL32(rnd_byte(), rnd_byte(), rnd_byte(), 230);\n"
|
|
"}\n"
|
|
"voronoi(\"##v\", seeds, 30, colors, ImVec2(-1, 300));"
|
|
);
|
|
}
|
|
|
|
} // namespace gallery
|