Skip to content

Commit e98aec1

Browse files
docs: rename ProcessedData to SessionAnalysis in data-entry tutorial
Re-executed against PostgreSQL. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 9cd0c9d commit e98aec1

File tree

1 file changed

+15
-204
lines changed

1 file changed

+15
-204
lines changed

src/tutorials/basics/03-data-entry.ipynb

Lines changed: 15 additions & 204 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
},
4848
{
4949
"cell_type": "code",
50-
"execution_count": 2,
50+
"execution_count": null,
5151
"id": "cell-2",
5252
"metadata": {
5353
"execution": {
@@ -58,60 +58,7 @@
5858
}
5959
},
6060
"outputs": [],
61-
"source": [
62-
"# Define tables for this tutorial\n",
63-
"@schema\n",
64-
"class Lab(dj.Manual):\n",
65-
" definition = \"\"\"\n",
66-
" lab_id : varchar(16)\n",
67-
" ---\n",
68-
" lab_name : varchar(100)\n",
69-
" \"\"\"\n",
70-
"\n",
71-
"@schema\n",
72-
"class Subject(dj.Manual):\n",
73-
" definition = \"\"\"\n",
74-
" subject_id : varchar(16)\n",
75-
" ---\n",
76-
" -> Lab\n",
77-
" species : varchar(50)\n",
78-
" date_of_birth : date\n",
79-
" notes = '' : varchar(1000)\n",
80-
" \"\"\"\n",
81-
"\n",
82-
"@schema\n",
83-
"class Session(dj.Manual):\n",
84-
" definition = \"\"\"\n",
85-
" -> Subject\n",
86-
" session_idx : int32\n",
87-
" ---\n",
88-
" session_date : date\n",
89-
" duration : decimal(4,1) # minutes\n",
90-
" \"\"\"\n",
91-
"\n",
92-
" class Trial(dj.Part):\n",
93-
" definition = \"\"\"\n",
94-
" -> master\n",
95-
" trial_idx : int32\n",
96-
" ---\n",
97-
" outcome : enum('hit', 'miss', 'false_alarm', 'correct_reject')\n",
98-
" reaction_time : decimal(3,2) # seconds\n",
99-
" \"\"\"\n",
100-
"\n",
101-
"@schema\n",
102-
"class ProcessedData(dj.Computed):\n",
103-
" definition = \"\"\"\n",
104-
" -> Session\n",
105-
" ---\n",
106-
" hit_rate : float32\n",
107-
" \"\"\"\n",
108-
" \n",
109-
" def make(self, key):\n",
110-
" outcomes = (Session.Trial & key).to_arrays('outcome')\n",
111-
" n_trials = len(outcomes)\n",
112-
" hit_rate = np.sum(outcomes == 'hit') / n_trials if n_trials else 0.0\n",
113-
" self.insert1({**key, 'hit_rate': hit_rate})"
114-
]
61+
"source": "# Define tables for this tutorial\n@schema\nclass Lab(dj.Manual):\n definition = \"\"\"\n lab_id : varchar(16)\n ---\n lab_name : varchar(100)\n \"\"\"\n\n@schema\nclass Subject(dj.Manual):\n definition = \"\"\"\n subject_id : varchar(16)\n ---\n -> Lab\n species : varchar(50)\n date_of_birth : date\n notes = '' : varchar(1000)\n \"\"\"\n\n@schema\nclass Session(dj.Manual):\n definition = \"\"\"\n -> Subject\n session_idx : int32\n ---\n session_date : date\n duration : decimal(4,1) # minutes\n \"\"\"\n\n class Trial(dj.Part):\n definition = \"\"\"\n -> master\n trial_idx : int32\n ---\n outcome : enum('hit', 'miss', 'false_alarm', 'correct_reject')\n reaction_time : decimal(3,2) # seconds\n \"\"\"\n\n@schema\nclass SessionAnalysis(dj.Computed):\n definition = \"\"\"\n -> Session\n ---\n hit_rate : float32\n \"\"\"\n \n def make(self, key):\n outcomes = (Session.Trial & key).to_arrays('outcome')\n n_trials = len(outcomes)\n hit_rate = np.sum(outcomes == 'hit') / n_trials if n_trials else 0.0\n self.insert1({**key, 'hit_rate': hit_rate})"
11562
},
11663
{
11764
"cell_type": "markdown",
@@ -982,7 +929,7 @@
982929
},
983930
{
984931
"cell_type": "code",
985-
"execution_count": 16,
932+
"execution_count": null,
986933
"id": "cell-29",
987934
"metadata": {
988935
"execution": {
@@ -992,30 +939,12 @@
992939
"shell.execute_reply": "2026-02-19T18:32:34.218561Z"
993940
}
994941
},
995-
"outputs": [
996-
{
997-
"name": "stdout",
998-
"output_type": "stream",
999-
"text": [
1000-
"Sessions: 1\n",
1001-
"Trials: 5\n",
1002-
"ProcessedData: 1\n"
1003-
]
1004-
}
1005-
],
1006-
"source": [
1007-
"# First, let's see what we have\n",
1008-
"print(f\"Sessions: {len(Session())}\")\n",
1009-
"print(f\"Trials: {len(Session.Trial())}\")\n",
1010-
"\n",
1011-
"# Populate computed table\n",
1012-
"ProcessedData.populate()\n",
1013-
"print(f\"ProcessedData: {len(ProcessedData())}\")"
1014-
]
942+
"outputs": [],
943+
"source": "# First, let's see what we have\nprint(f\"Sessions: {len(Session())}\")\nprint(f\"Trials: {len(Session.Trial())}\")\n\n# Populate computed table\nSessionAnalysis.populate()\nprint(f\"SessionAnalysis: {len(SessionAnalysis())}\")"
1015944
},
1016945
{
1017946
"cell_type": "code",
1018-
"execution_count": 17,
947+
"execution_count": null,
1019948
"id": "cell-30",
1020949
"metadata": {
1021950
"execution": {
@@ -1025,48 +954,8 @@
1025954
"shell.execute_reply": "2026-02-19T18:32:34.239434Z"
1026955
}
1027956
},
1028-
"outputs": [
1029-
{
1030-
"name": "stdout",
1031-
"output_type": "stream",
1032-
"text": [
1033-
"[2026-02-19 18:32:34] Deleting 5 rows from \"tutorial_data_entry\".\"session__trial\"\n"
1034-
]
1035-
},
1036-
{
1037-
"name": "stdout",
1038-
"output_type": "stream",
1039-
"text": [
1040-
"[2026-02-19 18:32:34] Deleting 1 rows from \"tutorial_data_entry\".\"__processed_data\"\n"
1041-
]
1042-
},
1043-
{
1044-
"name": "stdout",
1045-
"output_type": "stream",
1046-
"text": [
1047-
"[2026-02-19 18:32:34] Deleting 1 rows from \"tutorial_data_entry\".\"session\"\n"
1048-
]
1049-
},
1050-
{
1051-
"name": "stdout",
1052-
"output_type": "stream",
1053-
"text": [
1054-
"After delete:\n",
1055-
"Sessions: 0\n",
1056-
"Trials: 0\n",
1057-
"ProcessedData: 0\n"
1058-
]
1059-
}
1060-
],
1061-
"source": [
1062-
"# Delete a session - cascades to Trial and ProcessedData\n",
1063-
"(Session & {'subject_id': 'M001', 'session_idx': 1}).delete(prompt=False)\n",
1064-
"\n",
1065-
"print(f\"After delete:\")\n",
1066-
"print(f\"Sessions: {len(Session())}\")\n",
1067-
"print(f\"Trials: {len(Session.Trial())}\")\n",
1068-
"print(f\"ProcessedData: {len(ProcessedData())}\")"
1069-
]
957+
"outputs": [],
958+
"source": "# Delete a session - cascades to Trial and SessionAnalysis\n(Session & {'subject_id': 'M001', 'session_idx': 1}).delete(prompt=False)\n\nprint(f\"After delete:\")\nprint(f\"Sessions: {len(Session())}\")\nprint(f\"Trials: {len(Session.Trial())}\")\nprint(f\"SessionAnalysis: {len(SessionAnalysis())}\")"
1070959
},
1071960
{
1072961
"cell_type": "markdown",
@@ -1159,7 +1048,7 @@
11591048
},
11601049
{
11611050
"cell_type": "code",
1162-
"execution_count": 19,
1051+
"execution_count": null,
11631052
"id": "cell-34",
11641053
"metadata": {
11651054
"execution": {
@@ -1169,39 +1058,12 @@
11691058
"shell.execute_reply": "2026-02-19T18:32:34.262667Z"
11701059
}
11711060
},
1172-
"outputs": [
1173-
{
1174-
"name": "stdout",
1175-
"output_type": "stream",
1176-
"text": [
1177-
"Before correction: {'subject_id': 'M003', 'session_idx': 1, 'hit_rate': 0.5}\n"
1178-
]
1179-
}
1180-
],
1181-
"source": [
1182-
"# Add a session with trials (using transaction for compositional integrity)\n",
1183-
"with dj.conn().transaction:\n",
1184-
" Session.insert1({\n",
1185-
" 'subject_id': 'M003',\n",
1186-
" 'session_idx': 1,\n",
1187-
" 'session_date': '2026-01-08',\n",
1188-
" 'duration': 40.0\n",
1189-
" })\n",
1190-
" Session.Trial.insert([\n",
1191-
" {'subject_id': 'M003', 'session_idx': 1, 'trial_idx': 1,\n",
1192-
" 'outcome': 'hit', 'reaction_time': 0.35},\n",
1193-
" {'subject_id': 'M003', 'session_idx': 1, 'trial_idx': 2,\n",
1194-
" 'outcome': 'miss', 'reaction_time': 0.50},\n",
1195-
" ])\n",
1196-
"\n",
1197-
"# Compute results\n",
1198-
"ProcessedData.populate()\n",
1199-
"print(\"Before correction:\", ProcessedData.fetch1())"
1200-
]
1061+
"outputs": [],
1062+
"source": "# Add a session with trials (using transaction for compositional integrity)\nwith dj.conn().transaction:\n Session.insert1({\n 'subject_id': 'M003',\n 'session_idx': 1,\n 'session_date': '2026-01-08',\n 'duration': 40.0\n })\n Session.Trial.insert([\n {'subject_id': 'M003', 'session_idx': 1, 'trial_idx': 1,\n 'outcome': 'hit', 'reaction_time': 0.35},\n {'subject_id': 'M003', 'session_idx': 1, 'trial_idx': 2,\n 'outcome': 'miss', 'reaction_time': 0.50},\n ])\n\n# Compute results\nSessionAnalysis.populate()\nprint(\"Before correction:\", SessionAnalysis.fetch1())"
12011063
},
12021064
{
12031065
"cell_type": "code",
1204-
"execution_count": 20,
1066+
"execution_count": null,
12051067
"id": "cell-35",
12061068
"metadata": {
12071069
"execution": {
@@ -1211,59 +1073,8 @@
12111073
"shell.execute_reply": "2026-02-19T18:32:34.287511Z"
12121074
}
12131075
},
1214-
"outputs": [
1215-
{
1216-
"name": "stdout",
1217-
"output_type": "stream",
1218-
"text": [
1219-
"[2026-02-19 18:32:34] Deleting 2 rows from \"tutorial_data_entry\".\"session__trial\"\n"
1220-
]
1221-
},
1222-
{
1223-
"name": "stdout",
1224-
"output_type": "stream",
1225-
"text": [
1226-
"[2026-02-19 18:32:34] Deleting 1 rows from \"tutorial_data_entry\".\"__processed_data\"\n"
1227-
]
1228-
},
1229-
{
1230-
"name": "stdout",
1231-
"output_type": "stream",
1232-
"text": [
1233-
"[2026-02-19 18:32:34] Deleting 1 rows from \"tutorial_data_entry\".\"session\"\n"
1234-
]
1235-
},
1236-
{
1237-
"name": "stdout",
1238-
"output_type": "stream",
1239-
"text": [
1240-
"After correction: {'subject_id': 'M003', 'session_idx': 1, 'hit_rate': 1.0}\n"
1241-
]
1242-
}
1243-
],
1244-
"source": [
1245-
"# Suppose we discovered trial 2 was actually a 'hit' not 'miss'\n",
1246-
"# WRONG: Updating the trial would leave ProcessedData stale!\n",
1247-
"# Session.Trial.update1({...}) # DON'T DO THIS\n",
1248-
"\n",
1249-
"# CORRECT: Delete, reinsert, recompute\n",
1250-
"key = {'subject_id': 'M003', 'session_idx': 1}\n",
1251-
"\n",
1252-
"# 1. Delete cascades to ProcessedData\n",
1253-
"(Session & key).delete(prompt=False)\n",
1254-
"\n",
1255-
"# 2. Reinsert with corrected data (using transaction)\n",
1256-
"with dj.conn().transaction:\n",
1257-
" Session.insert1({**key, 'session_date': '2026-01-08', 'duration': 40.0})\n",
1258-
" Session.Trial.insert([\n",
1259-
" {**key, 'trial_idx': 1, 'outcome': 'hit', 'reaction_time': 0.35},\n",
1260-
" {**key, 'trial_idx': 2, 'outcome': 'hit', 'reaction_time': 0.50},\n",
1261-
" ])\n",
1262-
"\n",
1263-
"# 3. Recompute\n",
1264-
"ProcessedData.populate()\n",
1265-
"print(\"After correction:\", ProcessedData.fetch1())"
1266-
]
1076+
"outputs": [],
1077+
"source": "# Suppose we discovered trial 2 was actually a 'hit' not 'miss'\n# WRONG: Updating the trial would leave SessionAnalysis stale!\n# Session.Trial.update1({...}) # DON'T DO THIS\n\n# CORRECT: Delete, reinsert, recompute\nkey = {'subject_id': 'M003', 'session_idx': 1}\n\n# 1. Delete cascades to SessionAnalysis\n(Session & key).delete(prompt=False)\n\n# 2. Reinsert with corrected data (using transaction)\nwith dj.conn().transaction:\n Session.insert1({**key, 'session_date': '2026-01-08', 'duration': 40.0})\n Session.Trial.insert([\n {**key, 'trial_idx': 1, 'outcome': 'hit', 'reaction_time': 0.35},\n {**key, 'trial_idx': 2, 'outcome': 'hit', 'reaction_time': 0.50},\n ])\n\n# 3. Recompute\nSessionAnalysis.populate()\nprint(\"After correction:\", SessionAnalysis.fetch1())"
12671078
},
12681079
{
12691080
"cell_type": "markdown",
@@ -1528,4 +1339,4 @@
15281339
},
15291340
"nbformat": 4,
15301341
"nbformat_minor": 5
1531-
}
1342+
}

0 commit comments

Comments
 (0)