fulviodeo commited on
Commit
3cd0ccc
·
1 Parent(s): eafd831

Abstracted button styles. Changed layout of loading section

Browse files
notebooks/notebook.ipynb CHANGED
@@ -11,269 +11,7 @@
11
  }
12
  },
13
  "outputs": [],
14
- "source": [
15
- "import subprocess\n",
16
- "from datetime import date\n",
17
- "from dateutil.relativedelta import relativedelta\n",
18
- "import os\n",
19
- "import ipywidgets as widgets\n",
20
- "from IPython.display import HTML, clear_output\n",
21
- "import warnings\n",
22
- "warnings.filterwarnings(\"ignore\")\n",
23
- "\n",
24
- "from src.handlers.model_wrapper import available_models\n",
25
- "\n",
26
- "# --- UI Elements ---\n",
27
- "\n",
28
- "model_dropdown = widgets.Dropdown(\n",
29
- " options=[m.name for m in available_models],\n",
30
- " value=available_models[0].name,\n",
31
- " description='',\n",
32
- " disabled=True,\n",
33
- " layout=widgets.Layout(width='300px')\n",
34
- ")\n",
35
- "\n",
36
- "selected_model = available_models[0]\n",
37
- "\n",
38
- "query_method = widgets.RadioButtons(\n",
39
- " options=['default', 'custom'],\n",
40
- " value='default',\n",
41
- " layout=widgets.Layout(width='180px')\n",
42
- ")\n",
43
- "\n",
44
- "custom_query_file = widgets.Text(\n",
45
- " placeholder='Enter query filename',\n",
46
- " description='',\n",
47
- " disabled=True,\n",
48
- " layout=widgets.Layout(width='300px')\n",
49
- ")\n",
50
- "\n",
51
- "def toggle_custom_query(change):\n",
52
- " custom_query_file.disabled = (change.new != 'custom')\n",
53
- "\n",
54
- "query_method.observe(toggle_custom_query, names='value')\n",
55
- "\n",
56
- "start_date_value = date.today() - relativedelta(months=1)\n",
57
- "end_date_value = date.today()\n",
58
- "\n",
59
- "start_date = widgets.DatePicker(\n",
60
- " description='Start date: ',\n",
61
- " value=start_date_value\n",
62
- ")\n",
63
- "\n",
64
- "end_date = widgets.DatePicker(\n",
65
- " description='End Date: ',\n",
66
- " value=end_date_value\n",
67
- ")\n",
68
- "\n",
69
- "recall_target = widgets.Dropdown(\n",
70
- " options=[('95%', 95), ('90%', 90), ('80%', 80), ('70%', 70), ('60%', 60)],\n",
71
- " value=95,\n",
72
- " description='',\n",
73
- " layout=widgets.Layout(width='120px')\n",
74
- ")\n",
75
- "\n",
76
- "# Button style\n",
77
- "display(HTML(\"\"\"\n",
78
- "<style>\n",
79
- ".widget-button {\n",
80
- " justify-content: flex-start !important;\n",
81
- " text-align: left !important;\n",
82
- " font-weight: bold !important;\n",
83
- " font-size: 15px !important;\n",
84
- " padding-left: 12px !important;\n",
85
- "}\n",
86
- "</style>\n",
87
- "\"\"\"))\n",
88
- "\n",
89
- "load_btn = widgets.Button(\n",
90
- " description='Load',\n",
91
- " layout=widgets.Layout(width='100px'),\n",
92
- " style=widgets.ButtonStyle(font_weight='bold')\n",
93
- ")\n",
94
- "\n",
95
- "download_btn = widgets.Button(\n",
96
- " description='Download abstracts from PubMed',\n",
97
- " layout=widgets.Layout(width='300px'),\n",
98
- " style=widgets.ButtonStyle(font_weight='bold')\n",
99
- ")\n",
100
- "\n",
101
- "predict_btn = widgets.Button(\n",
102
- " description='Run the model and screen articles',\n",
103
- " layout=widgets.Layout(width='300px'),\n",
104
- " style=widgets.ButtonStyle(font_weight='bold')\n",
105
- ")\n",
106
- "\n",
107
- "# Output areas\n",
108
- "download_output = widgets.Output()\n",
109
- "load_model_output = widgets.Output()\n",
110
- "predict_output = widgets.Output()\n",
111
- "\n",
112
- "\n",
113
- "# --- Helper ---\n",
114
- "def mark_done(output_placeholder, header_widget):\n",
115
- " output_placeholder.clear_output()\n",
116
- " with output_placeholder:\n",
117
- " display(header_widget)\n",
118
- " display(widgets.HTML(\n",
119
- " \"<span style='color: green; font-weight: bold; font-size:15px; margin-left:12px;'>&#10004; Done</span>\"\n",
120
- " ))\n",
121
- "\n",
122
- "\n",
123
- "# --- Event Handlers ---\n",
124
- "\n",
125
- "def run_load_model(b):\n",
126
- " b.close()\n",
127
- " with load_model_output:\n",
128
- " clear_output(wait=True)\n",
129
- " header = widgets.HTML(\n",
130
- " \"<div style='font-size:15px; font-weight:bold; margin-left:12px;'>Load the model</div>\"\n",
131
- " )\n",
132
- " display(header)\n",
133
- " try:\n",
134
- " print(' Loading the model...')\n",
135
- " with open(os.path.abspath(os.path.join(os.getcwd(), 'src/load_model.py'))) as f:\n",
136
- " exec(f.read(), globals())\n",
137
- " mark_done(load_model_output, header)\n",
138
- " except Exception:\n",
139
- " import traceback\n",
140
- " traceback.print_exc()\n",
141
- "\n",
142
- "\n",
143
- "def run_download_citations(b):\n",
144
- " b.close()\n",
145
- " with download_output:\n",
146
- " clear_output(wait=True)\n",
147
- " header = widgets.HTML(\n",
148
- " \"<div style='font-size:15px; font-weight:bold; margin-left:12px;'>Download abstracts from PubMed</div>\"\n",
149
- " )\n",
150
- " display(header)\n",
151
- " try:\n",
152
- " print(f' Downloading articles published between {start_date.value} and {end_date.value}...')\n",
153
- " with open(os.path.abspath(os.path.join(os.getcwd(), 'src/download_citations.py'))) as f:\n",
154
- " exec(f.read(), globals())\n",
155
- " mark_done(download_output, header)\n",
156
- " path_to_articles = os.path.join(globals().get('directory'), 'downloaded_articles.csv')\n",
157
- " display(widgets.HTML(\n",
158
- " f\"<p style='font-size:12px; color:gray; margin-top:6px; margin-left:12px; margin-bottom:0px;'>\"\n",
159
- " f\"Article abstracts downloaded to: {path_to_articles}</p>\"\n",
160
- " ))\n",
161
- " except Exception:\n",
162
- " import traceback\n",
163
- " traceback.print_exc()\n",
164
- "\n",
165
- "\n",
166
- "def open_ris_file(b):\n",
167
- " path = os.path.join(globals().get('directory'), 'articles_to_review.ris')\n",
168
- " try:\n",
169
- " if os.name == 'posix':\n",
170
- " subprocess.Popen(['open', path])\n",
171
- " elif os.name == 'nt':\n",
172
- " subprocess.Popen(['start', '', path], shell=True)\n",
173
- " except Exception:\n",
174
- " import traceback\n",
175
- " traceback.print_exc()\n",
176
- "\n",
177
- "\n",
178
- "def run_prediction(b):\n",
179
- " b.close()\n",
180
- " with predict_output:\n",
181
- " clear_output(wait=True)\n",
182
- " header = widgets.HTML(\n",
183
- " \"<div style='font-size:15px; font-weight:bold; margin-left:12px;'>Run the model and screen articles</div>\"\n",
184
- " )\n",
185
- " display(header)\n",
186
- " try:\n",
187
- " print(' Running the model...')\n",
188
- " with open(os.path.abspath(os.path.join(os.getcwd(), 'src/predict.py'))) as f:\n",
189
- " exec(f.read(), globals())\n",
190
- " mark_done(predict_output, header)\n",
191
- " except Exception:\n",
192
- " import traceback\n",
193
- " traceback.print_exc()\n",
194
- "\n",
195
- " path_to_ris = os.path.join(globals().get('directory'), 'articles_to_review.ris')\n",
196
- " open_file_btn = widgets.Button(description='📄 Open in EndNote', layout=widgets.Layout(width='350px'))\n",
197
- " open_file_btn.on_click(open_ris_file)\n",
198
- " path_display = widgets.HTML(\n",
199
- " f\"<p style='font-size:12px; color:gray; margin-top:6px; margin-left:12px;'>\"\n",
200
- " f\"Path to the EndNote file: {path_to_ris}</p>\"\n",
201
- " )\n",
202
- " final_message_1 = widgets.HTML(\n",
203
- " \"<p style='font-size:14px; color:black; margin-top:10px; margin-left:12px;'>\"\n",
204
- " \"Open the .ris file in EndNote by clicking on the button above or navigating to the file</p>\"\n",
205
- " )\n",
206
- " final_message_2 = widgets.HTML(\n",
207
- " \"<p style='font-size:14px; color:black; margin-top:10px; margin-left:12px;'>\"\n",
208
- " \"Select RefMan - RIS as the input file format</p>\"\n",
209
- " )\n",
210
- " with predict_output:\n",
211
- " display(widgets.VBox([open_file_btn, path_display, final_message_1, final_message_2]))\n",
212
- "\n",
213
- "\n",
214
- "load_btn.on_click(run_load_model)\n",
215
- "download_btn.on_click(run_download_citations)\n",
216
- "predict_btn.on_click(run_prediction)\n",
217
- "\n",
218
- "# --- Layout ---\n",
219
- "\n",
220
- "title_style = 'font-size: 22px; font-weight: bold; margin-bottom: 40px;'\n",
221
- "\n",
222
- "header = widgets.HTML(\n",
223
- " f\"<h2 style='margin-left:12px; {title_style}'>Automated screening of the literature</h2>\"\n",
224
- ")\n",
225
- "\n",
226
- "# 1 - Choose model\n",
227
- "choose_model_content = widgets.VBox([\n",
228
- " widgets.HTML(\"<b style='font-size:16px;'>Choose a model</b>\"),\n",
229
- " model_dropdown,\n",
230
- " load_model_output,\n",
231
- "], layout=widgets.Layout(margin='0 0 0 12px'))\n",
232
- "\n",
233
- "choose_model = widgets.HBox([\n",
234
- " choose_model_content,\n",
235
- " load_btn,\n",
236
- "], layout=widgets.Layout(justify_content='space-between', align_items='flex-end'))\n",
237
- "\n",
238
- "sep1 = widgets.HTML(\"<hr style='margin: 20px 12px; border: none; border-top: 1px solid #ccc;'>\")\n",
239
- "\n",
240
- "# 2 - Search PubMed\n",
241
- "search_pubmed = widgets.VBox([\n",
242
- " widgets.HTML(\"<b style='font-size:16px;'>Define the PubMed search</b>\"),\n",
243
- " widgets.HBox([\n",
244
- " widgets.VBox([\n",
245
- " start_date,\n",
246
- " end_date\n",
247
- " ], layout=widgets.Layout(margin='0 20px 0 0')),\n",
248
- " widgets.VBox([\n",
249
- " widgets.HBox([\n",
250
- " widgets.Label('Query: ', layout=widgets.Layout(width='60px')),\n",
251
- " query_method\n",
252
- " ]),\n",
253
- " custom_query_file\n",
254
- " ], layout=widgets.Layout(margin='0 0 0 20px'))\n",
255
- " ], layout=widgets.Layout(justify_content='flex-start', gap='20px', margin='10px 0')),\n",
256
- " widgets.HTML(\"<div style='height:15px;'></div>\"),\n",
257
- " download_btn,\n",
258
- " download_output,\n",
259
- "], layout=widgets.Layout(margin='0 0 0 12px'))\n",
260
- "\n",
261
- "sep2 = widgets.HTML(\"<hr style='margin: 20px 12px; border: none; border-top: 1px solid #ccc;'>\")\n",
262
- "\n",
263
- "# 3 - Screen articles\n",
264
- "screen_articles = widgets.VBox([\n",
265
- " widgets.HTML(\"<b style='font-size:16px;'>Define how inclusive the model should be</b>\"),\n",
266
- " widgets.HTML(\"<span style='font-size:13px; color:gray; margin-top:2px; display:block;'>Based on the recall achieved in previous testing; the higher the recall, the more inclusive the model</span>\"),\n",
267
- " widgets.HTML(\"<div style='height:8px;'></div>\"),\n",
268
- " recall_target,\n",
269
- " widgets.HTML(\"<div style='height:15px;'></div>\"),\n",
270
- " predict_btn,\n",
271
- " predict_output\n",
272
- "], layout=widgets.Layout(margin='0 0 0 12px'))\n",
273
- "\n",
274
- "\n",
275
- "display(header, choose_model, sep1, search_pubmed, sep2, screen_articles)"
276
- ]
277
  },
