Corso: GNU Octave con GX-TXT — Programmazione scientifica e analisi numerica
Framework verificato: GX-TXT 0.9.8.10-dev-112, Release 2, P005
Sorgenti pubblici di riferimento: giuxlab-hub/GX-TXT, maintenance/dev112
Commit di riferimento: 125afdb62110a92199f59a066199bb7f2dc7ed68
Licenza degli script: GPL-3.0-or-later

Obiettivi didattici

In questa lezione utilizzeremo i tre segnali pubblicati nella Lezione 07 per creare due grafici scientifici persistenti all’interno di GX-TXT:

  1. Un grafico cartesiano nel quale vengono sovrapposte tre curve.
  2. Tre pannelli disposti verticalmente, con l’asse temporale X condiviso.

Impareremo inoltre a individuare un errore introdotto intenzionalmente in uno script GNU Octave. Non ci limiteremo a mostrare un messaggio d’errore nel terminale: utilizzeremo il debugger nativo dell’Octave Script Workspace di GX-TXT, impostando un vero breakpoint e osservando lo stack delle chiamate e le variabili locali durante l’esecuzione.

Per costruire i grafici utilizzeremo l’API pubblica Plot Dataset API v4. I dati resteranno nei Dataset canonici della Session, mentre GX-TXT gestirà le rappresentazioni grafiche e le loro varianti persistenti. In questo modo potremo visualizzare gli stessi dati in forme differenti senza duplicarli.

Dalle lezioni precedenti ai nuovi strumenti

Questa esercitazione riprende strumenti già utilizzati nel corso e introduce due argomenti nuovi: il debugging durante l’esecuzione e la costruzione di grafici con più serie e più pannelli. La tabella aiuta a distinguere i prerequisiti da ciò che approfondiremo adesso.

LezioneConoscenze già acquisiteCome vengono utilizzate nella Lezione 08
01–04Variabili, operatori, vettori, condizioni e cicli for.Controlliamo il numero di campioni ed eseguiamo cicli per costruire le serie.
05Dataset ID, Variable ID, struct e cell array.Riferiamo ogni curva a una variabile scientifica e organizziamo pannelli e serie.
06Lettura con read_range e primo grafico a barre con Plot Dataset API v4.Passiamo dal grafico singolo a rappresentazioni con più curve e pannelli.
07Generazione e pubblicazione atomica dei tre segnali sinusoidali.Riutilizziamo i Dataset già pubblicati senza generarli nuovamente.

Non ripartiremo quindi dalla sintassi elementare di Octave. Ci concentreremo su breakpoint, variabili osservate e stack delle chiamate, poi sulla struttura di PlotSpec e sul ciclo di vita dei grafici persistenti.

1. Materiale necessario

Occorrono GX-TXT DEV112-P005, GNU Octave e una Session GX-TXT dedicata alle prove.

I tre Dataset di ingresso sono quelli generati dallo script di pubblicazione atomica della Lezione 07.02:

Dataset IDSegnaleVariable ID XVariable ID Y
lesson07_sine_pureSinusoide a 5 Hz, ampiezza 1,5 Vtime_svoltage_v
lesson07_sine_noisySinusoide a 5 Hz con rumore gaussiano riproducibiletime_svoltage_v
lesson07_sine_harmonicSinusoide a 5 Hz con terza armonica a 15 Hztime_svoltage_v

Ciascun Dataset contiene 801 campioni, relativi all’intervallo da 0 a 2 secondi, con una frequenza di campionamento di 400 campioni al secondo (intervallo fra due punti: 0,0025 s). La deviazione standard del rumore è 0,2 V; l’ampiezza della terza armonica è 0,45 V. Il generatore casuale usato nello script preliminare è inizializzato con il seme 707.

Il numero 801 deriva dal fatto che lo script include sia l’istante iniziale sia quello finale: con 400 intervalli al secondo per 2 secondi si ottengono 800 intervalli, ma 801 punti. È la distinzione fra numero di intervalli e numero di campioni che sfrutteremo nell’esercizio di debugging.

Se questi Dataset non sono ancora presenti, importa L08_00_Prerequisite_L07_Signals.m nell’Octave Script Workspace, assegna uno Script ID univoco, salva lo script nella Session ed eseguilo mediante Run > Open Script Runner…. Il Job dovrà terminare con lo stato COMPLETED. A quel punto, i tre identificativi dovranno comparire nel catalogo dei Dataset della Session.

