{"id":"flowio","name":"flowio","summary":"Flow IOでFlow Cytometry Standard(FCS)2.0、3.0、3.1ファイルを読み込み、検査し、書き込みできます。","body":"# FlowIO\n\n## Purpose\n\nUse FlowIO as a lightweight, low-level reader and writer for Flow Cytometry\nStandard files. Examples in this skill target **FlowIO 1.4.0**, the current\nstable release verified on 2026-07-23.\n\nFlowIO is appropriate for:\n\n- Reading FCS 2.0, 3.0, and 3.1 files\n- Inspecting HEADER, TEXT, ANALYSIS, and channel metadata\n- Retrieving event data as a two-dimensional NumPy array\n- Reading legacy files that contain multiple datasets\n- Writing list-mode, single-precision FCS 3.1 files\n- Preparing data for pandas, machine-learning, or downstream cytometry tools\n\nFlowIO does **not** perform compensation, logicle/biexponential transforms,\ngating, clustering, or FlowJo workspace processing. Use FlowKit or another\nanalysis package for those tasks.\n\n## Install\n\nCreate or activate a Python environment, then install the verified release:\n\n```bash\nuv pip install \"flowio==1.4.0\"\n```\n\nConfirm the runtime version:\n\n```bash\nuv run python -c \"import flowio; print(flowio.__version__)\"\n```\n\nFlowIO 1.4.0 supports Python 3.9 through 3.13 and depends on NumPy.\n\n## Operating Workflow\n\n1. **Clarify the operation.** Distinguish metadata inventory, event extraction,\n   file repair, conversion, and downstream biological analysis.\n2. **Inspect before loading events.** Use `only_text=True` for metadata-only\n   work, especially with large or unfamiliar files.\n3. **Choose event semantics explicitly.** Use `as_array(preprocess=True)` for\n   gain/log/time scaling from FCS metadata, or `preprocess=False` for values as\n   encoded in the DATA segment. Record the choice.\n4. **Keep parsing strict by default.** Do not automatically suppress offset\n   errors. Relax checks only for a known vendor-format defect, and review the\n   resulting event data.\n5. **Treat metadata as potentially sensitive.** FCS TEXT values can include\n   sample, subject, operator, and instrument identifiers. Export only fields\n   needed for the task.\n6. **Validate writes by reopening them.** Check event/channel counts, labels,\n   metadata, and representative values after any FCS export.\n\n## Critical Semantics\n\n### TEXT keys are normalized\n\n`FlowData.text` stores keys in lowercase and strips the leading `$` from\nstandard FCS keywords:\n\n```python\nfrom flowio import FlowData\n\nflow = FlowData(\"sample.fcs\", only_text=True)\nacquisition_date = flow.text.get(\"date\")\ninstrument = flow.text.get(\"cyt\")\nnext_dataset = int(flow.text.get(\"nextdata\", \"0\"))\n```\n\nDo not look up `\"$DATE\"`, `\"$CYT\"`, or other uppercase dollar-prefixed keys.\nTEXT values remain strings. FlowIO 1.4.0 also removes every `$` character from\nthe decoded TEXT segment, including `$` characters inside values; preserve the\noriginal file when exact metadata fidelity matters.\n\n### Events have two representations\n\n- `flow.events` is the unprocessed, flattened one-dimensional event array.\n- `flow.as_array()` returns shape `(event_count, channel_count)` as a NumPy\n  `float64` array.\n- `flow.as_array(preprocess=True)` applies FCS gain, logarithmic, and time\n  scaling. It does not apply compensation or logicle/biexponential display\n  transforms.\n- `flow.as_array(preprocess=False)` reshapes the encoded event values without\n  those scaling steps.\n\n`as_array()` creates another in-memory array. FlowIO does not provide chunked\nor memory-mapped event access.\n\n### Channel numbering uses two conventions\n\n- NumPy columns and `fluoro_indices`, `scatter_indices`, and `time_index` use\n  zero-based indices.\n- `flow.channels` uses FCS parameter numbers beginning at 1.\n- `null_channels` contains the PnN label strings supplied through\n  `null_channel_list`, including supplied labels that were not found.\n- `pns_labels` always matches `pnn_labels` in length; missing optional PnS\n  labels appear as empty strings.\n\n### Writing is intentionally limited\n\n`create_fcs()` requires:\n\n- An already-open binary file handle\n- Flattened one-dimensional event data in row-major event/channel order\n- One PnN name per channel\n- Optional PnS names and string-valued metadata via `metadata_dict`\n\nIt writes FCS 3.1 list-mode (`$MODE=L`) single-precision float\n(`$DATATYPE=F`) data. Required interpretation keywords are generated by\nFlowIO and cannot be overridden through metadata.\n\n## Quick Start: Read an FCS File\n\n```python\nfrom pathlib import Path\n\nfrom flowio import FlowData\n\nflow = FlowData(Path(\"sample.fcs\"))\nevents = flow.as_array(preprocess=True)\n\nprint(\n    {\n        \"version\": flow.version,\n        \"events\": flow.event_count,\n        \"channels\": flow.channel_count,\n        \"shape\": events.shape,\n        \"pnn\": flow.pnn_labels,\n        \"pns\": flow.pns_labels,\n        \"date\": flow.text.get(\"date\"),\n        \"instrument\": flow.text.get(\"cyt\"),\n    }\n)\n```\n\nFor metadata only:\n\n```python\nfrom flowio import FlowData\n\nflow = FlowData(\"sample.fcs\", only_text=True)\nprint(flow.version, flow.event_count, flow.pnn_labels)\n```\n\nDo not call `as_array()` on a metadata-only instance because its event data was\nnot loaded.\n\nPrefer a path or `Path` over a caller-owned file handle. `FlowData` closes a\nprovided handle after parsing. In FlowIO 1.4.0,\n`read_multiple_data_sets(handle)` can fail after the first dataset because the\nhandle has been closed; pass a filesystem path for multi-dataset files.\n\n## Quick Start: Read Multiple Datasets\n\nUse the standalone helper rather than manually interpreting `$NEXTDATA`\noffsets:\n\n```python\nfrom flowio import read_multiple_data_sets\n\ndatasets = read_multiple_data_sets(\"legacy-multi-dataset.fcs\")\nfor index, dataset in enumerate(datasets):\n    values = dataset.as_array(preprocess=True)\n    print(index, dataset.event_count, dataset.pnn_labels, values.shape)\n```\n\nThe FCS 3.1 specification deprecated multiple datasets in one file, but FlowIO\ncan read legacy files that use them.\n\n## Quick Start: Create an FCS 3.1 File\n\n```python\nfrom pathlib import Path\n\nimport numpy as np\nfrom flowio import FlowData, create_fcs\n\nvalues = np.asarray(\n    [[100.0, 200.0, 50.0], [150.0, 180.0, 60.0]],\n    dtype=np.float32,\n)\npnn_labels = [\"FSC-A\", \"SSC-A\", \"FITC-A\"]\npns_labels = [\"Forward scatter\", \"Side scatter\", \"CD3\"]\n\noutput = Path(\"output.fcs\")\nwith output.open(\"xb\") as handle:\n    create_fcs(\n        handle,\n        values.ravel(order=\"C\"),\n        pnn_labels,\n        opt_channel_names=pns_labels,\n        metadata_dict={\n            \"date\": \"23-JUL-2026\",\n            \"cyt\": \"Example instrument\",\n            \"src\": \"Validated NumPy array\",\n        },\n    )\n\nroundtrip = FlowData(output)\nassert roundtrip.event_count == values.shape[0]\nassert roundtrip.pnn_labels == pnn_labels\nnp.testing.assert_allclose(\n    roundtrip.as_array(preprocess=False),\n    values,\n    rtol=1e-6,\n    atol=1e-6,\n)\n```\n\nMetadata keys may be supplied in mixed case or with `$`, but lowercase keys\nwithout `$` match FlowIO's normalized representation and are less error-prone.\nMetadata values must be strings.\n\n## Copy or Rewrite an Existing File\n\nUse `write_fcs()` when the event data does not need to change:\n\n```python\nfrom flowio import FlowData\n\nflow = FlowData(\"source.fcs\")\n\n# Preserve selected source metadata (cyt, date, and spill/spillover when present).\nflow.write_fcs(\"copy.fcs\")\n\n# Write only required metadata plus the custom fields supplied here.\nflow.write_fcs(\"deidentified.fcs\", metadata={\"src\": \"Deidentified export\"})\n```\n\nPassing `metadata=None` preserves FlowIO's selected defaults. Passing any\ndictionary, including `{}`, replaces those defaults rather than merging with\nthem. `write_fcs()` always produces FCS 3.1 floating-point output; non-float\nsource events are preprocessed before writing. It opens the destination for\noverwrite, so reject an existing output path before calling it unless\nreplacement is intentional. For floating-point sources it can preserve encoded\nevents while dropping PnG or `timestep`, changing later\n`as_array(preprocess=True)` results. Validate both raw and preprocessed\nround-trips.\n\nUse `create_fcs()` instead when event values, event count, or channel layout\nchanges.\n\n## Bundled Inspector\n\n`scripts/inspect_fcs.py` inventories one or more datasets without network\naccess. By default it reads metadata only, emits structural fields and channel\nlabels without full TEXT/ANALYSIS values, and refuses files above a\nconfigurable size limit.\n\nSet `FLOWIO_SKILL_DIR` to the installed skill directory. From this repository's\nroot, use `skills/flowio`:\n\n```bash\nFLOWIO_SKILL_DIR=\"skills/flowio\"\n\n# Metadata and channel inventory\nuv run --no-project --with \"flowio==1.4.0\" \\\n  python \"$FLOWIO_SKILL_DIR/scripts/inspect_fcs.py\" sample.fcs\n\n# Include all normalized TEXT metadata; review output for identifiers\nuv run --no-project --with \"flowio==1.4.0\" \\\n  python \"$FLOWIO_SKILL_DIR/scripts/inspect_fcs.py\" sample.fcs --include-text\n\n# Load events and compute finite-value statistics using FlowIO preprocessing\nuv run --no-project --with \"flowio==1.4.0\" \\\n  python \"$FLOWIO_SKILL_DIR/scripts/inspect_fcs.py\" sample.fcs --stats\n\n# Compute statistics from encoded values instead\nuv run --no-project --with \"flowio==1.4.0\" \\\n  python \"$FLOWIO_SKILL_DIR/scripts/inspect_fcs.py\" sample.fcs --stats --raw\n```\n\nUse `--help` for output files, input/array memory limits, null-channel labels,\nand controlled offset-recovery options.\n\n## References\n\nRead only the reference needed for the current task:\n\n- `references/api_reference.md` — exact FlowIO 1.4.0 public API and signatures\n- `references/workflows.md` — inventory, DataFrame/CSV, batch, write, and\n  round-trip patterns\n- `references/fcs_semantics.md` — FCS structure, metadata normalization,\n  preprocessing equations, indexing, and writer behavior\n- `references/troubleshooting.md` — offset failures, multi-dataset files,\n  memory limits, validation, security, and privacy\n- `references/sources.md` — authoritative upstream docs, release notes, source,\n  and FCS 3.1 publications used for this refresh\n\n## Non-Negotiable Checks\n\n- Never claim FlowIO applies compensation or gating.\n- Never treat `as_array(preprocess=True)` as raw acquisition values.\n- Never pass a two-dimensional array or a path directly to `create_fcs()`.\n- Never assume TEXT keys retain `$` or uppercase spelling.\n- Never silence offset errors without documenting why and validating the data.\n- Never describe FlowIO event loading as streaming or chunked.","author":"@K-Dense-AI","ownerProfile":null,"authorContacts":null,"sourceUrl":"https://github.com/K-Dense-AI/scientific-agent-skills/tree/main/skills/flowio","license":"MIT","category":"writing","lang":"en","tokens":2480,"stars":0,"calls30d":1,"claimed":false,"visibility":"public","origin":"crawler","version":"0.1.0","createdAt":"2026-08-22","updatedAt":"2026-08-22","files":[{"path":"references/api_reference.md","size":11771,"sha256":"7327ec209bdaf9472989beb9beafcf74ddb459ed7fd4e2f036b34d40169c015c"},{"path":"references/fcs_semantics.md","size":9878,"sha256":"77f276e082f003f072c610fc6c04a0935d561ad8622ed4cf07218c6974835f81"},{"path":"references/sources.md","size":4614,"sha256":"774658123b07300922548b3d518db3dfe0240565cc2ba65ca3a1a312515c7ee3"},{"path":"references/troubleshooting.md","size":10967,"sha256":"d57e542594d4c280f191792a5cb923c54f0e117a193e502c71360df2ed38d8b4"},{"path":"references/workflows.md","size":10376,"sha256":"8a304848a31913a9408683b99669289f57f244f9a6910ee27d9e74c31ea9410a"},{"path":"scripts/inspect_fcs.py","size":13735,"sha256":"118a9af5374437d72020de1dfbf0aafc39aaa62d65cb92ef3821d2f5782ce22d"}],"requires":{"mcp":[],"tools":["Read Write Bash"]},"safety":{"flags":[{"code":"net.endpoints","kind":"exfiltration","excerpt":"doi.org, flowio.readthedocs.io, flowkit.readthedocs.io, pmc.ncbi.nlm.nih.gov, pubmed.ncbi.nlm.nih.gov","message":"bundled scripts reach 5 external host(s)","severity":"warn"}],"scannedAt":"2026-08-22","hasScripts":true,"networkEndpoints":["doi.org","flowio.readthedocs.io","flowkit.readthedocs.io","pmc.ncbi.nlm.nih.gov","pubmed.ncbi.nlm.nih.gov"]}}