278
  {
279
  "cell_type": "code",
@@ -306,4 +44,4 @@
306
  },
307
  "nbformat": 4,
308
  "nbformat_minor": 5
309
- }
 
11
  }
12
  },
13
  "outputs": [],
14
+ "source": "import subprocess\nfrom datetime import date\nfrom dateutil.relativedelta import relativedelta\nimport os\nimport ipywidgets as widgets\nfrom IPython.display import clear_output\nimport warnings\nwarnings.filterwarnings(\"ignore\")\n\nfrom src.handlers.model_wrapper import available_models\nfrom src.utils.ui_elements import inject_styles, make_button, set_executing, set_done, set_error\n\ninject_styles()\n\n# --- UI Elements ---\n\nmodel_dropdown = widgets.Dropdown(\n options=[m.name for m in available_models],\n value=available_models[0].name,\n description='',\n disabled=False,\n layout=widgets.Layout(width='300px')\n)\n\nselected_model = available_models[0]\n\nquery_method = widgets.RadioButtons(\n options=['default', 'custom'],\n value='default',\n layout=widgets.Layout(width='180px')\n)\n\ncustom_query_file = widgets.Text(\n placeholder='Enter query filename',\n description='',\n disabled=True,\n layout=widgets.Layout(width='300px')\n)\n\ndef toggle_custom_query(change):\n custom_query_file.disabled = (change.new != 'custom')\n\nquery_method.observe(toggle_custom_query, names='value')\n\nstart_date_value = date.today() - relativedelta(months=1)\nend_date_value = date.today()\n\nstart_date = widgets.DatePicker(\n description='Start date: ',\n value=start_date_value\n)\n\nend_date = widgets.DatePicker(\n description='End Date: ',\n value=end_date_value\n)\n\nrecall_target = widgets.Dropdown(\n options=[('95%', 95), ('90%', 90), ('80%', 80), ('70%', 70), ('60%', 60)],\n value=95,\n description='',\n layout=widgets.Layout(width='120px')\n)\n\n# Buttons\nload_btn = make_button('Load', width='300px')\ndownload_btn = make_button('Download abstracts from PubMed')\npredict_btn = make_button('Run the model and screen articles')\n\n# Output areas\nload_model_output = widgets.Output()\ndownload_output = widgets.Output()\npredict_output = widgets.Output()\n\n\n# --- Event Handlers ---\n\ndef run_load_model(b):\n set_executing(load_btn, 'Loading...')\n with load_model_output:\n clear_output(wait=True)\n try:\n with open(os.path.abspath(os.path.join(os.getcwd(), 'src/load_model.py'))) as f:\n exec(f.read(), globals())\n set_done(load_btn, '\\u2713 Loaded')\n except Exception:\n set_error(load_btn, 'Load')\n import traceback\n traceback.print_exc()\n\n\ndef run_download_citations(b):\n set_executing(download_btn, 'Downloading...')\n with download_output:\n clear_output(wait=True)\n try:\n with open(os.path.abspath(os.path.join(os.getcwd(), 'src/download_citations.py'))) as f:\n exec(f.read(), globals())\n set_done(download_btn, '\\u2713 Downloaded')\n path_to_articles = os.path.join(globals().get('directory'), 'downloaded_articles.csv')\n with download_output:\n display(widgets.HTML(\n f\"<p style='font-size:12px; color:gray; margin-top:6px; margin-left:12px; margin-bottom:0px;'>\"\n f\"Article abstracts downloaded to: {path_to_articles}</p>\"\n ))\n except Exception:\n set_error(download_btn, 'Download abstracts from PubMed')\n import traceback\n traceback.print_exc()\n\n\ndef open_ris_file(b):\n path = os.path.join(globals().get('directory'), 'articles_to_review.ris')\n try:\n if os.name == 'posix':\n subprocess.Popen(['open', path])\n elif os.name == 'nt':\n subprocess.Popen(['start', '', path], shell=True)\n except Exception:\n import traceback\n traceback.print_exc()\n\n\ndef run_prediction(b):\n set_executing(predict_btn, 'Running...')\n with predict_output:\n clear_output(wait=True)\n try:\n with open(os.path.abspath(os.path.join(os.getcwd(), 'src/predict.py'))) as f:\n exec(f.read(), globals())\n set_done(predict_btn, '\\u2713 Done')\n except Exception:\n set_error(predict_btn, 'Run the model and screen articles')\n import traceback\n traceback.print_exc()\n\n path_to_ris = os.path.join(globals().get('directory'), 'articles_to_review.ris')\n open_file_btn = make_button('📄 Open in EndNote', width='350px')\n open_file_btn.on_click(open_ris_file)\n path_display = widgets.HTML(\n f\"<p style='font-size:12px; color:gray; margin-top:6px; margin-left:12px;'>\"\n f\"Path to the EndNote file: {path_to_ris}</p>\"\n )\n final_message_1 = widgets.HTML(\n \"<p style='font-size:14px; color:black; margin-top:10px; margin-left:12px;'>\"\n \"Open the .ris file in EndNote by clicking on the button above or navigating to the file</p>\"\n )\n final_message_2 = widgets.HTML(\n \"<p style='font-size:14px; color:black; margin-top:10px; margin-left:12px;'>\"\n \"Select RefMan - RIS as the input file format</p>\"\n )\n with predict_output:\n display(widgets.VBox([open_file_btn, path_display, final_message_1, final_message_2]))\n\n\nload_btn.on_click(run_load_model)\ndownload_btn.on_click(run_download_citations)\npredict_btn.on_click(run_prediction)\n\n# --- Layout ---\n\ntitle_style = 'font-size: 22px; font-weight: bold; margin-bottom: 40px;'\n\nheader = widgets.HTML(\n f\"<h2 style='margin-left:12px; {title_style}'>Automated screening of the literature</h2>\"\n)\n\n# 1 - Choose model\nchoose_model = widgets.VBox([\n widgets.HTML(\"<b style='font-size:16px;'>Choose a model</b>\"),\n model_dropdown,\n load_btn,\n load_model_output,\n], layout=widgets.Layout(margin='0 0 0 12px'))\n\nsep1 = widgets.HTML(\"<hr style='margin: 20px 12px; border: none; border-top: 1px solid #ccc;'>\")\n\n# 2 - Search PubMed\nsearch_pubmed = widgets.VBox([\n widgets.HTML(\"<b style='font-size:16px;'>Define the PubMed search</b>\"),\n widgets.HBox([\n widgets.VBox([\n start_date,\n end_date\n ], layout=widgets.Layout(margin='0 20px 0 0')),\n widgets.VBox([\n widgets.HBox([\n widgets.Label('Query: ', layout=widgets.Layout(width='60px')),\n query_method\n ]),\n custom_query_file\n ], layout=widgets.Layout(margin='0 0 0 20px'))\n ], layout=widgets.Layout(justify_content='flex-start', gap='20px', margin='10px 0')),\n widgets.HTML(\"<div style='height:15px;'></div>\"),\n download_btn,\n download_output,\n], layout=widgets.Layout(margin='0 0 0 12px'))\n\nsep2 = widgets.HTML(\"<hr style='margin: 20px 12px; border: none; border-top: 1px solid #ccc;'>\")\n\n# 3 - Screen articles\nscreen_articles = widgets.VBox([\n widgets.HTML(\"<b style='font-size:16px;'>Define how inclusive the model should be</b>\"),\n widgets.HTML(\"<span style='font-size:13px; color:gray; margin-top:2px; display:block;'>Based on the recall achieved in previous testing; the higher the recall, the more inclusive the model</span>\"),\n widgets.HTML(\"<div style='height:8px;'></div>\"),\n recall_target,\n widgets.HTML(\"<div style='height:15px;'></div>\"),\n predict_btn,\n predict_output\n], layout=widgets.Layout(margin='0 0 0 12px'))\n\n\ndisplay(header, choose_model, sep1, search_pubmed, sep2, screen_articles)"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  },
16
  {
17
  "cell_type": "code",
 
44
  },