Il file preliminare riproduce lo script già presentato nella Lezione 07.02. Non modificare né sovrascrivere Dataset esistenti in una Session destinata ad altri esperimenti.

2. Preparare l’Octave Script Workspace

In GX-TXT, apri Viewers > Scientific Scripting > Octave Scripts.

L’editor può mostrare l’Explorer, gli esempi del Bridge GX-TXT, la versione dello script, i parametri, le proprietà e il debugger. Non tutte queste sezioni sono necessarie contemporaneamente.

Durante la preparazione dei grafici:

  • Nascondi GX-TXT Bridge Snippets e Script Explorer dopo aver selezionato lo script registrato.
  • Nascondi le sezioni Script properties, Version e Parameters dopo aver inserito lo Script ID e salvato.
  • Mantieni nascosti Debugger, Call Stack, Variables e Debugger Output finché non inizieremo l’esercizio di debugging.
  • Usa View > API Browser quando vuoi consultare la firma dichiarata di un’API; poi nascondilo, per lasciare più spazio al codice sorgente.

Sono tutte regolazioni della presentazione previste da GX-TXT: non modificano né lo script né i dati scientifici né il CORE del framework.

3. L’errore intenzionale: 800 invece di 801

Per cominciare, importa L08_01_Debug_Exercise_Buggy.m. Assegna uno Script ID univoco nella Session, ad esempio lesson08_intentional_bug, e salva.

Nel codice è presente un errore deliberato:

% The debugger exercise uses this expected sample count.
expected_sample_count = 800; % INTENTIONAL BUG: the source has 801 samples.

Successivamente, lo stesso script legge i dati canonici effettivi e confronta il numero dei campioni ottenuti con quello dichiarato:

block = gxtxt_api_call(dataset_api, 'read_range', ...
                       {source_ids{i}, {'time_s', 'voltage_v'}, 0, 801});

time_s = block.time_s.values(:);
voltage_v = block.voltage_v.values(:);
actual_sample_count = numel(time_s);

if actual_sample_count != expected_sample_count
  error('Expected %d samples but found %d in %s.', ...
        expected_sample_count, actual_sample_count, source_ids{i});
endif

I concetti di Octave

numel(time_s) restituisce il numero totale di elementi del vettore. L’operatore != significa «diverso da» e l’istruzione if ... endif esegue il proprio corpo soltanto quando la condizione è vera: sono costruzioni già incontrate nelle lezioni iniziali. Qui le utilizziamo per controllare la correttezza dei dati letti.

Osserva che lo script legge il Dataset reale: non genera un valore fittizio soltanto per provocare un errore.

L’istruzione block.time_s.values(:) estrae i valori della variabile e li dispone in un vettore colonna; source_ids{i} seleziona l’identificativo del Dataset dalla cell array. Nella chiamata read_range, lo 0 indica invece la prima riga del Dataset: gli indici di lettura di GX-TXT partono da zero, mentre gli indici ordinari di Octave partono da uno, come già visto nella Lezione 06.

Che cosa osserva il debugger

Un debugger permette di sospendere uno script in un punto scelto e di esaminarne lo stato durante l’esecuzione. Un breakpoint è un punto di arresto, non una modifica del calcolo. Una volta raggiunto, possiamo distinguere ciò che lo script si aspettava da ciò che le istruzioni hanno effettivamente prodotto.

StrumentoChe cosa mostraPerché ci serve
BreakpointLa riga alla quale arrestare l’esecuzione.Fermarci prima del controllo che può generare l’errore.
Variables / LocalsI valori delle variabili nel contesto osservato.Confrontare i numeri 800 e 801 senza dedurli dal solo messaggio finale.
Call StackLa sequenza delle chiamate che ha portato al punto corrente.Capire in quale funzione e in quale riga si trova l’esecuzione.
Continue e Step OverRipresa dell’esecuzione o avanzamento oltre una singola istruzione.Verificare quando viene valutata la condizione errata.

Il debugger opera sulla revisione dello script salvata e registrata nella Session. Per questo, prima di avviare il Debug Job, occorre salvare le modifiche: il Job deve eseguire una versione identificabile del codice.

Impostare un vero breakpoint

