Verarbeitung von Datei-Eingaben¶
KI-gestützte Übersetzung - mehr erfahren & Verbesserungen vorschlagen
Wissenschaftliche Analyse-Workflows beinhalten oft die Verarbeitung großer Mengen von Dateien. Nextflow bietet leistungsstarke Werkzeuge, um Dateien effizient zu verwalten und dir zu helfen, deine Daten mit minimalem Code zu organisieren und zu verarbeiten.
Lernziele¶
In dieser Side Quest erkunden wir, wie Nextflow mit Dateien umgeht – von grundlegenden Dateioperationen bis hin zu fortgeschritteneren Techniken für die Arbeit mit Dateisammlungen. Du lernst, wie du Metadaten aus Dateinamen extrahierst, was eine häufige Anforderung in wissenschaftlichen Analyse-Pipelines ist.
Am Ende dieser Side Quest kannst du:
- Path-Objekte aus Dateipfad-Strings mit Nextflows
file()-Methode erstellen - Dateiattribute wie Name, Erweiterung und übergeordnetes Verzeichnis abrufen
- Lokale und entfernte Dateien transparent über URIs verarbeiten
- Kanäle zur Automatisierung der Dateiverarbeitung mit
channel.fromPath()undchannel.fromFilePairs()verwenden - Metadaten aus Dateinamen mithilfe von String-Manipulation extrahieren und strukturieren
- Zusammengehörige Dateien mit Pattern-Matching und Glob-Ausdrücken gruppieren
- Dateioperationen mit korrekter Eingabeverarbeitung in Nextflow-Prozesse integrieren
- Prozessausgaben mithilfe metadatengesteuerter Verzeichnisstrukturen organisieren
Diese Fähigkeiten helfen dir, Workflows zu erstellen, die verschiedene Arten von Datei-Eingaben mit großer Flexibilität verarbeiten können.
Voraussetzungen¶
Bevor du diese Side Quest in Angriff nimmst, solltest du:
- Das Tutorial Hello Nextflow oder einen gleichwertigen Einsteigerkurs abgeschlossen haben.
- Mit grundlegenden Nextflow-Konzepten und -Mechanismen (Prozesse, Kanäle, Operatoren) vertraut sein.
0. Erste Schritte¶
Trainings-Codespace öffnen¶
Falls noch nicht geschehen, öffne die Trainingsumgebung wie in der Umgebung einrichten beschrieben.
In das Projektverzeichnis wechseln¶
Wechseln wir in das Verzeichnis, in dem sich die Dateien für dieses Tutorial befinden.
Du kannst VSCode so einstellen, dass es sich auf dieses Verzeichnis fokussiert:
Die Materialien ansehen¶
Du findest eine einfache Workflow-Datei namens main.nf, ein modules-Verzeichnis mit zwei Moduldateien und ein data-Verzeichnis mit einigen Beispieldatendateien.
Verzeichnisinhalt
.
├── data
│ ├── patientA_rep1_normal_R1_001.fastq.gz
│ ├── patientA_rep1_normal_R2_001.fastq.gz
│ ├── patientA_rep1_tumor_R1_001.fastq.gz
│ ├── patientA_rep1_tumor_R2_001.fastq.gz
│ ├── patientA_rep2_normal_R1_001.fastq.gz
│ ├── patientA_rep2_normal_R2_001.fastq.gz
│ ├── patientA_rep2_tumor_R1_001.fastq.gz
│ ├── patientA_rep2_tumor_R2_001.fastq.gz
│ ├── patientB_rep1_normal_R1_001.fastq.gz
│ ├── patientB_rep1_normal_R2_001.fastq.gz
│ ├── patientB_rep1_tumor_R1_001.fastq.gz
│ ├── patientB_rep1_tumor_R2_001.fastq.gz
│ ├── patientC_rep1_normal_R1_001.fastq.gz
│ ├── patientC_rep1_normal_R2_001.fastq.gz
│ ├── patientC_rep1_tumor_R1_001.fastq.gz
│ └── patientC_rep1_tumor_R2_001.fastq.gz
├── main.nf
└── modules
├── analyze_reads.nf
└── count_lines.nf
Dieses Verzeichnis enthält Paired-End-Sequenzierungsdaten von drei Patient*innen (A, B, C).
Für jede*n Patient*in haben wir Proben vom Typ tumor (typischerweise aus Tumorbiopsien stammend) oder normal (aus gesundem Gewebe oder Blut entnommen).
Falls du nicht mit der Krebsanalyse vertraut bist: Dieses Modell verwendet gepaarte Tumor/Normal-Proben für kontrastive Analysen.
Für Patient A haben wir speziell zwei Sätze technischer Replikate (Wiederholungen).
Die Sequenzierungsdatendateien sind nach der üblichen _R1_- und _R2_-Konvention für sogenannte 'Forward Reads' und 'Reverse Reads' benannt.
Keine Sorge, wenn du mit diesem experimentellen Design nicht vertraut bist – es ist nicht entscheidend für das Verständnis dieses Tutorials.
Die Aufgabe verstehen¶
Deine Aufgabe ist es, einen Nextflow-Workflow zu schreiben, der:
- Eingabedateien lädt mithilfe von Nextflows Dateiverarbeitungsmethoden
- Metadaten extrahiert (Patienten-ID, Replikat, Probentyp) aus der Dateinamenstruktur
- Gepaarte Dateien (R1/R2) gruppiert mithilfe von
channel.fromFilePairs() - Die Dateien verarbeitet mit einem bereitgestellten Analysemodul
- Ausgaben organisiert in einer Verzeichnisstruktur basierend auf den extrahierten Metadaten
Bereitschafts-Checkliste¶
Bereit zum Eintauchen?
- Ich verstehe das Ziel dieses Kurses und seine Voraussetzungen
- Mein Codespace läuft
- Ich habe mein Arbeitsverzeichnis entsprechend eingestellt
- Ich verstehe die Aufgabe
Wenn du alle Punkte abhaken kannst, kann es losgehen.
1. Grundlegende Dateioperationen¶
1.1. Den Typ eines Objekts mit .class bestimmen¶
Schau dir die Workflow-Datei main.nf an:
| main.nf | |
|---|---|
Dies ist ein Mini-Workflow (ohne Prozesse), der auf einen einzelnen Dateipfad verweist, ihn dann zusammen mit seiner Klasse auf der Konsole ausgibt.
Was ist .class?
In Nextflow sagt uns .class, mit welchem Objekttyp wir arbeiten. Es ist wie die Frage „Was für ein Ding ist das?" – um herauszufinden, ob es ein String, eine Zahl, eine Datei oder etwas anderes ist.
Das hilft uns, den Unterschied zwischen einem einfachen String und einem Path-Objekt in den nächsten Abschnitten zu veranschaulichen.
Führen wir den Workflow aus:
Befehlsausgabe
Wie du siehst, hat Nextflow den String-Pfad genau so ausgegeben, wie wir ihn geschrieben haben.
Das ist nur Textausgabe; Nextflow hat noch nichts Besonderes damit gemacht.
Wir haben auch bestätigt, dass es sich aus Nextflows Sicht nur um einen String handelt (der Klasse java.lang.String).
Das macht Sinn, da wir Nextflow noch nicht mitgeteilt haben, dass es einer Datei entspricht.
1.2. Ein Path-Objekt mit file() erstellen¶
Wir können Nextflow mitteilen, wie es mit Dateien umgehen soll, indem wir Path-Objekte aus Pfad-Strings erstellen.
In unserem Workflow können wir den String-Pfad data/patientA_rep1_normal_R1_001.fastq.gz mit der file()-Methode in ein Path-Objekt umwandeln, das Zugriff auf Dateieigenschaften und -operationen bietet.
Bearbeite main.nf und umschließe den String mit file() wie folgt:
Führe den Workflow erneut aus:
Befehlsausgabe
Diesmal siehst du den vollständigen absoluten Pfad anstelle des relativen Pfads, den wir als Eingabe angegeben haben.
Nextflow hat unseren String in ein Path-Objekt umgewandelt und es zum tatsächlichen Dateispeicherort auf dem System aufgelöst.
Der Dateipfad ist jetzt absolut, wie z. B. /workspaces/training/side-quests/working_with_files/data/patientA_rep1_normal_R1_001.fastq.gz.
Beachte auch, dass die Path-Objekt-Klasse sun.nio.fs.UnixPath ist: So stellt Nextflow lokale Dateien dar.
Wie wir später sehen werden, haben entfernte Dateien andere Klassennamen (z. B. nextflow.file.http.XPath für HTTP-Dateien), aber sie funktionieren alle auf genau die gleiche Weise und können in deinen Workflows identisch verwendet werden.
Tipp
Der wesentliche Unterschied:
- Path-String: Nur Text, den Nextflow als Zeichen behandelt
- Path-Objekt: Eine intelligente Dateireferenz, mit der Nextflow arbeiten kann
Stell es dir so vor: Ein Path-String ist wie eine Adresse auf Papier, während ein Path-Objekt wie eine in ein Navigationsgerät geladene Adresse ist, das weiß, wie man dorthin navigiert, und dir Details über die Route mitteilen kann.
1.3. Dateiattribute abrufen¶
Warum ist das hilfreich? Nun, da Nextflow versteht, dass myFile ein Path-Objekt und kein einfacher String ist, können wir auf die verschiedenen Attribute des Path-Objekts zugreifen.
Aktualisieren wir unseren Workflow, um die eingebauten Dateiattribute auszugeben:
Workflow ausführen:
Befehlsausgabe
N E X T F L O W ~ version 25.10.2
Launching `main.nf` [ecstatic_ampere] DSL2 - revision: f3fa3dcb48
File object class: sun.nio.fs.UnixPath
File name: patientA_rep1_normal_R1_001.fastq.gz
Simple name: patientA_rep1_normal_R1_001
Extension: gz
Parent directory: /workspaces/training/side-quests/working_with_files/data
Du siehst die verschiedenen Dateiattribute, die oben auf der Konsole ausgegeben werden.
1.4. Die Datei an einen Prozess übergeben¶
Der Unterschied zwischen Strings und Path-Objekten wird entscheidend, wenn du anfängst, echte Workflows mit Prozessen zu erstellen. Bisher haben wir bestätigt, dass Nextflow unsere Eingabedatei jetzt als Datei behandelt, aber lass uns sehen, ob wir tatsächlich etwas mit dieser Datei in einem Prozess ausführen können.
1.4.1. Den Prozess importieren und den Code untersuchen¶
Wir stellen dir ein vorgefertigtes Prozessmodul namens COUNT_LINES zur Verfügung, das eine Dateieingabe entgegennimmt und zählt, wie viele Zeilen darin enthalten sind.
Um den Prozess im Workflow zu verwenden, musst du nur eine include-Anweisung vor dem Workflow-Block hinzufügen:
Du kannst die Moduldatei öffnen, um ihren Code zu untersuchen:
| modules/count_lines.nf | |
|---|---|
Wie du siehst, ist es ein recht einfaches Skript, das die Datei entpackt und zählt, wie viele Zeilen sie enthält.
Was macht debug true?
Die debug true-Direktive in der Prozessdefinition bewirkt, dass Nextflow die Ausgabe deines Skripts (wie die Zeilenanzahl „40") direkt im Ausführungsprotokoll ausgibt.
Ohne diese Direktive würdest du nur den Prozessausführungsstatus sehen, aber nicht die tatsächliche Ausgabe deines Skripts.
Weitere Informationen zum Debuggen von Nextflow-Prozessen findest du in der Side Quest Debugging Nextflow Workflows.
1.4.2. Einen Aufruf von COUNT_LINES hinzufügen¶
Da der Prozess jetzt im Workflow verfügbar ist, können wir einen Aufruf des COUNT_LINES-Prozesses hinzufügen, um ihn auf der Eingabedatei auszuführen.
Nimm folgende Änderungen am Workflow vor:
Und jetzt den Workflow ausführen:
Befehlsausgabe
N E X T F L O W ~ version 25.10.2
Launching `main.nf` [cheeky_hypatia] DSL2 - revision: 281d13c414
File object class: class sun.nio.fs.UnixPath
File name: patientA_rep1_normal_R1_001.fastq.gz
Simple name: patientA_rep1_normal_R1_001
Extension: gz
Parent directory: /workspaces/training/side-quests/working_with_files/data
executor > local (1)
[e9/341c05] COUNT_LINES [100%] 1 of 1 ✔
Processing file: /workspaces/training/side-quests/working_with_files/data/patientA_rep1_normal_R1_001.fastq.gz
40
Das zeigt, dass wir die Datei innerhalb eines Prozesses korrekt verarbeiten können.
Konkret hat Nextflow folgende Operationen erfolgreich durchgeführt:
- Die Datei in das work directory gestaged
- Die .gz-Datei dekomprimiert
- Die Zeilen gezählt (in diesem Fall 40 Zeilen)
- Ohne Fehler abgeschlossen
Der Schlüssel zu diesem reibungslosen Ablauf ist, dass wir Nextflow explizit mitteilen, dass unsere Eingabe eine Datei ist und als solche behandelt werden soll.
1.5. Grundlegende Datei-Eingabefehler beheben¶
Das ist eine häufige Stolperfalle für Nextflow-Einsteiger*innen, also nehmen wir uns ein paar Minuten Zeit, um zu sehen, was passiert, wenn man es falsch macht.
Es gibt zwei Hauptstellen, an denen die Dateiverarbeitung schiefgehen kann: auf der Ebene des Workflows und auf der Ebene des Prozesses.
1.5.1. Fehler auf Workflow-Ebene¶
Schauen wir uns an, was passiert, wenn wir die Datei wieder als String behandeln, wenn wir die Eingabe im Workflow-Block angeben.
Nimm folgende Änderungen am Workflow vor und stelle sicher, dass du die pfadspezifischen Print-Anweisungen auskommentierst:
Und jetzt den Workflow ausführen:
Befehlsausgabe
N E X T F L O W ~ version 25.10.2
Launching `main.nf` [friendly_goodall] DSL2 - revision: ae50609b20
[- ] COUNT_LINES -
ERROR ~ Error executing process > 'COUNT_LINES'
Caused by:
Not a valid path value: 'data/patientA_rep1_normal_R1_001.fastq.gz'
Tip: view the complete command output by changing to the process work dir and entering the command `cat .command.out`
-- Check '.nextflow.log' file for details
Das ist der wichtige Teil:
Wenn du eine path-Eingabe angibst, überprüft Nextflow, ob du tatsächliche Dateireferenzen übergibst und keine einfachen Strings.
Dieser Fehler teilt dir mit, dass 'data/patientA_rep1_normal_R1_001.fastq.gz' kein gültiger Pfadwert ist, weil es ein String und kein Path-Objekt ist.
Nextflow hat das Problem sofort erkannt und gestoppt, bevor der Prozess überhaupt gestartet wurde.
1.5.2. Fehler auf Prozess-Ebene¶
Die andere Stelle, an der wir vergessen könnten anzugeben, dass Nextflow die Eingabe als Datei behandeln soll, ist in der Prozessdefinition.
Warnung
Damit dieser Test korrekt funktioniert, behalte den Workflow in seinem fehlerhaften Zustand (mit einem einfachen String statt file()).
In Kombination mit val im Prozess erzeugt das den unten gezeigten Fehler.
Nimm folgende Änderung am Modul vor:
Und jetzt den Workflow erneut ausführen:
Befehlsausgabe
N E X T F L O W ~ version 25.10.2
Launching `main.nf` [soggy_golick] DSL2 - revision: ae50609b20
executor > local (1)
[b3/b3023c] COUNT_LINES [ 0%] 0 of 1 ✘
ERROR ~ Error executing process > 'COUNT_LINES'
Caused by:
Process `COUNT_LINES` terminated with an error exit status (1)
Command executed:
set -o pipefail
echo "Processing file: data/patientA_rep1_normal_R1_001.fastq.gz"
gzip -dc data/patientA_rep1_normal_R1_001.fastq.gz | wc -l
Command exit status:
1
Command output:
Processing file: data/patientA_rep1_normal_R1_001.fastq.gz
0
Command error:
Processing file: data/patientA_rep1_normal_R1_001.fastq.gz
gzip: data/patientA_rep1_normal_R1_001.fastq.gz: No such file or directory
0
Work dir:
/workspaces/training/side-quests/working_with_files/work/b3/b3023cb2ccb986851301d8e369e79f
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
Das zeigt viele Details über den Fehler, da der Prozess so eingestellt ist, dass er Debug-Informationen ausgibt, wie oben erwähnt.
Die relevantesten Abschnitte sind:
Command executed:
set -o pipefail
echo "Processing file: data/patientA_rep1_normal_R1_001.fastq.gz"
gzip -dc data/patientA_rep1_normal_R1_001.fastq.gz | wc -l
Command error:
Processing file: data/patientA_rep1_normal_R1_001.fastq.gz
gzip: data/patientA_rep1_normal_R1_001.fastq.gz: No such file or directory
0
Das bedeutet, dass das System die Datei nicht finden konnte; wenn du jedoch den Pfad nachschaust, gibt es dort eine Datei mit diesem Namen.
Als wir das ausgeführt haben, hat Nextflow den String-Wert an das Skript weitergegeben, aber die eigentliche Datei nicht in das work directory gestaged.
Der Prozess hat also versucht, den relativen String data/patientA_rep1_normal_R1_001.fastq.gz zu verwenden, aber diese Datei existiert nicht im work directory des Prozesses.
Zusammengenommen zeigen diese beiden Beispiele, wie wichtig es ist, Nextflow mitzuteilen, wenn eine Eingabe als Datei behandelt werden soll.
Hinweis
Stelle sicher, dass du beide absichtlichen Fehler behebst, bevor du mit dem nächsten Abschnitt fortfährst.
Fazit¶
- Path-Strings vs. Path-Objekte: Strings sind nur Text, Path-Objekte sind intelligente Dateireferenzen
- Die
file()-Methode wandelt einen String-Pfad in ein Path-Objekt um, mit dem Nextflow arbeiten kann - Du kannst auf Dateieigenschaften wie
name,simpleName,extensionundparentmithilfe von Dateiattributen zugreifen - Die Verwendung von Path-Objekten statt Strings ermöglicht es Nextflow, Dateien in deinem Workflow korrekt zu verwalten
- Prozess-Eingabeergebnisse: Eine korrekte Dateiverarbeitung erfordert Path-Objekte, keine Strings, damit Dateien korrekt gestaged und für Prozesse zugänglich sind.
2. Entfernte Dateien verwenden¶
Eine der wichtigsten Funktionen von Nextflow ist die Möglichkeit, nahtlos zwischen lokalen Dateien (auf demselben Rechner) und entfernten Dateien, die über das Internet zugänglich sind, zu wechseln.
Wenn du es richtig machst, solltest du die Logik deines Workflows nie ändern müssen, um Dateien aus verschiedenen Speicherorten zu verarbeiten. Alles, was du tun musst, um eine entfernte Datei zu verwenden, ist das entsprechende Präfix im Dateipfad anzugeben, wenn du ihn dem Workflow übergibst.
Zum Beispiel hat /path/to/data kein Präfix, was darauf hinweist, dass es ein „normaler" lokaler Dateipfad ist, während s3://path/to/data das Präfix s3:// enthält, was darauf hinweist, dass es sich in Amazons S3-Objektspeicher befindet.
Viele verschiedene Protokolle werden unterstützt:
- HTTP(S)/FTP (http://, https://, ftp://)
- Amazon S3 (s3://)
- Azure Blob Storage (az://)
- Google Cloud Storage (gs://)
Um eines davon zu verwenden, gib einfach das entsprechende Präfix im String an, der dann technisch als Uniform Resource Identifier (URI) statt als Dateipfad bezeichnet wird. Nextflow übernimmt die Authentifizierung und das Staging der Dateien an den richtigen Ort, einschließlich aller anderen Dateioperationen, die du erwarten würdest.
Die wichtigste Stärke dieses Systems ist, dass wir zwischen Umgebungen wechseln können, ohne die Pipeline-Logik zu ändern. Du kannst zum Beispiel mit einem kleinen, lokalen Testdatensatz entwickeln und dann einfach durch Ändern der URI auf einen vollständigen Testdatensatz in einem entfernten Speicher umsteigen.
2.1. Eine Datei aus dem Internet verwenden¶
Testen wir das, indem wir den lokalen Pfad, den wir unserem Workflow übergeben, durch einen HTTPS-Pfad ersetzen, der auf eine Kopie derselben Daten verweist, die auf Github gespeichert ist.
Warnung
Das funktioniert nur, wenn du eine aktive Internetverbindung hast.
Öffne main.nf erneut und ändere den Eingabepfad wie folgt:
Führen wir den Workflow aus:
Befehlsausgabe
N E X T F L O W ~ version 25.10.2
Launching `main.nf` [insane_swartz] DSL2 - revision: fff18abe6d
File object class: class nextflow.file.http.XPath
File name: patientA_rep1_normal_R1_001.fastq.gz
Simple name: patientA_rep1_normal_R1_001
Extension: gz
Parent directory: /nextflow-io/training/master/side-quests/working_with_files/data
executor > local (1)
[8a/2ab7ca] COUNT_LINES [100%] 1 of 1 ✔
Processing file: patientA_rep1_normal_R1_001.fastq.gz
40
Es funktioniert! Du siehst, dass sich sehr wenig geändert hat.
Der einzige Unterschied in der Konsolenausgabe ist, dass die Path-Objekt-Klasse jetzt nextflow.file.http.XPath ist, während sie für den lokalen Pfad sun.nio.fs.UnixPath war.
Du musst dir diese Klassen nicht merken; wir erwähnen das nur, um zu zeigen, dass Nextflow die verschiedenen Speicherorte entsprechend identifiziert und verarbeitet.
Im Hintergrund hat Nextflow die Datei in ein Staging-Verzeichnis innerhalb des work directory heruntergeladen. Diese gestagede Datei kann dann als lokale Datei behandelt und per Symlink in das entsprechende Prozessverzeichnis eingebunden werden.
Du kannst überprüfen, ob das passiert ist, indem du dir den Inhalt des work directory ansiehst, das sich am Hash-Wert des Prozesses befindet.
Work-Verzeichnis Inhalt
Wenn der Prozess-Hash 8a/2ab7ca war, könntest du das work directory erkunden:
$ ls -la work/8a/2ab7ca*/
total 16
drwxr-xr-x 6 user staff 192 Jan 28 10:00 .
drwxr-xr-x 3 user staff 96 Jan 28 10:00 ..
-rw-r--r-- 1 user staff 0 Jan 28 10:00 .command.begin
-rw-r--r-- 1 user staff 127 Jan 28 10:00 .command.sh
lrwxr-xr-x 1 user staff 89 Jan 28 10:00 patientA_rep1_normal_R1_001.fastq.gz -> /path/to/work/stage/.../patientA_rep1_normal_R1_001.fastq.gz
Der Symlink verweist auf eine gestagede Kopie der entfernten Datei, die Nextflow automatisch heruntergeladen hat.
Beachte, dass der Download-Schritt bei größeren Dateien im Vergleich zur Ausführung mit lokalen Dateien etwas mehr Zeit in Anspruch nimmt. Nextflow prüft jedoch, ob bereits eine gestagede Kopie vorhanden ist, um unnötige Downloads zu vermeiden. Wenn du also erneut auf derselben Datei ausführst und die gestagede Datei nicht gelöscht hast, verwendet Nextflow die gestagede Kopie.
Das zeigt, wie einfach es ist, mit Nextflow zwischen lokalen und entfernten Daten zu wechseln – eine wichtige Funktion von Nextflow.
Hinweis
Die eine wichtige Ausnahme von diesem Prinzip ist, dass du keine Glob-Muster oder Verzeichnispfade mit HTTPS verwenden kannst, da HTTPS keine mehreren Dateien auflisten kann. Du musst also genaue Datei-URLs angeben.
Andere Speicherprotokolle wie Blob-Speicher (s3://, az://, gs://) können jedoch sowohl Globs als auch Verzeichnispfade verwenden.
So könntest du Glob-Muster mit Cloud-Speicher verwenden:
// S3 mit Glob-Mustern - würde mehrere Dateien matchen
ch_s3_files = channel.fromPath('s3://my-bucket/data/*.fastq.gz')
// Azure Blob Storage mit Glob-Mustern
ch_azure_files = channel.fromPath('az://container/data/patient*_R{1,2}.fastq.gz')
// Google Cloud Storage mit Glob-Mustern
ch_gcs_files = channel.fromPath('gs://bucket/data/sample_*.fastq.gz')
Im nächsten Abschnitt zeigen wir dir, wie du in der Praxis mit Globs arbeitest.
2.2. Zurück zur lokalen Datei wechseln¶
Für den Rest dieser Side Quest werden wir wieder unsere lokalen Beispieldateien verwenden, also wechseln wir die Workflow-Eingabe zurück zur ursprünglichen Datei:
Fazit¶
- Auf entfernte Daten wird über eine URI zugegriffen (HTTP, FTP, S3, Azure, Google Cloud)
- Nextflow lädt die Daten automatisch herunter und stagt sie an den richtigen Ort, solange diese Pfade an Prozesse übergeben werden
- Schreibe keine Logik zum Herunterladen oder Hochladen entfernter Dateien!
- Lokale und entfernte Dateien erzeugen unterschiedliche Objekttypen, funktionieren aber identisch
- Wichtig: HTTP/HTTPS funktioniert nur mit einzelnen Dateien (keine Glob-Muster)
- Cloud-Speicher (S3, Azure, GCS) unterstützt sowohl einzelne Dateien als auch Glob-Muster
- Du kannst nahtlos zwischen lokalen und entfernten Datenquellen wechseln, ohne die Code-Logik zu ändern (solange das Protokoll die erforderlichen Operationen unterstützt)
3. Die fromPath()-Kanal-Factory verwenden¶
Bisher haben wir immer mit einer einzelnen Datei gearbeitet, aber in Nextflow werden wir typischerweise einen Eingabekanal mit mehreren Eingabedateien zur Verarbeitung erstellen wollen.
Eine naive Methode wäre, die file()-Methode mit channel.of() zu kombinieren:
ch_files = channel.of([file('data/patientA_rep1_normal_R1_001.fastq.gz')],
[file('data/patientA_rep1_normal_R1_001.fastq.gz')])
Das funktioniert, ist aber umständlich.
Tipp: Wann file() vs. channel.fromPath() verwenden
- Verwende
file(), wenn du ein einzelnes Path-Objekt für die direkte Manipulation benötigst (prüfen, ob eine Datei existiert, ihre Attribute lesen oder an einen einzelnen Prozessaufruf übergeben) - Verwende
channel.fromPath(), wenn du einen Kanal benötigst, der mehrere Dateien aufnehmen kann, insbesondere mit Glob-Mustern, oder wenn Dateien durch mehrere Prozesse fließen sollen
Hier kommt channel.fromPath() ins Spiel: eine praktische Kanal-Factory, die alle Funktionen bündelt, die wir benötigen, um einen Kanal aus einem oder mehreren statischen Datei-Strings sowie Glob-Mustern zu erstellen.
3.1. Die Kanal-Factory hinzufügen¶
Aktualisieren wir unseren Workflow, um channel.fromPath zu verwenden.
Wir haben auch den Code, der die Attribute ausgibt, vorerst auskommentiert und eine .view-Anweisung hinzugefügt, die stattdessen nur den Dateinamen ausgibt.
Workflow ausführen:
Befehlsausgabe
Wie du siehst, wird der Dateipfad als Path-Objekt im Kanal geladen.
Das ist ähnlich wie bei file(), aber jetzt haben wir einen Kanal, in den wir bei Bedarf weitere Dateien laden können.
channel.fromPath() ist eine praktische Möglichkeit, einen neuen Kanal zu erstellen, der mit einer Liste von Dateien befüllt ist.
3.2. Attribute von Dateien im Kanal anzeigen¶
Bei unserem ersten Einsatz der Kanal-Factory haben wir den Code vereinfacht und nur den Dateinamen ausgegeben.
Gehen wir zurück zur Ausgabe der vollständigen Dateiattribute:
Wir aktivieren auch den COUNT_LINES-Prozessaufruf wieder, um zu überprüfen, dass die Dateiverarbeitung mit unserem kanalbasierten Ansatz weiterhin korrekt funktioniert.
Workflow ausführen:
Befehlsausgabe
N E X T F L O W ~ version 25.10.2
Launching `main.nf` [furious_swanson] DSL2 - revision: c35c34950d
executor > local (1)
[9d/6701a6] COUNT_LINES (1) [100%] 1 of 1 ✔
File object class: sun.nio.fs.UnixPath
File name: patientA_rep1_normal_R1_001.fastq.gz
Simple name: patientA_rep1_normal_R1_001
Extension: gz
Parent directory: /workspaces/training/side-quests/working_with_files/data
Processing file: patientA_rep1_normal_R1_001.fastq.gz
40
Und da haben wir es – dieselben Ergebnisse wie zuvor, aber jetzt haben wir die Datei in einem Kanal, sodass wir weitere hinzufügen können.
3.3. Einen Glob verwenden, um mehrere Dateien zu matchen¶
Es gibt mehrere Möglichkeiten, weitere Dateien in den Kanal zu laden. Hier zeigen wir dir, wie du Glob-Muster verwendest, eine praktische Methode zum Matchen und Abrufen von Datei- und Verzeichnisnamen basierend auf Platzhalterzeichen. Der Prozess des Matchens dieser Muster wird als „Globbing" oder „Dateinamen-Expansion" bezeichnet.
Hinweis
Wie bereits erwähnt, unterstützt Nextflow Globbing zur Verwaltung von Eingabe- und Ausgabedateien in den meisten Fällen, außer bei HTTPS-Dateipfaden, da HTTPS keine mehreren Dateien auflisten kann.
Angenommen, wir möchten beide Dateien in einem Dateipaar abrufen, das einem bestimmten Patienten patientA zugeordnet ist:
Da der einzige Unterschied zwischen den Dateinamen die Replikatnummer ist, d. h. die Zahl nach R, können wir das Platzhalterzeichen * wie folgt als Ersatz für die Zahl verwenden:
Das ist das Glob-Muster, das wir benötigen.
Jetzt müssen wir nur noch den Dateipfad in der Kanal-Factory aktualisieren, um dieses Glob-Muster zu verwenden:
Nextflow erkennt automatisch, dass es sich um ein Glob-Muster handelt, und verarbeitet es entsprechend.
Führe den Workflow aus, um das zu testen:
Befehlsausgabe
N E X T F L O W ~ version 25.10.2
Launching `main.nf` [boring_sammet] DSL2 - revision: d2aa789c9a
executor > local (2)
[3c/a65de5] COUNT_LINES (2) [100%] 2 of 2 ✔
File object class: class sun.nio.fs.UnixPath
File name: patientA_rep1_normal_R1_001.fastq.gz
Simple name: patientA_rep1_normal_R1_001
Extension: gz
Parent directory: /workspaces/training/side-quests/working_with_files/data
File object class: class sun.nio.fs.UnixPath
File name: patientA_rep1_normal_R2_001.fastq.gz
Simple name: patientA_rep1_normal_R2_001
Extension: gz
Parent directory: /workspaces/training/side-quests/working_with_files/data
Processing file: patientA_rep1_normal_R1_001.fastq.gz
40
Processing file: patientA_rep1_normal_R2_001.fastq.gz
40
Wie du siehst, haben wir jetzt zwei Path-Objekte in unserem Kanal, was zeigt, dass Nextflow die Dateinamen-Expansion korrekt durchgeführt und beide Dateien wie erwartet geladen und verarbeitet hat.
Mit dieser Methode können wir beliebig viele Dateien abrufen, indem wir einfach das Glob-Muster ändern. Wenn wir es großzügiger gestalten, zum Beispiel indem wir alle variablen Teile der Dateinamen durch * ersetzen (z. B. data/patient*_rep*_*_R*_001.fastq.gz), könnten wir alle Beispieldateien im data-Verzeichnis abrufen.
Fazit¶
channel.fromPath()erstellt einen Kanal mit Dateien, die einem Muster entsprechen- Jede Datei wird als separates Element im Kanal ausgegeben
- Wir können ein Glob-Muster verwenden, um mehrere Dateien zu matchen
- Dateien werden automatisch in Path-Objekte mit vollständigen Attributen umgewandelt
- Die
.view()-Methode ermöglicht die Inspektion von Kanalinhalten
4. Grundlegende Metadaten aus Dateinamen extrahieren¶
In den meisten wissenschaftlichen Bereichen ist es sehr üblich, Metadaten in den Namen der Datendateien zu kodieren. In der Bioinformatik werden Dateien mit Sequenzierungsdaten beispielsweise oft so benannt, dass Informationen über die Probe, den Zustand, das Replikat und die Read-Nummer kodiert sind.
Wenn die Dateinamen nach einer konsistenten Konvention aufgebaut sind, kannst du diese Metadaten auf standardisierte Weise extrahieren und im Verlauf deiner Analyse verwenden. Das ist natürlich ein großes „Wenn", und du solltest sehr vorsichtig sein, wenn du dich auf die Dateinamenstruktur verlässt; aber die Realität ist, dass dieser Ansatz sehr weit verbreitet ist, also schauen wir uns an, wie es in Nextflow gemacht wird.
Im Fall unserer Beispieldaten wissen wir, dass die Dateinamen konsistent strukturierte Metadaten enthalten.
Zum Beispiel kodiert der Dateiname patientA_rep1_normal_R2_001 folgendes:
- Patienten-ID:
patientA - Replikat-ID:
rep1 - Probentyp:
normal(im Gegensatz zutumor) - Read-Set:
R1(im Gegensatz zuR2)
Wir werden unseren Workflow in drei Schritten modifizieren, um diese Informationen abzurufen:
- Den
simpleNameder Datei abrufen, der die Metadaten enthält - Die Metadaten mit einer Methode namens
tokenize()trennen - Eine map verwenden, um die Metadaten zu organisieren
Warnung
Du solltest niemals sensible Informationen in Dateinamen kodieren, wie z. B. Patientennamen oder andere identifizierende Merkmale, da dies die Privatsphäre von Patient*innen oder andere relevante Sicherheitsbeschränkungen gefährden kann.
4.1. Den simpleName abrufen¶
Der simpleName ist ein Dateiattribut, das dem Dateinamen ohne Pfad und Erweiterung entspricht.
Nimm folgende Änderungen am Workflow vor:
Das ruft den simpleName ab und verknüpft ihn mit dem vollständigen Dateiobjekt mithilfe einer map()-Operation.
Führe den Workflow aus, um zu testen, ob es funktioniert:
Befehlsausgabe
N E X T F L O W ~ version 25.10.2
Launching `main.nf` [suspicious_mahavira] DSL2 - revision: ae8edc4e48
executor > local (2)
[e9/55774b] COUNT_LINES (2) [100%] 2 of 2 ✔
[patientA_rep1_normal_R2_001, /workspaces/training/side-quests/working_with_files/data/patientA_rep1_normal_R2_001.fastq.gz]
[patientA_rep1_normal_R1_001, /workspaces/training/side-quests/working_with_files/data/patientA_rep1_normal_R1_001.fastq.gz]
Processing file: patientA_rep1_normal_R1_001.fastq.gz
40
Processing file: patientA_rep1_normal_R2_001.fastq.gz
40
Jedes Element im Kanal ist jetzt ein Tupel, das den simpleName und das ursprüngliche Dateiobjekt enthält.
4.2. Die Metadaten aus dem simpleName extrahieren¶
An diesem Punkt sind die gewünschten Metadaten im simpleName eingebettet, aber wir können nicht direkt auf einzelne Elemente zugreifen.
Wir müssen also den simpleName in seine Bestandteile aufteilen.
Glücklicherweise sind diese Bestandteile im ursprünglichen Dateinamen einfach durch Unterstriche getrennt, sodass wir eine gängige Nextflow-Methode namens tokenize() anwenden können, die für diese Aufgabe perfekt geeignet ist.
Nimm folgende Änderungen am Workflow vor:
Die tokenize()-Methode teilt den simpleName-String überall dort auf, wo sie Unterstriche findet, und gibt eine Liste mit den Teilstrings zurück.
Workflow ausführen:
Befehlsausgabe
N E X T F L O W ~ version 25.10.2
Launching `main.nf` [gigantic_gauss] DSL2 - revision: a39baabb57
executor > local (2)
[e7/da2f4b] COUNT_LINES (2) [100%] 2 of 2 ✔
[[patientA, rep1, normal, R2, 001], /workspaces/training/side-quests/working_with_files/data/patientA_rep1_normal_R2_001.fastq.gz]
[[patientA, rep1, normal, R1, 001], /workspaces/training/side-quests/working_with_files/data/patientA_rep1_normal_R1_001.fastq.gz]
Processing file: patientA_rep1_normal_R2_001.fastq.gz
40
Processing file: patientA_rep1_normal_R1_001.fastq.gz
40
Jetzt enthält das Tupel für jedes Element in unserem Kanal die Liste der Metadaten (z. B. [patientA, rep1, normal, R1, 001]) und das ursprüngliche Dateiobjekt.
Großartig! Wir haben unsere Patienteninformationen von einem einzelnen String in eine Liste von Strings aufgeteilt. Wir können jetzt jeden Teil der Patienteninformationen separat verarbeiten.
4.3. Eine map verwenden, um die Metadaten zu organisieren¶
Unsere Metadaten sind im Moment nur eine flache Liste. Sie ist einfach genug zu verwenden, aber schwer zu lesen.
Was ist das Element an Index 3? Kannst du es sagen, ohne auf die ursprüngliche Erklärung der Metadatenstruktur zurückzugreifen?
Das ist eine gute Gelegenheit, einen Key-Value-Store zu verwenden, bei dem jedes Element einen Satz von Schlüsseln und ihren zugehörigen Werten hat, sodass du leicht auf jeden Schlüssel verweisen kannst, um den entsprechenden Wert zu erhalten.
In unserem Beispiel bedeutet das, von dieser Organisation:
Zu dieser hier:
In Nextflow nennt man das eine map.
Konvertieren wir jetzt unsere flache Liste in eine map. Nimm folgende Änderungen am Workflow vor:
Die wichtigsten Änderungen hier sind:
- Destrukturierungs-Zuweisung:
def (patient, replicate, type, readNum) = ...extrahiert die tokenisierten Werte in einer Zeile in benannte Variablen - Map-Literal-Syntax:
[id: patient, replicate: ...]erstellt eine map, bei der jeder Schlüssel (wieid) mit einem Wert (wiepatient) verknüpft ist - Verschachtelte Struktur: Die äußere Liste
[..., myFile]verbindet die Metadaten-map mit dem ursprünglichen Dateiobjekt
Wir haben auch einige der Metadaten-Strings mit einer String-Ersetzungsmethode namens replace() vereinfacht, um einige unnötige Zeichen zu entfernen (z. B. replicate.replace('rep', ''), um nur die Zahl aus den Replikat-IDs zu behalten).
Führen wir den Workflow erneut aus:
Befehlsausgabe
N E X T F L O W ~ version 25.10.2
Launching `main.nf` [infallible_swartz] DSL2 - revision: 7f4e68c0cb
executor > local (2)
[1b/e7fb27] COUNT_LINES (1) [100%] 2 of 2 ✔
[[id:patientA, replicate:1, type:normal, readNum:2], /workspaces/training/side-quests/working_with_files/data/patientA_rep1_normal_R2_001.fastq.gz]
[[id:patientA, replicate:1, type:normal, readNum:1], /workspaces/training/side-quests/working_with_files/data/patientA_rep1_normal_R1_001.fastq.gz]
Processing file: patientA_rep1_normal_R2_001.fastq.gz
40
Processing file: patientA_rep1_normal_R1_001.fastq.gz
40
Jetzt sind die Metadaten übersichtlich beschriftet (z. B. [id:patientA, replicate:1, type:normal, readNum:2]), sodass es viel einfacher ist zu erkennen, was was ist.
Es wird auch viel einfacher sein, Metadaten-Elemente im Workflow tatsächlich zu nutzen, und unser Code wird leichter zu lesen und zu warten sein.
Fazit¶
- Wir können Dateinamen in Nextflow mit der Leistung einer vollständigen Programmiersprache verarbeiten
- Wir können die Dateinamen als Strings behandeln, um relevante Informationen zu extrahieren
- Die Verwendung von Methoden wie
tokenize()undreplace()ermöglicht es uns, Strings im Dateinamen zu manipulieren - Die
.map()-Operation transformiert Kanalelemente und bewahrt dabei die Struktur - Strukturierte Metadaten (maps) machen den Code lesbarer und wartbarer als Positionslisten
Als nächstes schauen wir uns an, wie man gepaarte Datendateien verarbeitet.
5. Gepaarte Datendateien verarbeiten¶
Viele experimentelle Designs erzeugen gepaarte Datendateien, die davon profitieren, explizit gepaart verarbeitet zu werden. In der Bioinformatik werden Sequenzierungsdaten beispielsweise oft in Form von gepaarten Reads generiert, d. h. Sequenzstrings, die aus demselben DNA-Fragment stammen (oft als 'Forward' und 'Reverse' bezeichnet, weil sie von entgegengesetzten Enden gelesen werden).
Das ist der Fall bei unseren Beispieldaten, wo R1 und R2 auf die beiden Read-Sets verweisen.
Nextflow bietet eine spezialisierte Kanal-Factory für die Arbeit mit solchen gepaarten Dateien namens channel.fromFilePairs(), die Dateien automatisch basierend auf einem gemeinsamen Benennungsmuster gruppiert. Das ermöglicht es dir, die gepaarten Dateien mit weniger Aufwand enger miteinander zu verknüpfen.
Wir werden unseren Workflow modifizieren, um davon zu profitieren. Das erfordert zwei Schritte:
- Die Kanal-Factory auf
channel.fromFilePairs()umstellen - Die Metadaten extrahieren und mappen
5.1. Die Kanal-Factory auf channel.fromFilePairs() umstellen¶
Um channel.fromFilePairs zu verwenden, müssen wir das Muster angeben, das Nextflow verwenden soll, um die beiden Mitglieder eines Paares zu identifizieren.
Zurück zu unseren Beispieldaten können wir das Benennungsmuster wie folgt formalisieren:
Das ist ähnlich wie das Glob-Muster, das wir zuvor verwendet haben, außer dass es die Teilstrings (entweder 1 oder 2 direkt nach dem R) explizit aufzählt, die die beiden Mitglieder des Paares identifizieren.
Aktualisieren wir den Workflow main.nf entsprechend:
Wir haben die Kanal-Factory umgestellt und das Datei-Matching-Muster angepasst, und dabei auch die map-Operation auskommentiert. Wir werden sie später mit einigen Änderungen wieder hinzufügen.
Führe den Workflow aus, um ihn zu testen:
Befehlsausgabe
N E X T F L O W ~ version 25.10.2
Launching `main.nf` [angry_koch] DSL2 - revision: 44fdf66105
[- ] COUNT_LINES -
[- ] COUNT_LINES -
[patientA_rep1_normal_R, [/workspaces/training/side-quests/working_with_files/data/patientA_rep1_normal_R1_001.fastq.gz, /workspaces/training/side-quests/working_with_files/data/patientA_rep1_normal_R2_001.fastq.gz]]
ERROR ~ Error executing process > 'COUNT_LINES (1)'
Caused by:
Not a valid path value: 'patientA_rep1_normal_R'
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 nein, diesmal ist die Ausführung fehlgeschlagen!
Der relevante Teil der Fehlermeldung ist hier:
Das liegt daran, dass wir die Kanal-Factory geändert haben. Bisher enthielt der ursprüngliche Eingabekanal nur die Dateipfade. Alle Metadaten-Manipulationen, die wir durchgeführt haben, haben den Kanalinhalt nicht tatsächlich verändert.
Jetzt, da wir die .fromFilePairs-Kanal-Factory verwenden, ist der Inhalt des resultierenden Kanals anders.
Wir sehen nur ein Kanalelement, das aus einem Tupel mit zwei Elementen besteht: dem Teil des simpleName, der von den beiden Dateien geteilt wird und als Bezeichner dient, und einem Tupel mit den beiden Dateiobjekten im Format id, [ file1, file2 ].
Das ist großartig, denn Nextflow hat die schwere Arbeit erledigt, den Patientennamen zu extrahieren, indem es das gemeinsame Präfix untersucht und es als Patientenbezeichner verwendet hat.
Allerdings bricht das unseren aktuellen Workflow.
Wenn wir COUNT_LINES weiterhin auf die gleiche Weise ausführen wollten, ohne den Prozess zu ändern, müssten wir eine Mapping-Operation anwenden, um die Dateipfade zu extrahieren.
Das werden wir aber nicht tun, da unser eigentliches Ziel ist, einen anderen Prozess, ANALYZE_READS, zu verwenden, der Dateipaare entsprechend verarbeitet.
Also kommentieren wir einfach den Aufruf von COUNT_LINES aus (oder löschen ihn) und machen weiter.
Du kannst auch die COUNT_LINES-Include-Anweisung auskommentieren oder löschen, aber das hat keine funktionalen Auswirkungen.
Führen wir den Workflow erneut aus:
Befehlsausgabe
N E X T F L O W ~ version 25.10.2
Launching `main.nf` [fabulous_davinci] DSL2 - revision: 22b53268dc
[patientA_rep1_normal_R, [/workspaces/training/side-quests/working_with_files/data/patientA_rep1_normal_R1_001.fastq.gz, /workspaces/training/side-quests/working_with_files/data/patientA_rep1_normal_R2_001.fastq.gz]]
Diesmal ist der Workflow erfolgreich!
Wir müssen jedoch noch die restlichen Metadaten aus dem id-Feld extrahieren.
5.2. Metadaten aus Dateipaaren extrahieren und organisieren¶
Unsere map-Operation von vorhin wird nicht funktionieren, weil sie nicht zur Datenstruktur passt, aber wir können sie anpassen.
Wir haben bereits Zugriff auf den eigentlichen Patientenbezeichner in dem String, den fromFilePairs() als Bezeichner verwendet hat, sodass wir diesen verwenden können, um die Metadaten zu extrahieren, ohne den simpleName aus dem Path-Objekt zu holen, wie wir es zuvor getan haben.
Kommentiere die map-Operation im Workflow aus und nimm folgende Änderungen vor:
| main.nf | |
|---|---|
Diesmal beginnt die map mit id, files statt nur myFile, und tokenize() wird auf id statt auf myFile.simpleName angewendet.
Beachte auch, dass wir readNum aus der tokenize()-Zeile entfernt haben; alle Teilstrings, die wir nicht explizit benennen (von links beginnend), werden stillschweigend verworfen.
Das können wir tun, weil die gepaarten Dateien jetzt eng miteinander verknüpft sind, sodass wir readNum nicht mehr in der Metadaten-map benötigen.
Führen wir den Workflow aus:
Befehlsausgabe
N E X T F L O W ~ version 25.10.2
Launching `main.nf` [prickly_stonebraker] DSL2 - revision: f62ab10a3f
[[id:patientA, replicate:1, type:normal], [/workspaces/training/side-quests/working_with_files/data/patientA_rep1_normal_R1_001.fastq.gz, /workspaces/training/side-quests/working_with_files/data/patientA_rep1_normal_R2_001.fastq.gz]]
Und da ist es: Wir haben die Metadaten-map ([id:patientA, replicate:1, type:normal]) an der ersten Position des Ausgabe-Tupels, gefolgt vom Tupel der gepaarten Dateien, wie beabsichtigt.
Natürlich wird das nur dieses spezifische Dateipaar aufnehmen und verarbeiten.
Wenn du mit der Verarbeitung mehrerer Paare experimentieren möchtest, kannst du versuchen, Platzhalter in das Eingabemuster einzufügen und sehen, was passiert.
Versuche zum Beispiel data/patientA_rep1_*_R{1,2}_001.fastq.gz zu verwenden.
Fazit¶
channel.fromFilePairs()findet und paart verwandte Dateien automatisch- Das vereinfacht die Verarbeitung von Paired-End-Reads in deiner Pipeline
- Gepaarte Dateien können als
[id, [file1, file2]]-Tupel gruppiert werden - Die Metadatenextraktion kann aus der gepaarten Datei-ID statt aus einzelnen Dateien erfolgen
6. Dateioperationen in Prozessen verwenden¶
Jetzt bringen wir das alles in einem einfachen Prozess zusammen, um zu festigen, wie man Dateioperationen innerhalb eines Nextflow-Prozesses verwendet.
Wir stellen dir ein vorgefertigtes Prozessmodul namens ANALYZE_READS zur Verfügung, das ein Tupel aus Metadaten und einem Paar Eingabedateien entgegennimmt und sie analysiert.
Wir könnten uns vorstellen, dass dies ein Sequenz-Alignment, Variant Calling oder einen anderen Schritt durchführt, der für diesen Datentyp sinnvoll ist.
Fangen wir an.
6.1. Den Prozess importieren und den Code untersuchen¶
Um diesen Prozess im Workflow zu verwenden, müssen wir nur eine Modul-Include-Anweisung vor dem Workflow-Block hinzufügen.
Nimm folgende Änderung am Workflow vor:
Du kannst die Moduldatei öffnen, um ihren Code zu untersuchen:
Hinweis
Die tag- und publishDir-Direktiven verwenden Closure-Syntax ({ ... }) statt String-Interpolation ("${...}").
Das liegt daran, dass diese Direktiven auf Eingabevariablen (meta) verweisen, die erst zur Laufzeit verfügbar sind.
Die Closure-Syntax verzögert die Auswertung, bis der Prozess tatsächlich ausgeführt wird.
Hinweis
Wir nennen unsere Metadaten-map konventionsgemäß meta.
Für einen tieferen Einblick in Meta-Maps, siehe die Side Quest Metadata and meta maps.
6.2. Den Prozess im Workflow aufrufen¶
Da der Prozess jetzt im Workflow verfügbar ist, können wir einen Aufruf des ANALYZE_READS-Prozesses hinzufügen, um ihn auszuführen.
Um ihn auf unseren Beispieldaten auszuführen, müssen wir zwei Dinge tun:
- Dem remappten Kanal einen Namen geben
- Einen Aufruf des Prozesses hinzufügen
6.2.1. Den remappten Eingabekanal benennen¶
Wir haben die Mapping-Manipulationen bisher direkt auf den Eingabekanal angewendet.
Um den remappten Inhalt an den ANALYZE_READS-Prozess zu übergeben (und das auf eine klare und leicht lesbare Weise), wollen wir einen neuen Kanal namens ch_samples erstellen.
Das können wir mit dem set-Operator tun.
Ersetze im Haupt-Workflow den .view()-Operator durch .set { ch_samples } und füge eine Zeile hinzu, die testet, ob wir den Kanal beim Namen ansprechen können.
Führen wir das aus:
Befehlsausgabe
N E X T F L O W ~ version 25.10.2
Launching `main.nf` [goofy_kirch] DSL2 - revision: 3313283e42
[[id:patientA, replicate:1, type:normal], [/workspaces/training/side-quests/working_with_files/data/patientA_rep1_normal_R1_001.fastq.gz, /workspaces/training/side-quests/working_with_files/data/patientA_rep1_normal_R2_001.fastq.gz]]
Das bestätigt, dass wir den Kanal jetzt beim Namen ansprechen können.
6.2.2. Den Prozess auf den Daten aufrufen¶
Jetzt rufen wir den ANALYZE_READS-Prozess tatsächlich auf dem ch_samples-Kanal auf.
Nimm folgende Codeänderungen im Haupt-Workflow vor:
Führen wir das aus:
Befehlsausgabe
Dieser Prozess ist so eingerichtet, dass er seine Ausgaben in ein results-Verzeichnis veröffentlicht, also schau dort nach.
Verzeichnis- und Dateiinhalte
Der Prozess hat unsere Eingaben entgegengenommen und eine neue Datei mit den Patientenmetadaten erstellt, wie vorgesehen. Ausgezeichnet!
6.3. Viele weitere Patient*innen einbeziehen¶
Natürlich verarbeiten wir hier nur ein einzelnes Dateipaar für eine*n einzelne*n Patient*in, was nicht gerade der Hochdurchsatz ist, den du dir von Nextflow erhoffst. Du wirst wahrscheinlich viel mehr Daten auf einmal verarbeiten wollen.
Denke daran, dass channel.fromPath() einen Glob als Eingabe akzeptiert, was bedeutet, dass es eine beliebige Anzahl von Dateien akzeptieren kann, die dem Muster entsprechen.
Wenn wir also alle Patient*innen einbeziehen wollen, können wir einfach den Eingabe-String ändern, um mehr Patient*innen einzuschließen, wie bereits kurz erwähnt.
Stellen wir uns vor, wir wollen so viele Daten wie möglich verarbeiten. Nimm folgende Änderungen am Workflow vor:
Führe die Pipeline erneut aus:
Befehlsausgabe
Das results-Verzeichnis sollte jetzt Ergebnisse für alle verfügbaren Daten enthalten.
Verzeichnisinhalt
Erfolg! Wir haben alle Patient*innen auf einmal analysiert! Oder?
Vielleicht nicht. Wenn du genauer hinschaust, haben wir ein Problem: Wir haben zwei Replikate für patientA, aber nur eine Ausgabedatei! Wir überschreiben die Ausgabedatei jedes Mal.
6.4. Die veröffentlichten Dateien eindeutig machen¶
Da wir Zugriff auf die Patientenmetadaten haben, können wir sie verwenden, um die veröffentlichten Dateien eindeutig zu machen, indem wir differenzierende Metadaten entweder in die Verzeichnisstruktur oder in die Dateinamen selbst einbeziehen.
Nimm folgende Änderung am Workflow vor:
Hier zeigen wir die Option, zusätzliche Verzeichnisebenen zu verwenden, um Probentypen und Replikate zu berücksichtigen, aber du könntest auch auf Dateinamenebene experimentieren.
Führe die Pipeline jetzt noch einmal aus, aber stelle sicher, dass du zuerst das results-Verzeichnis entfernst, um einen sauberen Arbeitsbereich zu haben:
Befehlsausgabe
Überprüfe jetzt das results-Verzeichnis:
Verzeichnisinhalt
results/
├── normal
│ ├── patientA
│ │ ├── 1
│ │ │ └── patientA_stats.txt
│ │ └── 2
│ │ └── patientA_stats.txt
│ ├── patientB
│ │ └── 1
│ │ └── patientB_stats.txt
│ └── patientC
│ └── 1
│ └── patientC_stats.txt
└── tumor
├── patientA
│ ├── 1
│ │ └── patientA_stats.txt
│ └── 2
│ └── patientA_stats.txt
├── patientB
│ └── 1
│ └── patientB_stats.txt
└── patientC
└── 1
└── patientC_stats.txt
Und da ist es – alle unsere Metadaten, ordentlich organisiert. Das ist Erfolg!
Es gibt noch viel mehr, was du tun kannst, sobald du deine Metadaten in eine map geladen hast:
- Organisierte Ausgabeverzeichnisse basierend auf Patientenattributen erstellen
- Entscheidungen in Prozessen basierend auf Patienteneigenschaften treffen
- Daten basierend auf Metadatenwerten aufteilen, zusammenführen und neu kombinieren
Dieses Muster, Metadaten explizit und an die Daten gebunden zu halten (anstatt sie in Dateinamen zu kodieren), ist eine grundlegende Best Practice in Nextflow, die den Aufbau robuster, wartbarer Analyse-Workflows ermöglicht. Mehr dazu erfährst du in der Side Quest Metadata and meta maps.
Fazit¶
- Die
publishDir-Direktive kann Ausgaben basierend auf Metadatenwerten organisieren - Metadaten in Tupeln ermöglichen eine strukturierte Organisation der Ergebnisse
- Dieser Ansatz erstellt wartbare Workflows mit klarer Datenprovenienz
- Prozesse können Tupel aus Metadaten und Dateien als Eingabe entgegennehmen
- Die
tag-Direktive liefert Prozessidentifikation in Ausführungsprotokollen - Die Workflow-Struktur trennt die Kanalerstellung von der Prozessausführung
Zusammenfassung¶
In dieser Side Quest hast du gelernt, wie man mit Dateien in Nextflow arbeitet – von grundlegenden Operationen bis hin zu fortgeschritteneren Techniken für die Verarbeitung von Dateisammlungen.
Die Anwendung dieser Techniken in deiner eigenen Arbeit ermöglicht es dir, effizientere und wartbarere Workflows zu erstellen, insbesondere wenn du mit großen Mengen von Dateien mit komplexen Benennungskonventionen arbeitest.
Wichtige Muster¶
-
Grundlegende Dateioperationen: Wir haben Path-Objekte mit
file()erstellt und auf Dateiattribute wie Name, Erweiterung und übergeordnetes Verzeichnis zugegriffen und dabei den Unterschied zwischen Strings und Path-Objekten kennengelernt.- Ein Path-Objekt mit
file()erstellen
- Dateiattribute abrufen
- Ein Path-Objekt mit
-
Entfernte Dateien verwenden: Wir haben gelernt, wie man transparent zwischen lokalen und entfernten Dateien über URIs wechselt, und dabei Nextflows Fähigkeit demonstriert, Dateien aus verschiedenen Quellen zu verarbeiten, ohne die Workflow-Logik zu ändern.
- Lokale Datei
- FTP
- HTTPS
- Amazon S3
- Azure Blob Storage
- Google Cloud Storage
-
Dateien mit der
fromPath()-Kanal-Factory laden: Wir haben Kanäle aus Dateimustern mitchannel.fromPath()erstellt und ihre Dateiattribute einschließlich Objekttypen angezeigt.- Einen Kanal aus einem Dateimuster erstellen
- Dateiattribute abrufen
-
Patientenmetadaten aus Dateinamen extrahieren: Wir haben
tokenize()undreplace()verwendet, um Metadaten aus Dateinamen zu extrahieren und zu strukturieren und sie in organisierte maps umzuwandeln. -
Vereinfachung mit channel.fromFilePairs: Wir haben
channel.fromFilePairs()verwendet, um verwandte Dateien automatisch zu paaren und Metadaten aus gepaarten Datei-IDs zu extrahieren. -
Dateioperationen in Prozessen verwenden: Wir haben Dateioperationen mit korrekter Eingabeverarbeitung in Nextflow-Prozesse integriert und
publishDirverwendet, um Ausgaben basierend auf Metadaten zu organisieren.- Eine Meta-Map mit den Prozesseingaben verknüpfen
ch_files = channel.fromFilePairs('data/patientA_rep1_normal_R{1,2}_001.fastq.gz') ch_files.map { id, files -> def (sample, replicate, type, readNum) = id.tokenize('_') [ [ id: sample, replicate: replicate.replace('rep', ''), type: type ], files ] } .set { ch_samples } ANALYZE_READS(ch_samples)- Ausgaben basierend auf Metadaten organisieren
Weitere Ressourcen¶
Wie geht es weiter?¶
Kehre zum Menü der Side Quests zurück oder klicke auf die Schaltfläche unten rechts auf der Seite, um zum nächsten Thema in der Liste zu gelangen.