45
  "nbformat": 4,
46
  "nbformat_minor": 5
47
+ }
notebooks/src/utils/ui_elements.py ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import ipywidgets as widgets
2
+ from IPython.display import HTML, display
3
+
4
+
5
+ _BUTTON_STYLE_CSS = """
6
+ <style>
7
+ .widget-button {
8
+ justify-content: flex-start !important;
9
+ text-align: left !important;
10
+ font-weight: bold !important;
11
+ font-size: 15px !important;
12
+ padding-left: 12px !important;
13
+ }
14
+ </style>
15
+ """
16
+
17
+
18
+ def inject_styles():
19
+ display(HTML(_BUTTON_STYLE_CSS))
20
+
21
+
22
+ def make_button(description, width='300px'):
23
+ return widgets.Button(
24
+ description=description,
25
+ layout=widgets.Layout(width=width),
26
+ style=widgets.ButtonStyle(font_weight='bold')
27
+ )
28
+
29
+
30
+ def set_executing(btn, message='Running...'):
31
+ btn.description = message
32
+ btn.disabled = True
33
+
34
+
35
+ def set_done(btn, message):
36
+ btn.description = message
37
+ btn.disabled = True
38
+ btn.style.button_color = '#c3e6cb'
39
+
40
+
41
+ def set_error(btn, original_description):
42
+ btn.description = original_description
43
+ btn.disabled = False