Nell’editor del codice sorgente, raggiungi la riga 49, che contiene il confronto. Apri Run > Debug Session script…. Seleziona la riga e premi Breakpoint.

Premi Start Debug. GX-TXT avvia un Job di debugging gestito dal framework, interrompe l’esecuzione sul breakpoint e mostra la versione registrata dello script utilizzata dal Job.

Nella sezione Stack and variables, osserva queste due variabili locali:

Variabile localeValore osservato
actual_sample_count801
expected_sample_count800

La differenza permette di individuare il difetto prima che venga sollevata l’eccezione.

Editor GNU Octave di GX-TXT fermo al breakpoint sulla riga 49, durante il confronto tra il numero di campioni attesi e quelli effettivi.
Figura 1 — Un vero breakpoint sulla condizione presente nello script Octave registrato.
Pannello Locals/Globals del debugger GNU Octave con actual_sample_count uguale a 801 ed expected_sample_count uguale a 800.
Figura 2 — I valori delle variabili locali consentono di riconoscere l’errore di programmazione prima dell’eccezione.

Premi Continue. GNU Octave valuta la condizione, che risulta vera, e genera il messaggio:

Expected 800 samples but found 801 in lesson07_sine_pure.

Il Job termina con lo stato FAILED: è il risultato previsto per questo esercizio volutamente errato. Non si tratta di un problema di GX-TXT. L’esecuzione si interrompe prima che venga creato uno qualsiasi dei due grafici scientifici.

Messaggio del debugger GX-TXT che segnala Expected 800 samples but found 801 in lesson07_sine_pure.
Figura 3 — Il debugger segnala l’eccezione intenzionale alla riga 50. Il comando Program output / diagnostics permette di consultare il log conservato dal Job.

Precisazione sul debugger: dopo un errore, uno snapshot etichettato come «last paused» rappresenta i valori osservati nell’ultima pausa, non le variabili ancora attive di una funzione la cui esecuzione è già stata abbandonata.

4. Correggere l’errore

Apri lo script corretto L08_02_Native_Plots_Correct.m. La procedura scientifica è identica, ma questa volta il numero atteso di campioni è quello effettivo:

expected_sample_count = 801;

Utilizziamo due script registrati distinti: uno con l’errore e uno corretto. Questa scelta permette di confrontare i risultati dei due Job e dimostra un principio importante: il debugger si riferisce alla revisione dello script effettivamente eseguita, non a modifiche successive effettuate nell’editor.

Editor GNU Octave di GX-TXT con lo script corretto che imposta expected_sample_count a 801 e utilizza Plot Dataset API v4.
Figura 4 — Lo script corretto nell’Octave Script Workspace di GX-TXT.

5. API pubbliche GX-TXT utilizzate nella lezione

Uno script scientifico deve interagire con la superficie pubblica dello Script Bridge, senza chiamare direttamente procedure Tcl, leggere file privati della Session o richiamare le routine interne di rendering.

5.1 Dichiarare le dipendenze

dataset_api = 'CANONICAL_DATASET_API_v2';
plot_api = 'PLOT_DATASET_API_v4';

gxtxt_api_require({dataset_api, plot_api});

gxtxt_api_require() controlla la disponibilità delle API pubbliche richieste nel contesto dello script gestito dal framework. L’argomento è una cell array, cioè una struttura dati Octave contenente gli identificativi delle API.

Il controllo successivo è più specifico:

required_operations = {'new_spec', 'validate_spec', ...
                       'upsert_plot', 'render', 'artifacts'};
for i = 1:numel(required_operations)
  if !gxtxt_api_has_operation(plot_api, required_operations{i})
    error('Required public plot operation missing: %s', ...
          required_operations{i});
  endif
endfor

gxtxt_api_has_operation(api_id, operation) verifica che una determinata operazione dello Script Bridge sia effettivamente registrata. Conoscere il nome di una famiglia di API non autorizza automaticamente a chiamare una qualsiasi procedura interna.

Per consultare una descrizione più dettagliata delle operazioni effettivamente disponibili, puoi usare gxtxt_api_describe('PLOT_DATASET_API_v4') in uno script gestito, oppure aprire l’API Browser di GX-TXT. I descrittori delle operazioni possono documentare i contratti relativi agli argomenti e ai risultati.

5.2 Consultare un Dataset canonico

