obi-notebook 0.1.dev9__tar.gz → 0.1.dev10__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (21) hide show
  1. {obi_notebook-0.1.dev9 → obi_notebook-0.1.dev10}/PKG-INFO +1 -1
  2. {obi_notebook-0.1.dev9 → obi_notebook-0.1.dev10}/example.ipynb +33 -21
  3. {obi_notebook-0.1.dev9 → obi_notebook-0.1.dev10}/src/obi_notebook/get_entities.py +80 -10
  4. {obi_notebook-0.1.dev9 → obi_notebook-0.1.dev10}/src/obi_notebook.egg-info/PKG-INFO +1 -1
  5. {obi_notebook-0.1.dev9 → obi_notebook-0.1.dev10}/.github/workflows/sdist.yml +0 -0
  6. {obi_notebook-0.1.dev9 → obi_notebook-0.1.dev10}/.github/workflows/tox.yml +0 -0
  7. {obi_notebook-0.1.dev9 → obi_notebook-0.1.dev10}/.gitignore +0 -0
  8. {obi_notebook-0.1.dev9 → obi_notebook-0.1.dev10}/CHANGELOG.rst +0 -0
  9. {obi_notebook-0.1.dev9 → obi_notebook-0.1.dev10}/LICENSE.txt +0 -0
  10. {obi_notebook-0.1.dev9 → obi_notebook-0.1.dev10}/README.md +0 -0
  11. {obi_notebook-0.1.dev9 → obi_notebook-0.1.dev10}/demo.gif +0 -0
  12. {obi_notebook-0.1.dev9 → obi_notebook-0.1.dev10}/pyproject.toml +0 -0
  13. {obi_notebook-0.1.dev9 → obi_notebook-0.1.dev10}/setup.cfg +0 -0
  14. {obi_notebook-0.1.dev9 → obi_notebook-0.1.dev10}/src/obi_notebook/__init__.py +0 -0
  15. {obi_notebook-0.1.dev9 → obi_notebook-0.1.dev10}/src/obi_notebook/get_projects.py +0 -0
  16. {obi_notebook-0.1.dev9 → obi_notebook-0.1.dev10}/src/obi_notebook.egg-info/SOURCES.txt +0 -0
  17. {obi_notebook-0.1.dev9 → obi_notebook-0.1.dev10}/src/obi_notebook.egg-info/dependency_links.txt +0 -0
  18. {obi_notebook-0.1.dev9 → obi_notebook-0.1.dev10}/src/obi_notebook.egg-info/requires.txt +0 -0
  19. {obi_notebook-0.1.dev9 → obi_notebook-0.1.dev10}/src/obi_notebook.egg-info/top_level.txt +0 -0
  20. {obi_notebook-0.1.dev9 → obi_notebook-0.1.dev10}/tox.ini +0 -0
  21. {obi_notebook-0.1.dev9 → obi_notebook-0.1.dev10}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: obi_notebook
3
- Version: 0.1.dev9
3
+ Version: 0.1.dev10
4
4
  Summary: convenience functions for OBI notebooks
5
5
  Author-email: Open Brain Institute <jean-denis.courcol@epfl.ch>
6
6
  Maintainer-email: Open Brain Institute <jean-denis.courcol@epfl.ch>
@@ -8,7 +8,8 @@
8
8
  "outputs": [],
9
9
  "source": [
10
10
  "import obi_auth\n",
11
- "from obi_notebook import get_projects, get_entities"
11
+ "\n",
12
+ "from obi_notebook import get_entities, get_projects"
12
13
  ]
13
14
  },
