---
name: samples_to_grid_2d
kind: function
lang: cpp
domain: datascience
version: "1.0.0"
purity: pure
signature: "void samples_to_grid_2d_counts(const double* x, const double* y, size_t n, double xmin, double xmax, double ymin, double ymax, int nx, int ny, unsigned int* out_counts); void samples_to_grid_2d_density(...float* out_density); void counts_to_density(const unsigned int* counts, int nx, int ny, float* out_density)"
description: "Binning 2D CPU para alimentar heatmap_cpp_viz / contour_cpp_viz / surface_plot_3d desde un set de samples (x[], y[]). Variante counts (uint, acumulable) y density (float [0,1] normalizado a max). Pareja CPU del gpu_histogram_2d."
tags: [binning, histogram_2d, density, heatmap, contour, datascience, pendiente-usar]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: ""
imports: [cstddef, cmath, vector]
tested: false
tests: []
test_file_path: ""
file_path: "cpp/functions/datascience/samples_to_grid_2d.cpp"
params:
  - name: samples_x
    desc: "Array de coordenadas X de los samples."
  - name: samples_y
    desc: "Array de coordenadas Y de los samples."
  - name: n
    desc: "Numero de samples (longitud de samples_x y samples_y)."
  - name: xmin
    desc: "Limite inferior X. Samples con x fuera de [xmin, xmax) se descartan."
  - name: xmax
    desc: "Limite superior X."
  - name: ymin
    desc: "Limite inferior Y."
  - name: ymax
    desc: "Limite superior Y."
  - name: nx
    desc: "Bins en X."
  - name: ny
    desc: "Bins en Y."
  - name: out_counts
    desc: "Buffer destino unsigned int[nx*ny] row-major (idx = y*nx + x). NO se inicializa: el caller decide si poner a cero (acumular sobre llamadas previas)."
  - name: out_density
    desc: "Buffer destino float[nx*ny] normalizado a max=1.0. Variante density auto-rellena."
  - name: counts
    desc: "(counts_to_density) input uint[nx*ny]."
output: "out_counts incrementado con los conteos; out_density normalizado [0, 1]. Si todos los counts son 0, density se llena con 0."
---

# samples_to_grid_2d

Binning 2D para densidades de muestras (joint posteriors, walks 2D, scatter density). Versión CPU canónica — usar GPU `gpu_histogram_2d` cuando los samples ya viven en GPU.

## Patron tipico (mcmc-visualizer / mcmc-full)

```cpp
constexpr int NX = 128, NY = 128;
std::vector<float> density(NX * NY);

fn::ds::samples_to_grid_2d_density(
    chain_x.data(), chain_y.data(), chain_x.size(),
    -5.0, 5.0, -5.0, 5.0,
    NX, NY,
    density.data()
);

fn::viz::heatmap(density.data(), NX, NY, /*...*/);
```

## Acumulado a lo largo de iteraciones

Para visualizar la cadena creciendo en vivo sin recomputar todo:

```cpp
std::vector<unsigned int> counts(NX * NY, 0u);

// Cada iteracion del MCMC:
fn::ds::samples_to_grid_2d_counts(
    new_x.data(), new_y.data(), new_x.size(),
    -5.0, 5.0, -5.0, 5.0,
    NX, NY,
    counts.data()                 // sigue acumulando
);

std::vector<float> density(NX * NY);
fn::ds::counts_to_density(counts.data(), NX, NY, density.data());
fn::viz::heatmap(density.data(), NX, NY, /*...*/);
```

## Notas

- Samples fuera del rango `[xmin, xmax) x [ymin, ymax)` se descartan, no se clampean. Si quieres clamp, pre-clamp los samples antes de llamar.
- O(n) sobre samples + O(nx*ny) para to_density. Para n = 10^7, nx=ny=256: ~70 ms CPU. Para refresh interactivo a 60 FPS, downsample a n=10^5 o usar la version GPU.
- Layout row-major idx = y*nx + x — coincide con lo que esperan `heatmap_cpp_viz` y `contour_cpp_viz`.
