// 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 #include #include #include 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 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 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 nodes = { {"premium"}, {"basicos"}, {"laptops"}, {"phones"}, {"tablets"}, {"hardware"}, {"software"}, {"servicios"}, }; std::vector 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 nodes = {{\"premium\"}, {\"basicos\"}, ...};\n" "std::vector 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