콘텐츠로 이동

How-to: 새 분야 팩 만들기

fig-atlas의 코어(fig_atlas)는 분야와 무관합니다. 전기생리, 이미징, 임상처럼 특정 분야의 지식은 분야 팩이라는 별도 패키지에 담고, 코어는 진입점(entry point)으로만 팩을 찾습니다. 오믹스 팩 fig_atlas_omics가 첫 번째 예입니다.

이 문서는 전기생리 팩 fig_atlas_ephys를 예로, 팩을 처음부터 만드는 과정을 보여 줍니다. 아래 코드 블록 중 <!-- file: ... --> 표시가 붙은 것은 tests/test_example_pack.py가 그대로 꺼내 실제 팩을 만들고 인식되는지 확인합니다. 그래서 이 문서의 예제는 항상 동작합니다.

1. 무엇을 팩에 넣나

팩에 넣는 것 예
데이터 읽기·반입 어댑터 ABF/NWB 파일 읽기, 장비 내보내기 형식 변환
번들 계약 어떤 열·파일·메타데이터가 있어야 하는가
레시피 코어 렌더러(모양) + 이 분야의 열 역할·용어·기본값
분석 도우미 스파이크 검출, 입력 저항 계산
이 분야에서만 의미 있는 모양 (드묾) 서열 로고, 유전체 트랙

렌더러는 모양 단위입니다. 선, 막대, 산점도, 히트맵은 처음 쓰는 데이터가 전기생리여도 코어에 둡니다(AGENTS.md §3). 대부분의 분야 그림은 코어 모양에 레시피를 얹는 것으로 충분합니다. 쓸 수 있는 모양은 fa renderers로 봅니다.

2. 패키지 구조

fig_atlas_ephys/
  __init__.py
  contracts.py        # 번들 계약 + plot_type -> 렌더러 매핑
  recipes.py          # 레시피
  cli.py              # (선택) `fa ephys ...` 명령

팩은 코어를 import해도 되지만, 코어는 팩을 import하지 않습니다.

"""Electrophysiology pack for fig-atlas (example from docs/howto/new_domain_pack.md)."""

3. 계약

번들의 metadata.yaml에 적힌 plot_type으로 계약이 정해집니다. required는 그리는 데 꼭 필요한 열(없으면 오류), expected는 문서가 요구하는 나머지 열(없으면 경고)입니다. INGEST는 plot_type을 그릴 함수(또는 레시피 이름)로 잇습니다.

from fig_atlas.contracts import Contract

CONTRACTS = [
    Contract("ephys.iv", ("iv_curve",),
             required=("voltage_mV", "current_pA"),
             expected=("cell",),
             doc="docs/howto/new_domain_pack.md",
             title="Current-voltage steps: one row per (cell, voltage step)"),
]

# plot_type -> "module:function" that draws it
INGEST = {"iv_curve": "fig_atlas_ephys.recipes:render_iv_curve"}

4. 레시피

레시피는 코어 렌더러 하나와, 이 분야에서의 열 역할·기본값을 묶은 데이터입니다. 아래는 I-V 곡선을 코어의 line_band(선 + 오차 띠)로 그리는 레시피입니다. surface는 프로젝트 config에서 쓸 파라미터 이름, aliases는 그 이름과 범용 이름의 대응입니다.

from fig_atlas.recipes import recipe, render

IV_CURVE = recipe(
    "iv_curve", "fig_atlas.renderers.line_band:render_line_band",
    defaults={"x_col": "voltage_mV", "y_col": "current_pA", "error": "sem",
              "labels_xlabel": "Membrane potential (mV)", "labels_ylabel": "Current (pA)",
              "zero_line": True, "show_points": True},
    surface=("error", "show_points", "line_width", "labels_title"),
    aliases={},
)

RECIPES = [IV_CURVE]


def render_iv_curve(ax, df, params=None):
    return render(IV_CURVE, ax, df, params=params)

5. (선택) 명령

팩은 fa 아래에 자기 명령을 붙일 수 있습니다. register는 하위 명령을 만들고 {이름: 처리 함수}를 돌려줍니다. 코어 명령과 이름이 같으면 코어가 우선합니다.

import json


def register(subparsers):
    p = subparsers.add_parser("ephys", help="electrophysiology pack: what it provides")
    p.add_argument("action", choices=("list",))
    return {"ephys": run}


def run(args, root):
    from .contracts import CONTRACTS
    from .recipes import RECIPES
    print(json.dumps({"contracts": [c.name for c in CONTRACTS], "recipes": [r.name for r in RECIPES]}))
    return 0

6. 진입점 등록

팩의 pyproject.toml에 진입점을 적습니다. 그룹은 다섯 가지이고, 필요한 것만 씁니다.

[project.entry-points."fig_atlas.contracts"]
ephys = "fig_atlas_ephys.contracts:CONTRACTS"

[project.entry-points."fig_atlas.ingest"]
ephys = "fig_atlas_ephys.contracts:INGEST"

[project.entry-points."fig_atlas.recipes"]
ephys = "fig_atlas_ephys.recipes:RECIPES"

[project.entry-points."fig_atlas.commands"]
ephys = "fig_atlas_ephys.cli:register"
그룹 값 쓰임
fig_atlas.renderers 렌더러 패키지 ("pack.renderers") 이 분야 고유 모양이 있을 때만
fig_atlas.contracts Contract 목록 fa bundle check
fig_atlas.ingest {plot_type: "module:function"} fa bundle check가 그릴 렌더러를 보여 줌
fig_atlas.recipes Recipe 목록 fig_atlas.render("이름", ...), fa renderers
fig_atlas.commands register(subparsers) 함수 fa <팩 명령>

그다음 설치합니다. 진입점은 설치할 때 등록되므로, 바꿀 때마다 다시 실행합니다.

pip install -e .

7. 확인

fa renderers                    # iv_curve가 recipe로 보여야 합니다
fa bundle contracts             # ephys.iv가 보여야 합니다
fa bundle check <bundle-folder>  # plot_type: iv_curve 번들을 계약으로 검사
fa ephys list                   # 팩의 명령

분석 스크립트에서는 이름으로 그립니다. 레시피가 어느 팩에 있는지 몰라도 됩니다.

import fig_atlas
fig_atlas.render("iv_curve", ax, df, params={"error": "sem"})

팩에 렌더러를 넣었다면 각 렌더러에 SCHEMA가 있어야 하고(tests/test_renderer_schemas.py가 모든 등록 패키지를 검사합니다), 하드코딩된 스타일 값이 없어야 합니다(fa lint --hardcoded).

체크리스트

  • [ ] 모양은 코어 렌더러를 쓰고, 분야 지식은 레시피·계약·도우미로 담았다
  • [ ] 계약마다 사람이 읽는 문서(doc)가 있다
  • [ ] 레시피의 defaults와 aliases는 코어 렌더러의 파라미터 이름만 쓴다
  • [ ] pyproject.toml에 진입점을 적고 pip install -e .를 다시 실행했다
  • [ ] fa renderers, fa bundle contracts에 팩의 항목이 보인다