background

PortLab

CMS per la generazione di portali web dedicati a progetti di ricerca

Funzioni e serie dati

Le serie di func3d nascono da due registri JavaScript: SERIES_FUNCS (funzioni analitiche, file js/local/func3d/series-funcs.js) e SERIES_DATA (dataset numerici, file js/local/func3d/series-data.js). Un modulo ponte (series-bridge.js) registra ogni dataset come "funzione" campionabile tramite un metodo di interpolazione, così superfici analitiche e superfici da dati condividono la stessa pipeline di disegno.

Funzioni analitiche implementate

FunzioneNoteParametri
Sincsin(r)/r, il classico "cappello"
cos(r)/roscillante con singolarità smorzata
Paraboloide ellitticoquadricaa, b
Gaussianacampanaσ
Sella iperbolica quadraticaparaboloide iperbolicoa, b
Cono|r|
Pianoax + by + ca, b, c
Sella linearek·x·yk
Rosenbrockbanana function, banco di prova per l'ottimizzazionea, b
Ackleymoltissimi minimi locali, test per ottimizzatori globalia, b, c
Bessel J0J0(s·r), modi radialis
Ripple 2Dinterferenza di onde in x e yfx, fy
Ondasinusoide 2Da, b
Gobbemassimi e minimi periodicia, b, c
Piramidesuperficie a spigoli
Onda smorzatasinusoide con inviluppokx, ky
Rastriginmultimodale con griglia regolare di minimi (test di ottimizzazione)A
Funzione di Frankeil banco di prova classico dell'interpolazione 2D: due colline, un crinale e una buca
Himmelblauquattro minimi globali identici (test di ottimizzazione)
Membrana circolare (modi)onda stazionaria di un tamburo Jn(s·r)·cos(nθ); la fase la animan, s, fase
Müller‑Brown (PES)superficie di energia potenziale test per i cammini di reazioneVmax
Potenziale di dipoloV = 1/r₊ − 1/r₋ ammorbidito (colormap divergente)separazione, ε

Le superfici chiuse (z a due valori: la pagina disegna automaticamente i rami superiore e inferiore):

FunzioneParametri
Sommità troncaH, R
Iperboloidea

Ellissoide e toroide stavano in questo elenco e adesso sono parametrici (qui sotto). Cucire due rami z(x,y) lungo l'equatore lascia una fessura dove la derivata diverge: alla giunzione i triangoli dei due rami non combaciano e la superficie appare lacerata. In forma parametrica il problema non esiste, perché la maglia è una sola.

Le superfici parametriche (u,v) → (x,y,z): oggetti non esprimibili come z(x,y), disegnati in proporzioni reali con scala uniforme; il colore si può basare sulla quota z oppure sui parametri u/v (select Base colore nella card):

FunzioneNoteParametri
Armoniche sferiche |Ylm|r(θ,φ) = |Ylm|: le forme degli orbitali (u=θ, v=φ)l, m, scala
Orbitale ibrido spⁿr = |ψ|² con ψ = (s + √λ·pz)/√(1+λ): il lobo asimmetrico degli ibridi (λ=1,2,3)λ, scala
Nastro di Möbiusnastro con mezzo giro di torsioneR, w
Toro annodato (p,q)tubo attorno al nodo torico (p,q)p, q, R, r, a
Ellissoidex = a·sinθcosφ, y = b·sinθsinφ, z = c·cosθ (u = θ, v = φ): poli ed equatore pulitia, b, c
Toroidex = (R + r·cos v)·cos u, y = (R + r·cos v)·sin u, z = r·sin vR, r
Bottiglia di Kleinimmersione "a otto": superficie chiusa non orientabileR
Catenoide ↔ Elicoidela famiglia isometrica delle superfici minime, con morphing continuo t=0→1t, c
Superficie di rivoluzioneprofilo r(v) = R + A·sin(k·v) ruotato attorno all'asse zR, A, k

