Move metadata xlsx/TSV to /mnt/data/projects/cupido/
Consolidates everything bulky (tracking DBs, targets, metadata spreadsheet) under a single DATA_VOLUME root outside the ownCloud-synced repo. Notebooks now use a visible DATA_DIR = Path(...) idiom rather than walking up the filesystem with PROJECT_ROOT.parent — easier for students with no Python background to follow. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
ec56e51bf9
commit
f176224150
8 changed files with 102 additions and 160 deletions
|
|
@ -16,7 +16,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# 02 \u00b7 A first look at one tracking database\n",
|
||||
"# 02 · A first look at one tracking database\n",
|
||||
"\n",
|
||||
"In this notebook we open **one** of the SQLite databases that the tracker\n",
|
||||
"produced and look at what's actually inside. By the end you'll be able to:\n",
|
||||
|
|
@ -40,7 +40,7 @@
|
|||
"## Setup\n",
|
||||
"\n",
|
||||
"We import the libraries we need. `sqlite3` is part of Python's standard\n",
|
||||
"library \u2014 no install needed.\n"
|
||||
"library — no install needed.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -71,15 +71,7 @@
|
|||
"metadata": {},
|
||||
"execution_count": null,
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"tracked_dir = Path(\"/mnt/data/projects/cupido/tracked\")\n",
|
||||
"db_files = sorted(tracked_dir.glob(\"*_tracking.db\"))\n",
|
||||
"\n",
|
||||
"print(f\"Found {len(db_files)} tracking DBs.\")\n",
|
||||
"print(\"\\nFirst 5 by name:\")\n",
|
||||
"for db in db_files[:5]:\n",
|
||||
" print(f\" {db.name}\")\n"
|
||||
]
|
||||
"source": "# Single root for all the project's data. Build sub-paths from it.\nDATA_DIR = Path(\"/mnt/data/projects/cupido\")\ntracked_dir = DATA_DIR / \"tracked\"\n\ndb_files = sorted(tracked_dir.glob(\"*_tracking.db\"))\n\nprint(f\"Found {len(db_files)} tracking DBs.\")\nprint(\"\\nFirst 5 by name:\")\nfor db in db_files[:5]:\n print(f\" {db.name}\")\n"
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
|
|
@ -90,7 +82,7 @@
|
|||
"\n",
|
||||
"```\n",
|
||||
"2024-09-17_10-32-10_076e2825a7274661bd0697c42d6fa4c0__1920x1088@25fps-28q_merged_tracking.db\n",
|
||||
"\u2514\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2518\u2514\u2500\u2500\u252c\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n",
|
||||
"└────┬─────┘└──┬──┘ └────────────────┬───────────────┘└──────┬───────┘\n",
|
||||
" date time machine UUID video format\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
|
|
@ -152,7 +144,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"You should see tables like `ROI_1`, `ROI_2`, \u2026, `ROI_6` (one per\n",
|
||||
"You should see tables like `ROI_1`, `ROI_2`, …, `ROI_6` (one per\n",
|
||||
"sub-arena), plus housekeeping tables like `METADATA`, `ROI_MAP`,\n",
|
||||
"`VAR_MAP`, `START_EVENTS`. We mostly care about the `ROI_*` ones.\n",
|
||||
"\n",
|
||||
|
|
@ -187,7 +179,7 @@
|
|||
"- `x`, `y`: fly position in **pixels**. The image origin (0, 0) is the\n",
|
||||
" **top-left** corner. y grows downward.\n",
|
||||
"- `w`, `h`: bounding-box width/height. Their product (`area = w*h`) is a\n",
|
||||
" rough proxy for \"how big does this blob look\" \u2014 useful for spotting\n",
|
||||
" rough proxy for \"how big does this blob look\" — useful for spotting\n",
|
||||
" frames where the tracker merged two flies into one big detection.\n"
|
||||
]
|
||||
},
|
||||
|
|
@ -245,7 +237,7 @@
|
|||
"source": [
|
||||
"The output tells you, e.g., \"100,000 frames had 2 flies visible, 30,000\n",
|
||||
"had 1 fly visible\". Frames with 1 fly usually mean the two flies are\n",
|
||||
"overlapping or one is occluded \u2014 that's something we'll handle properly\n",
|
||||
"overlapping or one is occluded — that's something we'll handle properly\n",
|
||||
"in the next notebook.\n"
|
||||
]
|
||||
},
|
||||
|
|
@ -257,7 +249,7 @@
|
|||
"\n",
|
||||
"We'll plot the position over the first 5 minutes (300 000 ms). For\n",
|
||||
"clarity we'll only look at frames where there were 2 flies and pick the\n",
|
||||
"**first** of the two (sorted by `id`) as \"fly 1\" \u2014 this is a rough\n",
|
||||
"**first** of the two (sorted by `id`) as \"fly 1\" — this is a rough\n",
|
||||
"heuristic; identity tracking is harder than it sounds.\n"
|
||||
]
|
||||
},
|
||||
|
|
@ -280,7 +272,7 @@
|
|||
"plt.gca().invert_yaxis() # because pixel y grows downward\n",
|
||||
"plt.xlabel(\"x (pixels)\")\n",
|
||||
"plt.ylabel(\"y (pixels)\")\n",
|
||||
"plt.title(f\"Fly 1 trajectory \u2014 first 5 min \u2014 {db_path.name[:30]}\u2026\")\n",
|
||||
"plt.title(f\"Fly 1 trajectory — first 5 min — {db_path.name[:30]}…\")\n",
|
||||
"plt.legend()\n",
|
||||
"plt.axis(\"equal\")\n",
|
||||
"plt.show()\n"
|
||||
|
|
@ -293,7 +285,7 @@
|
|||
"You should see a tangle of lines confined to a roughly rectangular ROI.\n",
|
||||
"That tangle is the fly walking around its sub-arena.\n",
|
||||
"\n",
|
||||
"Notice we did `plt.gca().invert_yaxis()` \u2014 that's because in image\n",
|
||||
"Notice we did `plt.gca().invert_yaxis()` — that's because in image\n",
|
||||
"coordinates y grows downward, but humans expect plots where y grows\n",
|
||||
"upward. Without it the plot would be vertically flipped.\n"
|
||||
]
|
||||
|
|
@ -318,7 +310,7 @@
|
|||
"\n",
|
||||
"axes[0].plot(fly1[\"t\"] / 1000, fly1[\"x\"], linewidth=0.5)\n",
|
||||
"axes[0].set_ylabel(\"x (px)\")\n",
|
||||
"axes[0].set_title(f\"Fly 1, ROI 1, {db_path.name[:30]}\u2026\")\n",
|
||||
"axes[0].set_title(f\"Fly 1, ROI 1, {db_path.name[:30]}…\")\n",
|
||||
"\n",
|
||||
"axes[1].plot(fly1[\"t\"] / 1000, fly1[\"y\"], linewidth=0.5, color=\"darkorange\")\n",
|
||||
"axes[1].set_ylabel(\"y (px)\")\n",
|
||||
|
|
@ -344,7 +336,7 @@
|
|||
"## Distance between the two flies\n",
|
||||
"\n",
|
||||
"Whenever the ROI has 2 detections at the same `t`, we can compute the\n",
|
||||
"Euclidean distance between them: `sqrt((x1-x2)\u00b2 + (y1-y2)\u00b2)`.\n"
|
||||
"Euclidean distance between them: `sqrt((x1-x2)² + (y1-y2)²)`.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -399,7 +391,7 @@
|
|||
"## Don't forget to close the connection\n",
|
||||
"\n",
|
||||
"If you opened a connection, close it when you're done. (Not strictly\n",
|
||||
"necessary in a notebook \u2014 Python tidies up \u2014 but a good habit.)\n"
|
||||
"necessary in a notebook — Python tidies up — but a good habit.)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -423,7 +415,7 @@
|
|||
"2. Plot the distance trace for **ROI 4** instead of ROI 1.\n",
|
||||
"3. Compute the **percentage of frames** in ROI 1 that had only 1 fly visible.\n",
|
||||
"4. The `area = w * h` column is a useful diagnostic. Plot `area` vs `t`\n",
|
||||
" for fly 1 \u2014 when does the bounding box get unusually large?\n"
|
||||
" for fly 1 — when does the bounding box get unusually large?\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -436,4 +428,4 @@
|
|||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue