Parte 2: Hello Channels¶
Traduzione assistita da IA - scopri di più e suggerisci miglioramenti
Guardate l'intera playlist sul canale YouTube di Nextflow.
La trascrizione del video è disponibile qui.
Nella Parte 1 di questo corso (Hello World), vi abbiamo mostrato come fornire un input variabile a un processo passandolo direttamente nella chiamata al processo: sayHello(params.input).
Quello era un approccio volutamente semplificato.
In pratica, quell'approccio ha limitazioni importanti; in particolare, funziona solo per casi molto semplici in cui vogliamo eseguire il processo una sola volta, su un singolo valore.
Nella maggior parte dei casi d'uso realistici dei flussi di lavoro, vogliamo elaborare più valori (dati sperimentali per più campioni, per esempio), quindi abbiamo bisogno di un modo più sofisticato per gestire gli input.
Ecco a cosa servono i canali di Nextflow. I canali sono code progettate per gestire gli input in modo efficiente e trasferirli da un passaggio all'altro nei flussi di lavoro multi-step, fornendo al contempo parallelismo integrato e molti altri vantaggi.
In questa parte del corso, imparerete come utilizzare un canale per gestire più input da diverse fonti. Imparerete anche a utilizzare gli operatori per trasformare i contenuti dei canali secondo necessità.
Come iniziare da questa sezione
Questa sezione del corso presuppone che abbiate completato la Parte 1 del corso Hello Nextflow, ma se avete familiarità con i concetti base trattati in quella sezione, potete iniziare da qui senza fare nulla di speciale.
0. Riscaldamento: Eseguire hello-channels.nf¶
Useremo lo script del flusso di lavoro hello-channels.nf come punto di partenza.
È equivalente allo script prodotto seguendo la Parte 1 di questo corso di formazione, tranne che abbiamo cambiato la destinazione dell'output:
Solo per assicurarci che tutto funzioni, eseguite lo script una volta prima di apportare modifiche:
Output del comando
Come in precedenza, troverete il file di output chiamato output.txt nella directory results/hello_channels (come specificato nel blocco output dello script del flusso di lavoro, mostrato sopra).
Contenuto della directory
Se tutto ha funzionato, siete pronti a imparare i canali.
1. Fornire input variabili tramite un canale esplicitamente¶
Creeremo un canale per passare l'input variabile al processo sayHello() invece di affidarci alla gestione implicita, che ha alcune limitazioni.
1.1. Creare un canale di input¶
Esistono diverse fabbriche di canali che possiamo usare per configurare un canale.
Per mantenere le cose semplici per ora, useremo la fabbrica di canali più basilare, chiamata channel.of, che creerà un canale contenente un singolo valore.
Funzionalmente sarà simile a come lo avevamo configurato prima, ma invece di far creare a Nextflow un canale implicitamente, ora lo stiamo facendo esplicitamente.
Questa è la riga di codice che useremo:
Questo crea un canale chiamato greeting_ch usando la fabbrica di canali channel.of(), che configura un semplice canale di coda, e carica la stringa 'Hello Channels!' da usare come valore di saluto.
Nota
Stiamo temporaneamente tornando alle stringhe hardcoded invece di usare un parametro CLI per motivi di leggibilità. Torneremo a usare i parametri CLI una volta che avremo spiegato cosa succede a livello di canale.
Nel blocco workflow, aggiungete il codice della fabbrica di canali:
Questo non è ancora funzionale poiché non abbiamo ancora cambiato l'input nella chiamata al processo.
1.2. Aggiungere il canale come input alla chiamata del processo¶
Ora dobbiamo effettivamente collegare il nostro canale appena creato alla chiamata del processo sayHello(), sostituendo il parametro CLI che fornivamo direttamente prima.
Nel blocco workflow, effettuate la seguente modifica al codice:
Questo dice a Nextflow di eseguire il processo sayHello sui contenuti del canale greeting_ch.
Ora il nostro flusso di lavoro è correttamente funzionale; è l'equivalente esplicito di scrivere sayHello('Hello Channels!').
1.3. Eseguire il flusso di lavoro¶
Eseguiamolo!
Output del comando
Se avete effettuato entrambe le modifiche correttamente, dovreste ottenere un'esecuzione riuscita. Potete controllare la directory dei risultati per verificare che l'output sia ancora lo stesso di prima.
Quindi abbiamo aumentato la flessibilità del nostro flusso di lavoro ottenendo lo stesso risultato finale. Questo può sembrare scrivere più codice senza un beneficio tangibile, ma il valore diventerà chiaro non appena inizieremo a gestire più input.
Come anteprima, vediamo un'altra cosa prima di procedere: un piccolo ma conveniente vantaggio dell'uso di un canale esplicito per gestire l'input dei dati.
1.4. Usare view() per ispezionare i contenuti del canale¶
I canali di Nextflow sono costruiti in modo da permetterci di operare sui loro contenuti usando operatori, che tratteremo in dettaglio più avanti in questo capitolo.
Per ora, vi mostreremo semplicemente come usare un operatore super semplice chiamato view() per ispezionare i contenuti di un canale.
Potete pensare a view() come uno strumento di debug, come un'istruzione print() in Python, o il suo equivalente in altri linguaggi.
Aggiungete questa piccola riga al blocco workflow:
La quantità esatta di spazi non importa purché sia un multiplo di 4; stiamo solo cercando di allineare l'inizio dell'istruzione .view() alla parte .of() della costruzione del canale.
Ora eseguite di nuovo il flusso di lavoro:
Output del comando
Come potete vedere, questo mostra i contenuti del canale sulla console. Qui abbiamo solo un elemento, ma quando inizieremo a caricare più valori nel canale nella prossima sezione, vedrete che questo è impostato per mostrare un elemento per riga.
Takeaway¶
Sapete come usare una fabbrica di canali di base per fornire un input a un processo.
Cosa c'è dopo?¶
Imparate come usare i canali per far iterare il flusso di lavoro su più valori di input.
2. Modificare il flusso di lavoro per eseguire su più valori di input¶
I flussi di lavoro tipicamente vengono eseguiti su lotti di input che devono essere elaborati in blocco, quindi vogliamo aggiornare il flusso di lavoro per accettare più valori di input.
2.1. Caricare più saluti nel canale di input¶
Convenientemente, la fabbrica di canali channel.of() che abbiamo usato è perfettamente in grado di accettare più di un valore, quindi non abbiamo bisogno di modificarla affatto.
Possiamo semplicemente caricare più valori nel canale.
Usiamo 'Hello', 'Bonjour' e 'Holà'.
2.1.1. Aggiungere più saluti¶
Prima del blocco workflow, effettuate la seguente modifica al codice:
La documentazione ci dice che questo dovrebbe funzionare. Può davvero essere così semplice?
2.1.2. Eseguire il comando e guardare l'output del log¶
Proviamo.
Output del comando
Sembra certamente che abbia funzionato correttamente.
Il monitor di esecuzione mostra che sono state effettuate 3 of 3 chiamate per il processo sayHello, e vediamo i tre saluti elencati dall'istruzione view(), uno per riga come promesso.
Tuttavia, c'è ancora un solo output nella directory dei risultati:
Contenuto della directory
Dovreste vedere uno dei tre saluti lì dentro, ma quello che avete ottenuto potrebbe essere diverso da quello mostrato qui. Riuscite a pensare al motivo?
Nel diagramma, il canale è rappresentato in verde, e l'ordine degli elementi è rappresentato come biglie in un tubo: il primo caricato è a destra, poi il secondo al centro, poi il terzo è a sinistra.
Guardando indietro al monitor di esecuzione, ci ha dato solo un percorso di sottodirectory (f4/c9962c).
Diamo un'occhiata lì dentro.
Contenuto della directory
Questo non è nemmeno lo stesso saluto che abbiamo ottenuto nella directory dei risultati! Cosa sta succedendo?
A questo punto, dobbiamo dirvi che per impostazione predefinita, il sistema di logging ANSI scrive il logging di più chiamate allo stesso processo sulla stessa riga. Quindi lo stato di tutte e tre le chiamate al processo sayHello() finiscono nello stesso punto.
Fortunatamente, possiamo disabilitare quel comportamento per vedere l'elenco completo delle chiamate ai processi.
2.1.3. Eseguire di nuovo il comando con l'opzione -ansi-log false¶
Per espandere il logging e visualizzare una riga per chiamata di processo, aggiungete -ansi-log false al comando.
Output del comando
Questa volta vediamo tutte e tre le esecuzioni dei processi e le loro sottodirectory di lavoro associate elencate nell'output.
Molto meglio, almeno per un flusso di lavoro semplice.
Per un flusso di lavoro complesso, o un grande numero di input, avere l'elenco completo in output sul terminale diventerebbe un po' opprimente.
Ecco perché -ansi-log false non è il comportamento predefinito.
Suggerimento
Il modo in cui viene riportato lo stato è un po' diverso tra le due modalità di logging. Nella modalità condensata, Nextflow riporta se le chiamate sono state completate con successo o meno. In questa modalità espansa, riporta solo che sono state inviate.
Comunque, ora che abbiamo le sottodirectory di ogni chiamata di processo, possiamo cercare i loro log e output.
Contenuto della directory
work/23/871c7ec3642a898ecd5e6090d21300/
├── .command.begin
├── .command.err
├── .command.log
├── .command.out
├── .command.run
├── .command.sh
├── .exitcode
└── output.txt
Contenuto del file
Questo mostra che tutti e tre i processi sono stati eseguiti con successo (evviva).
Detto questo, abbiamo ancora il problema che c'è un solo file di output nella directory dei risultati.
Potete ricordare che abbiamo hardcodato il nome del file di output per il processo sayHello, quindi tutte e tre le chiamate hanno prodotto un file chiamato output.txt.
Finché i file di output rimangono nelle sottodirectory di lavoro, isolati dagli altri processi, va bene. Ma quando vengono pubblicati nella stessa directory dei risultati, quello che viene copiato per primo viene sovrascritto dal successivo, e così via.
2.2. Assicurarsi che i nomi dei file di output siano unici¶
Possiamo continuare a pubblicare tutti gli output nella stessa directory dei risultati, ma dobbiamo assicurarci che abbiano nomi unici. Nello specifico, dobbiamo modificare il primo processo per generare un nome di file dinamicamente in modo che i nomi dei file finali siano unici.
Quindi come rendiamo i nomi dei file unici? Un modo comune per farlo è usare qualche pezzo unico di metadati dagli input (ricevuti dal canale di input) come parte del nome del file di output. Qui, per comodità, useremo semplicemente il saluto stesso poiché è solo una stringa corta, e lo anteporremo al nome base del file di output.
2.2.1. Costruire un nome di file di output dinamico¶
Nel blocco process, effettuate le seguenti modifiche al codice:
Assicuratevi di sostituire output.txt sia nella definizione dell'output che nel blocco del comando script:.
Suggerimento
Nella definizione dell'output, DEVE usare le virgolette doppie attorno all'espressione del nome del file (NON le virgolette singole), altrimenti fallirà.
Questo dovrebbe produrre un nome di file di output unico ogni volta che il processo viene chiamato, in modo che possa essere distinto dagli output di altre chiamate allo stesso processo nella directory di output.
2.2.2. Eseguire il flusso di lavoro¶
Eseguiamolo. Nota che siamo tornati a eseguire con le impostazioni predefinite del log ANSI.
Output del comando
Tornando alla vista riassuntiva, l'output è di nuovo riassunto su una riga.
Date un'occhiata alla directory results per vedere se tutti i saluti di output sono presenti.
Contenuto della directory
Sì! E ognuno ha i contenuti attesi.
Successo! Ora possiamo aggiungere quanti saluti vogliamo senza preoccuparci che i file di output vengano sovrascritti.
Suggerimento
In pratica, nominare i file basandosi sui dati di input stessi è quasi sempre poco pratico. Il modo migliore per generare nomi di file dinamici è passare metadati a un processo insieme ai file di input. I metadati sono tipicamente forniti tramite un 'sample sheet' o equivalenti. Imparerete come farlo più avanti nella vostra formazione su Nextflow (vedete la side quest sui metadati).
Takeaway¶
Sapete come fornire più elementi di input attraverso un canale.
Cosa c'è dopo?¶
Imparate a usare un operatore per trasformare i contenuti di un canale.
3. Fornire più input tramite un array¶
Vi abbiamo appena mostrato come gestire più elementi di input che erano hardcodati direttamente nella fabbrica di canali. E se volessimo fornire questi input multipli in modo diverso?
Per esempio, immaginate di configurare una variabile di input contenente un array di elementi come questo:
greetings_array = ['Hello','Bonjour','Holà']
Possiamo caricarla nel nostro canale di output e aspettarci che funzioni?
Scopriamolo.
3.1. Fornire un array di valori come input al canale¶
Il buon senso suggerisce che dovremmo essere in grado di passare semplicemente un array di valori invece di un singolo valore. Proviamo; dovremo configurare la variabile di input e caricarla nella fabbrica di canali.
3.1.1. Configurare la variabile di input¶
Prendiamo la variabile greetings_array che abbiamo appena immaginato e rendiamola realtà aggiungendola al blocco workflow:
| hello-channels.nf | |
|---|---|
Questo non è ancora funzionale, abbiamo solo aggiunto una dichiarazione per l'array.
3.1.2. Impostare l'array di saluti come input alla fabbrica di canali¶
Ora sostituiremo i valori 'Hello','Bonjour','Holà' attualmente hardcodati nella fabbrica di canali con il greetings_array che abbiamo appena creato.
Nel blocco workflow, effettuate la seguente modifica:
| hello-channels.nf | |
|---|---|
| hello-channels.nf | |
|---|---|
Questo dovrebbe essere funzionale ora.
3.1.3. Eseguire il flusso di lavoro¶
Proviamo a eseguirlo:
Output del comando
N E X T F L O W ~ version 25.10.2
Launching `hello-channels.nf` [friendly_koch] DSL2 - revision: 97256837a7
executor > local (1)
[a8/1f6ead] sayHello (1) | 0 of 1
[Hello, Bonjour, Holà]
ERROR ~ Error executing process > 'sayHello (1)'
Caused by:
Missing output file(s) `[Hello, Bonjour, Holà]-output.txt` expected by process `sayHello (1)`
Command executed:
echo '[Hello, Bonjour, Holà]' > '[Hello, Bonjour, Holà]-output.txt'
Command exit status:
0
Command output:
(empty)
Work dir:
/workspaces/training/hello-nextflow/work/a8/1f6ead5f3fa30a3c508e2e7cf83ffb
Tip: you can replicate the issue by changing to the process work dir and entering the command `bash .command.run`
-- Check '.nextflow.log' file for details
Oh no! C'è un errore!
Guardate l'output di view() e i messaggi di errore.
Sembra che Nextflow abbia provato a eseguire una singola chiamata di processo, usando [Hello, Bonjour, Holà] come valore stringa, invece di usare le tre stringhe nell'array come valori separati.
Quindi è il 'confezionamento' che sta causando il problema. Come facciamo a far sì che Nextflow spacchetti l'array e carichi le singole stringhe nel canale?
3.2. Usare un operatore per trasformare i contenuti del canale¶
Qui entrano in gioco gli operatori.
Avete già usato l'operatore .view(), che semplicemente guarda cosa c'è dentro.
Ora vedremo operatori che ci permettono di agire sui contenuti di un canale.
Se scorrete la lista degli operatori nella documentazione di Nextflow, troverete flatten(), che fa esattamente ciò di cui abbiamo bisogno: spacchetta i contenuti di un array e li emette come elementi individuali.
3.2.1. Aggiungere l'operatore flatten()¶
Per applicare l'operatore flatten() al nostro canale di input, lo aggiungiamo alla dichiarazione della fabbrica di canali.
Nel blocco workflow, effettuate la seguente modifica al codice:
| hello-channels.nf | |
|---|---|
| hello-channels.nf | |
|---|---|
Qui abbiamo aggiunto l'operatore sulla riga successiva per leggibilità, ma potete aggiungere operatori sulla stessa riga della fabbrica di canali se preferite, così:
greeting_ch = channel.of(greetings_array).view().flatten()
3.2.2. Affinare le istruzioni view()¶
Potremmo eseguirlo subito per testare se funziona, ma già che ci siamo, affineremo come ispezioniamo i contenuti del canale.
Vogliamo poter confrontare come appaiono i contenuti prima e dopo l'applicazione dell'operatore flatten(), quindi ne aggiungeremo un secondo, E aggiungeremo un po' di codice per etichettarli più chiaramente nell'output.
Nel blocco workflow, effettuate la seguente modifica al codice:
| hello-channels.nf | |
|---|---|
Vedete che abbiamo aggiunto una seconda istruzione .view, e per ciascuna di esse, abbiamo sostituito le parentesi vuote (()) con parentesi graffe contenenti del codice, come { greeting -> "Prima di flatten: $greeting" }.
Queste si chiamano closure. Il codice che contengono verrà eseguito per ogni elemento nel canale.
Definiamo una variabile temporanea per il valore interno, qui chiamata greeting (ma potrebbe essere qualsiasi nome arbitrario), che viene usata solo nell'ambito di quella closure.
In questo esempio, $greeting rappresenta ogni singolo elemento caricato nel canale.
Questo risulterà in un output della console ordinatamente etichettato.
Info
In alcune pipeline potrete vedere una variabile speciale chiamata $it usata all'interno delle closure degli operatori.
Questa è una variabile implicita che permette un accesso abbreviato alla variabile interna,
senza doverla definire con un ->.
Preferiamo essere espliciti per aiutare la chiarezza del codice, quindi la sintassi $it è sconsigliata e sarà gradualmente eliminata dal linguaggio Nextflow.
3.2.3. Eseguire il flusso di lavoro¶
Finalmente, potete provare a eseguire di nuovo il flusso di lavoro!
Output del comando
Questa volta funziona E ci dà la comprensione aggiuntiva di come appaiono i contenuti del canale prima e dopo l'esecuzione dell'operatore flatten().
- Vedete che otteniamo una singola istruzione
Prima di flatten:perché a quel punto il canale contiene un elemento, l'array originale. Poi otteniamo tre istruzioni separateDopo flatten:, una per ogni saluto, che ora sono elementi individuali nel canale.
Importante, questo significa che ogni elemento può ora essere elaborato separatamente dal flusso di lavoro.
Suggerimento
È tecnicamente possibile ottenere gli stessi risultati usando una fabbrica di canali diversa, channel.fromList, che include un passo di mapping implicito nella sua operazione.
Qui abbiamo scelto di non usarla per dimostrare l'uso di un operatore su un caso d'uso semplice.
Takeaway¶
Sapete come usare un operatore come flatten() per trasformare i contenuti di un canale, e come usare l'operatore view() per ispezionare i contenuti del canale prima e dopo l'applicazione di un operatore.
Cosa c'è dopo?¶
Imparate come far prendere al flusso di lavoro un file come fonte di valori di input.
4. Leggere i valori di input da un file CSV¶
Realisticamente, raramente o mai partiremo da un array di valori. Molto probabilmente, avremo uno o più file contenenti i dati che devono essere elaborati, in qualche tipo di formato strutturato.
Abbiamo preparato un file CSV chiamato greetings.csv che contiene diversi saluti di input, imitando il tipo di dati colonnari che potreste voler elaborare in un'analisi dati reale, memorizzato sotto data/.
(I numeri non sono significativi, sono lì solo a scopo illustrativo.)
Il nostro prossimo compito è adattare il nostro flusso di lavoro per leggere i valori da questo file.
Vediamo come possiamo realizzarlo.
4.1. Modificare lo script per aspettarsi un file CSV come fonte di saluti¶
Per iniziare, dovremo apportare due modifiche chiave allo script:
- Cambiare il parametro di input per puntare al file CSV
- Cambiare la fabbrica di canali con una progettata per gestire un file
4.1.1. Cambiare il parametro di input per puntare al file CSV¶
Ricordate il parametro params.input che abbiamo configurato nella Parte 1?
Lo aggiorneremo per puntare al file CSV contenente i nostri saluti.
Effettuate la seguente modifica alla dichiarazione del parametro:
Questo presuppone che il file sia nella stessa posizione del codice del flusso di lavoro. Imparerete come gestire altre posizioni dei dati più avanti nel vostro percorso con Nextflow.
4.1.2. Passare a una fabbrica di canali progettata per gestire un file¶
Poiché ora vogliamo usare un file invece di semplici stringhe come input, non possiamo usare la fabbrica di canali channel.of() di prima.
Dobbiamo passare a usare una nuova fabbrica di canali, channel.fromPath(), che ha alcune funzionalità integrate per gestire i percorsi dei file.
Nel blocco workflow, effettuate la seguente modifica al codice:
Noterete che abbiamo riportato l'input del canale a param.input, e cancellato la dichiarazione greetings_array poiché non ne avremo più bisogno.
Abbiamo anche commentato flatten() e la seconda istruzione view().
4.1.3. Eseguire il flusso di lavoro¶
Proviamo a eseguire il flusso di lavoro con la nuova fabbrica di canali e il file di input.
Output del comando
N E X T F L O W ~ version 25.10.2
Launching `hello-channels.nf` [peaceful_poisson] DSL2 - revision: a286c08ad5
[- ] sayHello [ 0%] 0 of 1
Before flatten: /workspaces/training/hello-nextflow/data/greetings.csv
ERROR ~ Error executing process > 'sayHello (1)'
Caused by:
File `/workspaces/training/hello-nextflow/data/greetings.csv-output.txt` is outside the scope of the process work directory: /workspaces/training/hello-nextflow/work/30/e610cb4ea5ae8693f456ac3329c92f
Command executed:
echo '/workspaces/training/hello-nextflow/data/greetings.csv' > '/workspaces/training/hello-nextflow/data/greetings.csv-output.txt'
Command exit status:
-
Command output:
(empty)
Work dir:
/workspaces/training/hello-nextflow/work/30/e610cb4ea5ae8693f456ac3329c92f
Tip: when you have fixed the problem you can continue the execution adding the option `-resume` to the run command line
-- Check '.nextflow.log' file for details
Oh no, non funziona. Date un'occhiata all'inizio dell'output della console e al messaggio di errore.
La parte Command executed: è particolarmente utile qui.
Questo potrebbe sembrare un po' familiare. Sembra che Nextflow abbia provato a eseguire una singola chiamata di processo usando il percorso del file stesso come valore stringa. Quindi ha risolto correttamente il percorso del file, ma non ha effettivamente analizzato i suoi contenuti, che è quello che volevamo.
Come facciamo a far sì che Nextflow apra il file e carichi i suoi contenuti nel canale?
Sembra che abbiamo bisogno di un altro operatore!
4.2. Usare l'operatore splitCsv() per analizzare il file¶
Guardando di nuovo la lista degli operatori, troviamo splitCsv(), che è progettato per analizzare e dividere testo formattato CSV.
4.2.1. Applicare splitCsv() al canale¶
Per applicare l'operatore, lo aggiungiamo alla riga della fabbrica di canali come fatto in precedenza.
Nel blocco workflow, effettuate la seguente modifica al codice per sostituire flatten() con splitCsv() (senza commento):
| hello-channels.nf | |
|---|---|
Come potete vedere, abbiamo anche aggiornato le istruzioni view() prima/dopo.
Tecnicamente avremmo potuto usare lo stesso nome di variabile (greeting) ma l'abbiamo aggiornato a qualcosa di più appropriato (csv) per rendere il codice più leggibile agli altri.
4.2.2. Eseguire di nuovo il flusso di lavoro¶
Proviamo a eseguire il flusso di lavoro con la logica di parsing CSV aggiunta.
Output del comando
N E X T F L O W ~ version 25.10.2
Launching `hello-channels.nf` [insane_fermat] DSL2 - revision: 8e62fcbeb1
executor > local (3)
[24/76da2f] sayHello (2) [ 0%] 0 of 3 ✘
Before splitCsv: /workspaces/training/hello-nextflow/data/greetings.csv
After splitCsv: [Hello, English, 123]
After splitCsv: [Bonjour, French, 456]
After splitCsv: [Holà, Spanish, 789]
ERROR ~ Error executing process > 'sayHello (2)'
Caused by:
Missing output file(s) `[Bonjour, French, 456]-output.txt` expected by process `sayHello (2)`
Command executed:
echo '[Bonjour, French, 456]' > '[Bonjour, French, 456]-output.txt'
Command exit status:
0
Command output:
(empty)
Work dir:
/workspaces/training/hello-nextflow/work/24/76da2fcc4876b61632749f99e26a50
Tip: you can try to figure out what's wrong by changing to the process work dir and showing the script file named `.command.sh`
-- Check '.nextflow.log' file for details
Interessante, fallisce anche questo, ma con un errore diverso. Questa volta Nextflow ha analizzato i contenuti del file (evviva!) ma ha caricato ogni riga come un array, e ogni array è un elemento nel canale.
Dobbiamo dirgli di prendere solo la prima colonna di ogni riga. Quindi come spacchettamo questo?
Abbiamo usato precedentemente flatten() per spacchettare i contenuti di un canale, ma non funzionerebbe qui perché flatten spacchetta tutto (potete provarlo se volete vedere di persona).
Invece, useremo un altro operatore chiamato map() che è davvero utile e compare spesso nelle pipeline Nextflow.
4.3. Usare l'operatore map() per estrarre i saluti¶
L'operatore map() è un piccolo strumento molto utile che ci permette di fare ogni tipo di mappatura sui contenuti di un canale.
In questo caso, lo useremo per estrarre quell'unico elemento che vogliamo da ogni riga nel nostro file di dati. Ecco come appare la sintassi:
Questo significa 'per ogni riga nel canale, prendi l'elemento 0 (primo) che contiene'.
Quindi applichiamolo al nostro parsing CSV.
4.3.1. Applicare map() al canale¶
Nel blocco workflow, effettuate la seguente modifica al codice:
| hello-channels.nf | |
|---|---|
Vedete che abbiamo aggiunto un'altra chiamata view() per confermare che l'operatore fa quello che ci aspettiamo.
4.3.2. Eseguire il flusso di lavoro¶
Eseguiamolo ancora una volta:
Output del comando
N E X T F L O W ~ version 25.10.2
Launching `hello-channels.nf` [focused_volhard] DSL2 - revision: de435e45be
executor > local (3)
[54/6eebe3] sayHello (3) [100%] 3 of 3 ✔
Before splitCsv: /workspaces/training/hello-nextflow/data/greetings.csv
After splitCsv: [Hello, English, 123]
After splitCsv: [Bonjour, French, 456]
After splitCsv: [Holà, Spanish, 789]
After map: Hello
After map: Bonjour
After map: Holà
Questa volta dovrebbe funzionare senza errori.
Guardando l'output delle istruzioni view(), vedete il seguente:
- Una singola istruzione
Prima di splitCsv:: a quel punto il canale contiene un elemento, il percorso del file originale. - Tre istruzioni separate
Dopo splitCsv:: una per ogni saluto, ma ciascuna è contenuta in un array che corrisponde a quella riga nel file. - Tre istruzioni separate
Dopo map:: una per ogni saluto, che ora sono elementi individuali nel canale.
Nota che le righe potrebbero apparire in un ordine diverso nel vostro output.
Potete anche guardare i file di output per verificare che ogni saluto sia stato correttamente estratto ed elaborato attraverso il flusso di lavoro.
Abbiamo ottenuto lo stesso risultato di prima, ma ora abbiamo molta più flessibilità per aggiungere più elementi al canale di saluti che vogliamo elaborare modificando un file di input, senza modificare alcun codice. Imparerete approcci più sofisticati per gestire input complessi in una formazione successiva.
Takeaway¶
Sapete come usare il costruttore di canali .fromPath() e gli operatori splitCsv() e map() per leggere un file di valori di input e gestirli appropriatamente.
Più in generale, avete una comprensione di base di come Nextflow usa i canali per gestire gli input ai processi e gli operatori per trasformare i loro contenuti. Avete anche visto come i canali gestiscono l'esecuzione parallela implicitamente.
Cosa c'è dopo?¶
Prendetevi una bella pausa, avete lavorato duramente in questa sezione!
Quando siete pronti, passate alla Parte 3: Hello Workflow per imparare come aggiungere più passaggi e connetterli insieme in un flusso di lavoro vero e proprio.
Quiz¶
Cos'è un canale in Nextflow?
Quando un canale contiene più valori, come gestisce Nextflow l'esecuzione del processo?
Cosa fa l'operatore flatten()?
Qual è lo scopo dell'operatore view()?
Cosa fa splitCsv()?
Qual è lo scopo dell'operatore map()?
Perché è importante usare nomi di file di output dinamici quando si elaborano più input?