available_ids = gxtxt_api_call(dataset_api, 'list', {});
block = gxtxt_api_call(dataset_api, 'read_range', ...
                      {'lesson07_sine_pure', {'time_s','voltage_v'}, ...
                       0, 801});

CANONICAL_DATASET_API_v2 / list restituisce gli identificativi dei Dataset registrati nella Session corrente.

CANONICAL_DATASET_API_v2 / read_range permette di leggere un numero delimitato di righe, specificando i Variable ID stabili. I parametri sono:

  • L’identificativo del Dataset.
  • Una cell array contenente gli identificativi delle variabili da leggere.
  • L’indice della prima riga, che parte da zero.
  • Il numero delle righe richieste.

Il risultato contiene una struttura per ogni variabile selezionata, inclusi i rispettivi values. La lettura non dipende dal percorso di un file CSV né dalla posizione fisica delle colonne.

5.3 Definire un PlotSpec invece di disegnare una figura

overlay = gxtxt_api_call(plot_api, 'new_spec', ...
                         {'plot.dataset.xy', ...
                          'Lesson 08: signal comparison'});

PLOT_DATASET_API_v4 / new_spec crea una specifica dichiarativa iniziale. Il tipo di grafico plot.dataset.xy identifica una rappresentazione cartesiana X/Y.

Il PlotSpec descrive pannelli, assi, serie e opzioni di presentazione. Il contenuto dei Dataset rimane la fonte scientifica autorevole, indipendente dalla sua rappresentazione grafica.

Che cosa contiene un PlotSpec

Un PlotSpec è una descrizione strutturata di come rappresentare dati scientifici già disponibili. Non contiene necessariamente i campioni delle curve: indica quali Dataset e Variable ID utilizzare e come organizzarli. L’API new_spec restituisce una struttura Octave che possiamo completare prima di chiedere il rendering.

ElementoRuolo nella rappresentazione
titleTitolo generale del grafico.
panelsCell array dei pannelli che compongono il grafico.
axesEtichette e scale degli assi di ciascun pannello.
seriesElenco delle curve presenti in un pannello, con i riferimenti ai Dataset.
multi_panelAbilita la disposizione verticale di più pannelli con asse X condiviso.

Questo modello è dichiarativo: prepariamo e validiamo una struttura dati, poi lasciamo a GX-TXT il compito di generare il grafico. È diverso dal disegnare una curva impartendo direttamente una sequenza di comandi grafici a Octave.

Non bisogna confondere la versione dell’API con quella della specifica: Plot Dataset API v4 indica la versione del servizio pubblico utilizzato dallo script, mentre PlotSpec v2 identifica il formato della struttura che descrive il grafico. Sono due versionamenti diversi e compatibili fra loro.

5.4 Il ciclo di vita di un grafico

Operazione pubblicaScopo
new_specCreare una struttura PlotSpec iniziale corretta
validate_specRifiutare specifiche grafiche non valide o incoerenti
upsert_plotCreare o aggiornare un grafico o una variante persistente appartenente allo script, usando una chiave stabile del produttore
renderEseguire il rendering del grafico persistente attraverso il framework
artifactsConsultare i percorsi pubblici e i metadata degli artefatti prodotti

Tutte queste chiamate utilizzano il medesimo punto di ingresso dello Script Bridge:

result = gxtxt_api_call(plot_api, operation, arguments);

Il parametro arguments è una cell array di argomenti posizionali. Lo Script Bridge associa l’operazione pubblica al provider del framework, ne verifica il contratto e restituisce un risultato strutturato.

Grafico persistente, variante e chiave stabile

La Lezione 06 aveva già utilizzato Plot Dataset API v4 per un grafico a barre. Ora ne approfondiamo il comportamento: validate_spec verifica che la descrizione sia coerente, mentre upsert_plot registra la rappresentazione facendo riferimento a una chiave stabile dello script produttore. Se lo stesso script viene rieseguito nella medesima Session, quella chiave permette di aggiornare la rappresentazione associata anziché crearne automaticamente una nuova a ogni esecuzione.

Il risultato di upsert_plot è un riferimento al grafico (usato nelle successive chiamate render e artifacts). Non va confuso con il dataset_id: il primo identifica una rappresentazione, il secondo la sorgente scientifica. Le varianti consentono quindi di conservare viste differenti degli stessi dati. Gli identificativi p0001 e p0002 citati più avanti sono quelli assegnati nella Session dell’esercitazione; in altre Session possono essere diversi.