Una voce parametrica dichiara parametric: true, i range dei parametri nei defaults (xMin/xMax = u, yMin/yMax = v), il numero di campioni nU/nV e una build(params) che restituisce (u, v) => [x, y, z]. Per questi oggetti non esistono isolinee, sezione 2D e zScale (non c'è una z(x,y)); l'export CSV fornisce i punti 3D della griglia.

Le curve parametriche t → (x,y,z): una curva non è una superficie sottile, può passare più volte sopra lo stesso punto del piano, e questo un campo di quota non lo sa fare. Il colore segue il parametro t, quindi si legge anche il verso di percorrenza; lo spessore è in pixel reali (fat lines) e i punti non finiti spezzano la linea invece di chiuderla con un segmento inventato:

CurvaNoteParametri
Elica cilindricax = R·cos t, y = R·sin t, z = c·t; il passo è 2πcR, c
Nodo trifoglioil nodo non banale più semplice: una curva chiusa che non si scioglie senza tagliarlaa
Traiettoria di Lorenzintegrazione Runge-Kutta 4 con σ=10, β=8/3 e ρ regolabile; t è il tempoρ, passo

Nella card della serie i campi diventano t iniziale, t finale, Campioni e Spessore linea: modo superficie/wireframe, zScale, isolinee, sezione e classi non compaiono, perché su una curva non vogliono dire nulla. Se in scena non c'è nessuna superficie, i tick degli assi seguono gli estremi della curva.

Questi comandi agiscono in posto: muovere un parametro (il raggio dell'elica, il ρ di Lorenz) ricampiona la curva dentro il gruppo esistente, con la stessa normalizzazione — durante il gesto la scala non balla, e trascinare lo slider diventa un'animazione fluida. Un ricostruire completo (qualsiasi altro comando) rinormalizza sui dati nuovi.

Il piano immagine non è una funzione: è un rettangolo texturizzato su uno dei tre piani coordinati (xy, xz, yz), spostabile lungo la propria normale e ridimensionabile. Serve a mettere una foto, una mappa, una scansione o un fotogramma accanto ai dati — non sopra, come fa il drappeggio. La posizione è espressa, a scelta, in frazioni del riquadro degli assi (−1…1, utile per uno sfondo) oppure in coordinate dati: un rettangolo x0…x1, y0…y1 alla quota z, nelle unità della prima superficie a griglia in scena — il caso dell'ortofoto sul DEM, dove l'immagine deve stare dove stanno i metri. In coordinate dati il rettangolo può non essere quadrato e viene piazzato a fine costruzione, quando la mappatura della superficie di riferimento esiste; senza superficie di riferimento le coordinate si leggono come unità del riquadro. Le immagini disponibili sono quelle del registro (le stesse del drappeggio, vedi sotto).

Dataset di esempio

DatasetTipoContenuto
Ozonogriglia 11×11 (bilineare)campo di concentrazione con scala z ridotta
Tempogriglia temporale, 10 frame 21×21superficie che fluttua nel tempo
Sbuffo avvettatonube temporale [x, y, z, c]nube che si muove, si allarga e si diluisce
Nube rotantenube temporale [x, y, z, c]rotazione rigida con ricircolo
Demo nearest / IDW / bilineare / RBFpunti sparsi o grigliademo dei primi metodi di interpolazione (gli 11 attuali sono tutti selezionabili dalla card)
Demo pointspuntidisegno dei soli punti, senza superficie
Nucleo del calore 2Dgriglia temporale, 16 frame 41×41diffusione pura: gaussiana che si allarga e si abbassa
Lorenz (ensemble)nube temporale, 110 frame × 50 puntiensemble sull'attrattore di Lorenz, colore = velocità; con le traiettorie si vede la divergenza caotica
Vortice di Rankine + pozzocampo vettoriale piano 15×15nucleo in rotazione rigida, esterno potenziale, pozzo radiale
Dipolo magnetico (B)campo vettoriale 3Dlinee di campo di un dipolo con momento lungo z (softening)
Vulcano Maunga Whau (DEM)griglia reale 87×61, passo 10 mil classico dataset "volcano" di R: quote 94–195 m
Vulcano — campione sparso260 punti estratti dal DEM (estrazione fissa)da interpolare (natural, krige, rst…) e confrontare col DEM completo con "Differenza (A − B)"

Aggiungere una funzione analitica (su file)

Una voce di SERIES_FUNCS dichiara etichetta, parametri (con default e limiti per la UI) e la fabbrica build(params) che restituisce la funzione campionabile:

nome_funzione: {
  label: 'La mia funzione',
  params: [
    { name: 'k', label: 'k', type: 'number', step: 0.1, min: 0, max: 10, default: 1.0 }
  ],
  defaults: { xMin: -8, xMax: 8, yMin: -8, yMax: 8, step: 0.3, zScale: 1.0 },
  build: (p) => (x, y) => Math.sin(p.k * x) * Math.cos(p.k * y)
}

Per una superficie chiusa si aggiunge closed: true e la build riceve in params._branch il ramo (+1 superiore, −1 inferiore).

Aggiungere un dataset (su file)

Una voce di SERIES_DATA porta i dati e il metodo con cui campionarli. Punti sparsi in data (righe [x, y, z]) oppure griglie/frame in values:

mio_dataset: {
  label: 'Il mio dataset',
  defaults: {
    xMin: -3, xMax: 3, yMin: -3, yMax: 3, step: 0.15, zScale: 1.0,
    mode: 'surface', colormap: { mode: 'preset', name: 'viridis' }
  },
  method: { name: 'idw', params: { power: 2 } },   // nearest | idw | bilinear | bicubic | lanczos | natural | rbf | rst | bspline | krige | points
  data: [
    [-2, -2, 1.0], [-2, 0, 0.3], [0, 0, 1.0], [2, 2, 0.1]
  ],
  enabled: false,   // true = compare tra le serie all'apertura
  onLoad: false     // true = viene anche plottato subito
}

Varianti:

Aggiungere una curva parametrica o un piano immagine (su file)

Una curva dichiara isCurve: true, l'intervallo del parametro nei defaults (xMin/xMax = t), il numero di campioni nU e una build(params) che restituisce (t) => [x, y, z]:

elica: {
  label: 'Elica cilindrica',
  isCurve: true,
  nU: 800,
  params: [
    { name: 'R', label: 'R (raggio)', type: 'number', step: 0.1, min: 0.1, max: 20, default: 1.0 },
    { name: 'c', label: 'c (passo/2π)', type: 'number', step: 0.05, min: -5, max: 5, default: 0.25 }
  ],
  defaults: { xMin: 0, xMax: 8 * Math.PI, wireWidth: 3, colormap: { mode: 'preset', name: 'turbo' } },
  build: (p) => (t) => [p.R * Math.cos(t), p.R * Math.sin(t), p.c * t]
}

Se la curva non ha forma chiusa (una traiettoria integrata, per esempio) si integra una volta sola dentro build e la funzione restituita legge il risultato per interpolazione: rifare l'integrazione a ogni campione costerebbe O(n²) e darebbe la stessa curva. La traiettoria di Lorenz è scritta così.

Un piano immagine dichiara isImagePlane: true e i tre parametri piano (xy|xz|yz), posizione e copertura; l'immagine si scegle nella card fra quelle del registro. La build non viene usata (resta un segnaposto).

Le colonne in più (dimensioni extra)

Un dato di ricerca ha di solito più di tre colonne: x, y, quota, e poi la concentrazione, la data del rilievo, l'errore di misura, il numero di campione. Le colonne non assegnate a un ruolo nell'import non vengono più buttate: restano accanto ai dati, allineate riga per riga, e compaiono nella select Colora per della card.

// come si presentano nel dataset (import CSV o payload sul database)
{
  id: 'imp_1', label: 'campagna 2026',
  data: [ [x, y, z], ... ],                       // geometria: la quota
  extra: {
    names:  ['concentrazione', 'errore'],
    values: [ [12.4, 0.3], ... ]                  // una riga per punto, nello stesso ordine
  }
}

Scegliendo una di queste grandezze la superficie resta quella della quota e il colore racconta l'altra cosa. Il campo viene interpolato sulla stessa griglia e con lo stesso metodo (vedi Interpolazione): se colore e forma venissero da griglie diverse non parlerebbero degli stessi punti. Dove il campo non è definito il vertice resta grigio, che è diverso dal prendere un colore della scala — quello direbbe un valore che non c'è.

Immagini utente e layer salvati (profilo graph_editor)

Gli utenti col profilo graph_editor (o admin) trovano nel pannello Importa/Esporta due blocchi in più: Le mie immagini — upload personale di immagini da drappeggio (ridimensionate lato client, salvate fuori dal docroot in upload/graph/<utente>/ con quota per utente; nel select delle card compaiono accanto a quelle di sistema) — e Layer salvati — salvataggio su DB della serie selezionata (ricombinabile in altri grafici) o dello snapshot intero del grafico, con nome.

Immagini e layer nascono privati. Accanto a ogni elemento proprio c'è il controllo di condivisione, con la stessa semantica del resto della piattaforma: interruttore spento = privato; acceso senza profili = pubblico; acceso con profili scelti = visibile solo a quelli. Gli elementi condivisi da altri compaiono negli elenchi con l'etichetta condiviso e sono in sola lettura. Le tabelle di gestione dei grafici vivono nello schema graph del DB boot.

L'amministratore fa eccezione: vede tutti i contenuti di tutti gli utenti, compresi quelli privati (identificati dal nome del proprietario), e li può rinominare, ricondividere, sovrascrivere ed eliminare — dalla pagina stessa oppure, con la vista d'insieme di tutti gli utenti, dalla console gest → database → Dati func3d.

Importare da CSV (runtime)

Il pannello Importa/Esporta di func3d costruisce dataset temporanei a partire da CSV/TSV o dagli appunti, con mappatura guidata delle colonne (x, y, z, c, c2, t, gruppo, u, v, w). Sono dataset di sessione: per renderli permanenti si esporta il payload e lo si salva come dataset amministrato dalla console.

Keywords: funzioni, serie dati, dataset, registro, payload, grafici 3D

Moreno Comelli, CNR-IFAC, 2022-2026