14
15
  {
@@ -46,12 +47,12 @@
46
47
  {
47
48
  "data": {
48
49
  "application/vnd.jupyter.widget-view+json": {
49
- "model_id": "cc2954a000034b5db323c3c5bb43a985",
50
+ "model_id": "281a37021ded4183b265b05213be6b56",
50
51
  "version_major": 2,
51
52
  "version_minor": 0
52
53
  },
53
54
  "text/plain": [
54
- "Dropdown(description='Select:', options=(('Understanding connectivity', {'id': 'fe443f04-2d56-4c51-8347-8ca5f3…"
55
+ "Dropdown(description='Select:', options=(('My first project', {'id': '7d22829c-edc6-4b1d-8ab9-99dd9e511e74', '…"
55
56
  ]
56
57
  },
57
58
  "metadata": {},
@@ -71,7 +72,7 @@
71
72
  {
72
73
  "data": {
73
74
  "text/plain": [
74
- "ProjectContext(project_id=UUID('fe443f04-2d56-4c51-8347-8ca5f3a97ee6'), virtual_lab_id=UUID('cee1a37f-fe43-4589-9197-c46746aff976'), environment=<DeploymentEnvironment.production: 'production'>)"
75
+ "ProjectContext(project_id=UUID('7d22829c-edc6-4b1d-8ab9-99dd9e511e74'), virtual_lab_id=UUID('5f8376bf-b84f-4188-8ef5-e1df3d7529b4'), environment=<DeploymentEnvironment.production: 'production'>)"
75
76
  ]
76
77
  },
77
78
  "execution_count": 4,
@@ -85,19 +86,19 @@
85
86
  },
86
87
  {
87
88
  "cell_type": "code",
88
- "execution_count": 8,
89
+ "execution_count": 5,
89
90
  "id": "93029f77-d71f-40f4-8c4d-9f23d2b650bc",
90
91
  "metadata": {},
91
92
  "outputs": [
92
93
  {
93
94
  "data": {
94
95
  "application/vnd.jupyter.widget-view+json": {
95
- "model_id": "371c88af967a42a984fdf8fbf362660f",
96
+ "model_id": "62af910b9d8e4094853ad04fa4b62426",
96
97
  "version_major": 2,
97
98
  "version_minor": 0
98
99
  },
99
100
  "text/plain": [
100
- "HBox(children=(Dropdown(description='Scale:', options=('single', 'pair', 'small', 'microcircuit', 'region', 's…"
101
+ "HBox(children=(Dropdown(description='Scale:', index=1, options=('pair', 'small', 'microcircuit', 'region', 'sy…"
101
102
  ]
102
103
  },
103
104
  "metadata": {},
@@ -106,7 +107,7 @@
106
107
  {
107
108
  "data": {
108
109
  "application/vnd.jupyter.widget-view+json": {
109
- "model_id": "3d13a11549b84a3193044113977ba95b",
110
+ "model_id": "d55601c877f54aaa8a0dc6a92a9440d4",
110
111
  "version_major": 2,
111
112
  "version_minor": 0
112
113
  },
@@ -120,27 +121,38 @@
120
121
  ],
121
122
  "source": [
122
123
  "circuit_ids = []\n",
123
- "circuit_ids = get_entities.get_entities(\"circuit\", token, circuit_ids,)"
124
+ "circuit_ids = get_entities.get_entities(\n",
125
+ " \"circuit\",\n",
126
+ " token,\n",
127
+ " circuit_ids,\n",
128
+ " return_entities=False,\n",
129
+ " multi_select=True,\n",
130
+ " show_pages=True,\n",
131
+ " page_size=10,\n",
132
+ " default_scale=\"small\",\n",
133
+ " exclude_scales=[\"single\"],\n",
134
+ " add_columns=[\"subject.name\"],\n",
135
+ ")"
124
136
  ]
125
137
  },
126
138
  {
127
139
  "cell_type": "code",
128
- "execution_count": 9,
140
+ "execution_count": 6,
129
141
  "id": "da699ed4-39fd-4602-b54d-58a0b58c2539",
130
142
  "metadata": {},
131
143
  "outputs": [
132
144
  {
133
145
  "data": {
134
146
  "text/plain": [
135
- "['1be432a7-c7fa-422b-bb47-8b189ede363e',\n",
136
- " 'bf3a620d-5a36-401b-97ac-d27cde014039',\n",
137
- " 'b907f9a6-04e3-4a51-85f6-25ace2c816dc',\n",
138
- " 'ba297b44-9340-4646-8684-01ce31ed33f5',\n",
139
- " '8176966b-cce1-45ef-9642-e87c4436ee7d',\n",
140
- " 'f5e228e7-1c2b-4fa9-89ae-97026c97f83e']"
147
+ "['e9380365-7f37-4b8f-854b-7de929c59a48',\n",
148
+ " '51fd0040-7d0e-424f-b8d9-87cd28321081',\n",
149
+ " 'beb65adc-5d4d-42b2-b45e-dc6ae83e4236',\n",
150
+ " '1eb58db1-9dc9-4b9a-b842-543fb79754dc',\n",
151
+ " '05cfa4e6-a44e-44ce-9005-65f204a406a6',\n",
152
+ " '30a3a072-6e60-4042-8698-01bb0875be63']"
141
153
  ]
142
154
  },
143
- "execution_count": 9,
155
+ "execution_count": 6,
144
156
  "metadata": {},
145
157
  "output_type": "execute_result"
146
158
  }
@@ -152,7 +164,7 @@
152
164
  {
153
165
  "cell_type": "code",
154
166
  "execution_count": null,
155
- "id": "b6b9479f-60b8-4fa1-bd0d-8dbbda0909b8",
167
+ "id": "a5f5445d-a61a-4fbe-962f-51e701434771",
156
168
  "metadata": {},
157
169
  "outputs": [],
158
170
  "source": []
@@ -160,9 +172,9 @@
160
172
  ],
161
173
  "metadata": {
162
174
  "kernelspec": {
163
- "display_name": "Python (myenv)",
175
+ "display_name": "obi-one",
164
176
  "language": "python",
165
- "name": "obi-notebook"
177
+ "name": "obi-one"
166
178
  },
167
179
  "language_info": {
168
180
  "codemirror_mode": {
@@ -174,7 +186,7 @@
174
186
  "name": "python",
175
187
  "nbconvert_exporter": "python",
176
188
  "pygments_lexer": "ipython3",
177
- "version": "3.12.8"
189
+ "version": "3.12.9"
178
190
  }
179
191
  },
180
192
  "nbformat": 4,
@@ -1,9 +1,10 @@
1
1
  """A table widget to select entities."""
2
2
 
3
3
  import ipywidgets as widgets
4
+ import numpy as np
4
5
  import pandas as pd
5
6
  import requests
6
- from entitysdk import Client, models
7
+ from entitysdk import Client, models, types
7
8
  from ipydatagrid import DataGrid, TextRenderer
8
9
  from IPython.display import clear_output, display
9
10
 
@@ -17,24 +18,61 @@ def _estimate_column_widths(df, char_width=8, padding=2, max_size=250):
17
18
 
18
19
 
19
20
  def get_entities(
20
- entity_type, token, result, env="production", project_context=None, return_entities=False
21
+ entity_type,
22
+ token,
23
+ result,
24
+ env="production",
25
+ project_context=None,
26
+ return_entities=False,
27
+ multi_select=True,
28
+ page_size=10,
29
+ show_pages=True,
30
+ add_columns=None,
31
+ default_scale=None,
32
+ exclude_scales=None,
21
33
  ):
22
34
  """Select entities of type entity_type and add them to result.
23
35
 
24
36
  Note: The 'result' parameter is a mutable object (a list) that is modified in-place
25
37
  and also returned.
26
38
  """
39
+ if page_size is not None:
40
+ if page_size <= 0:
41
+ raise ValueError("ERROR: Page size must be larger than 0!")
42
+ # TODO: Could add an upper limit as well here
43
+
44
+ if add_columns is None:
45
+ add_columns = []
46
+ if exclude_scales is None:
47
+ exclude_scales = []
48
+
27
49
  # Widgets
28
50
  filters_dict = {}
29
51
  if entity_type == "circuit":
52
+ scale_options = [
53
+ _scale.value for _scale in types.CircuitScale if _scale.value not in exclude_scales
54
+ ]
55
+ if default_scale is None or default_scale not in scale_options:
56
+ default_scale = scale_options[0]
30
57
  scale_filter = widgets.Dropdown(
31
- options=["single", "pair", "small", "microcircuit", "region", "system", "whole"],
58
+ options=scale_options,
59
+ value=default_scale,
32
60
  description="Scale:",
33
61
  )
34
62
  filters_dict["scale"] = scale_filter
35
63
 
36
64
  filters_dict["name"] = widgets.Text(description="Name:")
37
65
 
66
+ if show_pages:
67
+ filters_dict["page"] = widgets.Dropdown(
68
+ options=[1],
69
+ value=1,
70
+ description="Results page:",
71
+ disabled=False,
72
+ style={"description_width": "auto"},
73
+ layout=widgets.Layout(width="max-content"),
74
+ )
75
+
38
76
  # Output area
39
77
  output = widgets.Output()
40
78
 
@@ -43,7 +81,10 @@ def get_entities(
43
81
 
44
82
  # Fetch and display function
45
83
  def fetch_data(filter_values):
46
- params = {"page_size": 10}
84
+ if page_size is None:
85
+ params = {}
86
+ else:
87
+ params = {"page_size": page_size}
47
88
  for k, v in filter_values.items():
48
89
  if k == "name":
49
90
  params["name__ilike"] = v
@@ -64,10 +105,11 @@ def get_entities(
64
105
  try:
65
106
  data = response.json()
66
107
  df = pd.json_normalize(data["data"])
67
- return df
108
+ pagination = data["pagination"]
109
+ return df, pagination
68
110
  except Exception as e:
69
111
  print("Error fetching or parsing data:", e)
70
- return pd.DataFrame()
112
+ return pd.DataFrame(), None
71
113
 
72
114
  grid = None
73
115
 
@@ -78,7 +120,7 @@ def get_entities(
78
120
  with output:
79
121
  clear_output()
80
122
  filter_values = {k: v.value for k, v in filters_dict.items()}
81
- df = fetch_data(filter_values)
123
+ df, pagination = fetch_data(filter_values)
82
124
 
83
125
  proper_columns = [
84
126
  "id",
@@ -86,12 +128,24 @@ def get_entities(
86
128
  "description",
87
129
  "brain_region.name",
88
130
  "subject.species.name",
89
- ]
131
+ ] + add_columns
90
132
  if len(df) == 0:
91
- print("no results")
133
+ if show_pages and filters_dict["page"].value != 1:
134
+ filters_dict["page"].options = [1] # Will update .value as well
135
+ else:
136
+ print("no results")
92
137
  return
93
138
 
139
+ proper_columns = [_col for _col in proper_columns if _col in df.columns]
94
140
  df = df[proper_columns].reset_index(drop=True)
141
+
142
+ if show_pages:
143
+ num_pages = np.maximum(
144
+ 1, np.ceil(pagination["total_items"] / pagination["page_size"]).astype(int)
145
+ )
146
+ filters_dict["page"].options = range(1, num_pages + 1)
147
+ df.index = df.index + (pagination["page"] - 1) * pagination["page_size"]
148
+
95
149
  column_widths = _estimate_column_widths(df)
96
150
  grid = DataGrid(
97
151
  df,
@@ -99,7 +153,6 @@ def get_entities(
99
153
  # auto_fit_columns=True,
100
154
  auto_fit_params={"area": "all"},
101
155
  selection_mode="row", # Enable row selection
102
- selection_behavior="multi",
103
156
  column_widths=column_widths,
104
157
  )
105
158
  grid.default_renderer = TextRenderer()
@@ -107,6 +160,23 @@ def get_entities(
107
160
 
108
161
  def on_selection_change(event, grid=grid):
109
162
  with output:
163
+ if not multi_select and len(grid.selections) > 0:
164
+ if (event["new"][-1]["r1"] != event["new"][-1]["r2"]) or len(
165
+ grid.selections
166
+ ) > 1: # Multiple rows selected
167
+ if event["new"][-1]["r1"] == event["old"][-1]["r1"]: # r1 unchanged
168
+ new_r = event["new"][-1]["r1"]
169
+ else: # r2 unchanged
170
+ new_r = event["new"][-1]["r2"]
171
+ # Enforce selection of a single row (last one that was selected)
172
+ grid.selections = [
173
+ {
174
+ "r1": new_r,
175
+ "r2": new_r,
176
+ "c1": grid.selections[-1]["c1"],
177
+ "c2": grid.selections[-1]["c2"],
178
+ }
179
+ ]
110
180
  result.clear()
111
181
  l_ids = set()
112
182
  for selection in grid.selections:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: obi_notebook
3
- Version: 0.1.dev9
3
+ Version: 0.1.dev10
4
4
  Summary: convenience functions for OBI notebooks
5
5
  Author-email: Open Brain Institute <jean-denis.courcol@epfl.ch>
6
6
  Maintainer-email: Open Brain Institute <jean-denis.courcol@epfl.ch>