Generate BOS+COM XY overlay visualizations (static PNG and animated GIF) from replace_V3D outputs to see where COM lies relative to BOS over time. Use when asked for "BOS/COM gif", "COM inside/outside BOS", step vs nonstep comparisons, right/left foot stepping trials (step_R/step_L), CCW 90-degree view rotation to match the experiment view, or when you need BOS-freeze at step_onset while keeping COM visible to the end. Uses `scripts/plot_bos_com_xy_sample.py`, `output/all_trials_timeseries.csv`, and optionally reads trial state from `data/perturb_inform.xlsm` (platform sheet).
BOS 사각형(프레임별 min/max) + COM 궤적(누적+현재점)을 같은 XY 평면에 겹쳐서, 시간에 따른 COM의 BOS 내부/외부 위치를 PNG/GIF로 빠르게 확인한다.
scripts/plot_bos_com_xy_sample.pyoutput/all_trials_timeseries.csvdata/perturb_inform.xlsm (platform 시트의 state로 step_R/step_L/nonstep 표시)output/figures/bos_com_xy_sample/이 스킬은 위 파일/경로/로직을 “표준 실행 절차”로 고정해서 반복 생산을 빠르게 하는 목적이다. 스크립트를 복제하지 말고, 필요한 경우에만 scripts/plot_bos_com_xy_sample.py를 수정한다.
conda run -n module python scripts/plot_bos_com_xy_sample.py \
--subject 조민석 --velocity 30 --trial 2 \
--step_vis phase_bos
기본값으로 아래가 적용된다.
--csv output/all_trials_timeseries.csv--event_xlsm data/perturb_inform.xlsm--rotate_ccw_deg 90--fps 20, --frame_step 1, --dpi 180--save_gif 기본 True (--no-save_gif로만 비활성화 가능)--step_vis none)conda run -n module python scripts/plot_bos_com_xy_sample.py \
--subject 이재유 --velocity 20 --trial 1 \
--step_vis none
conda run -n module python scripts/plot_bos_com_xy_sample.py \
--subject 조민석 --velocity 30 --trial 6 \
--step_vis phase_bos
output/all_trials_timeseries.csvscripts/plot_bos_com_xy_sample.py는 아래 컬럼이 최소로 필요하다.
subject, velocity, trialMocapFrameplatform_onset_local, platform_offset_local, step_onset_localCOM_X, COM_YBOS_minX, BOS_maxX, BOS_minY, BOS_maxY옵션 컬럼:
time_from_platform_onset_s가 있으면 GIF 좌상단 패널에 시간(t=... s)을 함께 출력한다.필수 컬럼 누락 시 즉시 에러로 종료한다. (입력 CSV가 “pipeline 결과물”이므로, 이 스크립트는 입력 보정을 하지 않는다.)
data/perturb_inform.xlsm--show_trial_state가 켜져 있으면(기본 True) platform 시트의 아래 컬럼을 읽어서 title subtitle로 표시한다.
subject, velocity, trial, statestate는 아래 값을 기대한다.
step_R, step_L, nonstep, footlift값이 다르거나 매칭 행이 없으면 경고 후 trial_type=unknown으로 표시한다. (플롯 생성 자체는 진행)
--subject --velocity --trial을 모두 주면 해당 trial을 그린다.(subject, velocity, trial) 정렬 기준 “첫 trial”을 자동 선택한다.--rotate_ccw_deg로 화면을 CCW(반시계)로 0/90/180/270도 회전할 수 있다.--rotate_ccw_deg 90이며, 플롯 title에 view=CCW90처럼 명시된다.회전은 “데이터 자체 수정”이 아니라, 플롯 표시를 위해 COM과 BOS bounds 모두에 동일 변환을 적용한다.
scripts/plot_bos_com_xy_sample.py:359 (rotate_xy)scripts/plot_bos_com_xy_sample.py:372 (rotate_box_bounds)축 라벨은 “회전 후 표시 좌표 기준”으로 다음을 사용한다.
X (m) [- Left / + Right]Y (m) [+ Anterior / - Posterior]라벨 위치: scripts/plot_bos_com_xy_sample.py:614, scripts/plot_bos_com_xy_sample.py:744
프레임별로 아래 조건을 만족하면 inside로 판정한다.
BOS_minX <= COM_X <= BOS_maxX and BOS_minY <= COM_Y <= BOS_maxY구현 위치: scripts/plot_bos_com_xy_sample.py:313
유효 프레임(valid frame) 정의:
BOS_min <= BOS_max bounds 순서가 정상인 프레임유효 프레임 필터링 위치: scripts/plot_bos_com_xy_sample.py:300
정적 PNG는 “trial 전체를 한 장”으로 요약한다.
platform_onset: 검정 원platform_offset: 주황 사각형step_onset: 보라 삼각형 (step_onset이 null이면 생략)GIF는 “프레임별로 BOS + 누적 COM + 현재 COM 상태”를 보여준다.
요구사항: step이면 BOS는 step_onset에서 멈추고(COM은 끝까지 계속) nonstep은 예외로 BOS가 계속 갱신.
step_onset_local이 존재하면(step trial로 간주) step_onset 시점의 BOS bounds를 찾아 그 이후 프레임에서 고정한다.step_onset_local이 null이면(nonstep) BOS는 매 프레임 갱신된다.구현 위치: scripts/plot_bos_com_xy_sample.py:653
기본 출력 경로:
output/figures/bos_com_xy_sample/파일명:
<subject>__velocity-<v>__trial-<n>__bos_com_xy_static.png<subject>__velocity-<v>__trial-<n>__bos_com_xy_anim.gifsuffix는 --png_name_suffix, --gif_name_suffix로 바꿀 수 있다.
이 스크립트는 trial을 자동으로 step_R만 골라주진 않는다. (trial state는 “표시용”)
빠른 방법(추천): data/perturb_inform.xlsm의 platform 시트에서
subject == <이름>state == step_R인 행을 찾아 velocity/trial을 그대로 CLI에 넣는다.
터미널에서 빠르게 조회(예시):
conda run -n module python -c \"import pandas as pd; df=pd.read_excel('data/perturb_inform.xlsm', sheet_name='platform'); df=df[['subject','velocity','trial','state']]; print(df[(df['subject'].astype(str).str.strip()=='조민석') & (df['state'].astype(str).str.strip()=='step_R')].sort_values(['velocity','trial']).to_string(index=False))\"
md5sum output/figures/bos_com_xy_sample/*.png output/figures/bos_com_xy_sample/*.gif | sort
같은 명령을 동일 인자로 다시 실행했을 때 MD5가 변하면 비결정성 원인이 있는지 확인한다.
Missing required columns: ...
output/all_trials_timeseries.csv를 생성하는 upstream pipeline을 먼저 점검.Event workbook not found: ...
data/perturb_inform.xlsm 경로가 다름.--event_xlsm로 올바른 xlsm 경로 지정, 또는 --no-show_trial_state로 상태표시를 끄고 진행.No valid frame remains ...
상세 설계/코드 포인터는 references/bos-com-xy-gif-design.md를 참고한다.