6. Primo grafico: tre curve sovrapposte

Per ogni curva descriviamo sia la sua identità scientifica sia la modalità con cui deve essere visualizzata:

p.series{i} = struct( ...
    'id', series_ids{i}, ...
    'label', series_labels{i}, ...
    'dataset_id', source_ids{i}, ...
    'x_variable_id', 'time_s', ...
    'y_variable_id', 'voltage_v', ...
    'axis', 'left', ...
    'kind', 'line');

I valori di dataset_id e dei due variable_id non sono semplici etichette. Sono riferimenti a risorse già pubblicate nella Session GX-TXT corrente.

Il campo axis seleziona l’asse Y sinistro e kind='line' richiede una rappresentazione con linee. Il campo label definisce il testo visualizzato in legenda.

Dal punto di vista di Octave, struct(...) costruisce la descrizione di una serie, mentre p.series{i} la inserisce nell’elemento i di una cell array. Le parentesi graffe {} servono ad accedere al contenuto delle celle; l’operatore punto accede invece ai campi delle strutture. Le due forme di accesso, già introdotte nelle Lezioni 05 e 07, qui lavorano insieme.

È utile distinguere tre identità: id è l’identificativo della serie nel grafico; dataset_id individua il Dataset sorgente; x_variable_id e y_variable_id selezionano le due variabili da rappresentare. Infine axis = left associa la serie all’asse Y sinistro, mentre nel campo axes.y_left si configurano le proprietà di quell’asse.

Lo script costruisce tre strutture di questo tipo nello stesso pannello, configura le etichette degli assi, valida il PlotSpec, quindi lo registra e lo renderizza:

if !gxtxt_api_call(plot_api, 'validate_spec', {overlay})
  error('The three-trace overlay PlotSpec failed validation.');
endif

ref_overlay = gxtxt_api_call(plot_api, 'upsert_plot', ...
                             {'lesson08_signal_overlay', overlay});
gxtxt_api_call(plot_api, 'render', {ref_overlay});
artifact_overlay = gxtxt_api_call(plot_api, 'artifacts', {ref_overlay});

Il risultato, la variante grafica GX-TXT p0001, mostra insieme i tre segnali a 5 Hz. La curva rumorosa si riconosce dalle deviazioni irregolari rispetto alla sinusoide ideale; la presenza della terza armonica altera invece la forma dell’onda.

Interfaccia Plots di GX-TXT con tre curve sinusoidali sovrapposte: segnale puro, segnale rumoroso e segnale con terza armonica.
Figura 5 — Tre Dataset canonici sono visualizzati sugli stessi assi. Nella scheda Plots di GX-TXT è selezionato il grafico corrispondente.
Particolare del grafico GX-TXT con tre curve sinusoidali sovrapposte, per confrontare il segnale ideale con rumore e distorsione armonica.
Figura 6 — Il grafico sovrapposto permette di confrontare la sinusoide pura con il segnale rumoroso e quello contenente la terza armonica.

7. Secondo grafico: tre pannelli verticali

Talvolta la sovrapposizione di più curve nasconde differenze importanti. Il modello PlotSpec v2, disponibile attraverso Plot Dataset API v4, supporta anche pannelli sovrapposti verticalmente che condividono l’asse X.

stacked = gxtxt_api_call(plot_api, 'new_spec', ...
                         {'plot.dataset.xy', ...
                          'Lesson 08: stacked panels'});
stacked.multi_panel = 1;
stacked.panels = cell(1, numel(source_ids));

Una cell array, creata con cell, permette di conservare più strutture che descrivono i pannelli. Il ciclo for ne costruisce uno per ciascun segnale scientifico:

Con cell(1, numel(source_ids)) riserviamo uno spazio per ciascuno dei tre pannelli. La preallocazione rende esplicita la dimensione della struttura che riempiremo con il ciclo for, una tecnica già incontrata nella Lezione 07. Ogni pannello possiede un proprio id, un titolo e un elenco di serie.

for i = 1:numel(source_ids)
  panel = struct();
  panel.id = series_ids{i};
  panel.title = panel_titles{i};
  panel.axes = struct( ...
      'x', struct('label', 'Time [s]', 'scale', 'linear'), ...
      'y_left', struct('label', 'Voltage [V]', 'scale', 'linear'));
  panel.annotations = {};
  panel.series = {p.series{i}};
  stacked.panels{i} = panel;
endfor

La distinzione fondamentale è che non pubblichiamo nuovamente i dati. Il secondo PlotSpec descrive una diversa rappresentazione degli stessi identificativi Dataset/Variable già presenti nella Session.

Nella struttura panel.axes, i campi x e y_left contengono a loro volta strutture con label e scale: sono quindi strutture annidate. Assegnare panel.series = {p.series{i}} significa collocare una sola curva nel pannello corrente. Impostando stacked.multi_panel = 1, GX-TXT organizza i pannelli verticalmente: l’asse temporale X è comune, mentre ogni pannello può avere la propria rappresentazione Y.

Validiamo ed eseguiamo il rendering come nel primo caso. Il grafico indipendente ottenuto è la variante p0002.

Interfaccia Plots di GX-TXT con tre pannelli verticali contenenti sinusoide pura, sinusoide rumorosa e sinusoide con terza armonica.
Figura 7 — Tre pannelli distinti mostrano gli stessi segnali con l’asse del tempo condiviso.
Particolare del grafico GX-TXT con tre pannelli verticali che mostrano una sinusoide pura, una rumorosa e una con terza armonica.
Figura 8 — La disposizione verticale consente di osservare separatamente il rumore e le variazioni dovute alla terza armonica.

Quale rappresentazione scegliere?

La sovrapposizione è utile quando vogliamo confrontare i tre segnali allo stesso istante, osservando direttamente le deviazioni rispetto alla sinusoide ideale. I pannelli separati sono più leggibili quando le curve si intersecano o il rumore maschera le differenze di forma. Le due rappresentazioni non cambiano i valori dei Dataset: cambia soltanto il modo in cui vengono osservati.

8. Esercizi

  1. Modifica il titolo generale del grafico con le curve sovrapposte e osserva come l’aggiornamento interessi la stessa variante grafica persistente.
  2. Cambia l’etichetta di legenda di una delle curve; verifica che il Dataset ID e i Variable ID della sorgente non siano stati modificati.
  3. Confronta la rappresentazione sovrapposta con quella a tre pannelli. Quale permette di riconoscere meglio il rumore gaussiano? Quale evidenzia maggiormente la terza armonica?
  4. Imposta un breakpoint sull’istruzione actual_sample_count = numel(time_s); ed esegui un Step Over. Osserva come cambia il valore della variabile.
  5. Ripristina l’errore intenzionale impostando il valore 800, esegui il solo esercizio di debugging in una Session di prova e poi correggilo nuovamente.

9. Errori comuni

«Missing Dataset» indica che la Lezione 07.02 non è stata eseguita nella Session corrente oppure che gli identificativi dei Dataset di origine sono differenti. Non sostituire silenziosamente un Dataset scientifico mancante con un array numerico creato nello script.

«Missing public plot operation» indica che la dichiarazione richiesta dallo Script Bridge, oppure il relativo modulo, non è disponibile nel contesto attivo del framework e dello script.

«Expected 800 samples but found 801» è l’errore introdotto appositamente nella prima versione. La correzione prevista consiste nell’impostare a 801 il numero di campioni attesi.

«Invalid Variable ID» indica che un riferimento non corrisponde a un descrittore di variabile realmente presente nel Dataset della Session. Occorre consultare lo schema canonico, anziché dedurre gli identificativi dalle posizioni delle colonne.

10. Materiale della lezione

La lezione riunisce i due livelli dell’esercitazione: con GNU Octave organizziamo le strutture, controlliamo i dati e costruiamo le specifiche del grafico; attraverso le API pubbliche, GX-TXT consulta i Dataset canonici e conserva le rappresentazioni grafiche persistenti nella Session.

Riferimenti ai sorgenti pubblici

Limite di validazione: questa lezione è stata verificata su DEV112-P005. Le revisioni successive pubblicate su GitHub potrebbero modificare elementi dell’interfaccia o introdurre nuove operazioni pubbliche: per questo viene indicato il commit esatto di riferimento.

#analisi dati #breakpoint #debugger #debugging Octave #GNU Octave #grafici scientifici #GX-TXT #Plot Dataset API v4 #programmazione scientifica #Script Workspace #tutorial Octave #visualizzazione dati

Altre tappe del progetto

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *