Diff of /dash/main.py [000000] .. [fa8046]

Switch to unified view

a b/dash/main.py
1
# Introducing callbacks
2
3
# -*- coding: utf-8 -*-
4
import base64
5
import time
6
import dash
7
import dash_core_components as dcc
8
import dash_html_components as html
9
import dash_daq as daq
10
11
12
import pandas as pd
13
import numpy as np
14
import numpy as np
15
16
import cv2
17
18
19
# prepare the data -- begin
20
21
cases = pd.read_csv('../data/valid-acl.csv',
22
                    header=None,
23
                    names=['Case', 'Abnormal'],
24
                    dtype={'Case': str, 'Abnormal': np.int64}
25
                    )
26
case_list = cases['Case'].tolist()
27
28
29
predictions = pd.read_csv('./val_data.csv')
30
31
32
# prepare the data -- end
33
34
35
app = dash.Dash(show_undo_redo=False)
36
37
# Boostrap CSS.
38
39
app.css.append_css({'external_url': 'https://codepen.io/amyoshino/pen/jzXypZ.css'})  # noqa: E501
40
#app.css.append_css({'external_url': "https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"})  # noqa: E501
41
42
43
44
app.layout = html.Div(
45
    html.Div([
46
        html.Div(
47
            
48
                html.H1(children='Interpretation of MRNet models through Class Activation Maps (CAM)', 
49
                        className='twelve columns',
50
                        style={'text-align': 'center'}                      
51
                    )
52
            ,
53
            className="row",
54
        ),
55
56
        html.Div(
57
            [
58
                html.Div(
59
                    [
60
                        html.P('Select a medical case (i.e. a patient)'),
61
                        html.Div([
62
                            dcc.Dropdown(
63
                                id='cases',
64
                                options=[
65
                                    {'label': case, 'value': case} for case in case_list
66
                                ],
67
                                placeholder="Pick a case",
68
                                clearable=False
69
                            )
70
                        ],
71
                            style={'margin-bottom': 20}
72
                        ),
73
                    ],
74
                    className='three columns',
75
                    style={'margin-top': '10'}
76
                ),
77
                html.Div([
78
                    html.Div([
79
                        html.Div([
80
                            html.P('Select true labels :'),
81
                            dcc.RadioItems(
82
                                id="label_radioitems",
83
                                options=[
84
                                    {'label': 'Positive (ACL tear)', 'value': 'acl'},
85
                                    {'label': 'Negative (Normal)', 'value': 'normal'},
86
                                ],
87
                                value='acl',
88
                                labelStyle={'display': 'inline-block'}
89
                            ),
90
                        ],
91
                            style={'float': 'left', 'width': '45%'}
92
                        ),
93
94
                        html.Div([
95
                            html.P('Select predicted labels :'),
96
                            dcc.RadioItems(
97
                                id="pred_radioitems",
98
                                options=[
99
                                    {'label': 'Positive (ACL tear)', 'value': 'acl'},
100
                                    {'label': 'Negative (Normal)', 'value': 'normal'},
101
                                ],
102
                                value='acl',
103
                                labelStyle={'display': 'inline-block'}
104
                            ),
105
                        ]
106
                        ),
107
                    ]),
108
                ],
109
                    className='six columns'
110
                ),
111
                html.Div([
112
                    html.Div(id="number_of_cases"),
113
                    html.Span(
114
                            id="label_badge", 
115
                            className="badge badge-success badge-large",
116
                            style={'font-size': '15px'}
117
                            ),
118
                ],
119
                    className='three columns'
120
121
                )
122
123
            ], className="row"
124
        ),
125
126
        html.Div([
127
128
            html.Div([
129
                html.P(id='summary', style={'font-size': '20px'}),
130
                html.Div([
131
                        html.Div('This probability is a weighted average of the three probabilities of tears over each plane', style={'float': 'left', 'font-size': '20px'}),
132
                        html.Div('Slide over the slices of each MRI to inspect highlighted regions of tear as depicted by CAMs', style={'float': 'left', 'font-size': '20px'}),
133
134
                    ],
135
                    # style={'text-align': 'center'}
136
                    )
137
                    ],
138
                    className="twelve columns"),
139
140
        ],
141
        className='row'
142
        ),
143
144
        html.Hr(),
145
146
        html.Div(
147
            [
148
                html.Div([
149
                    html.Div([
150
                        dcc.Slider(id='slider_axial', updatemode='drag')
151
                    ],
152
                        style={'margin-right': '5px'}
153
154
                    ),
155
                    html.Hr(),
156
                    html.P(id="score_axial", style={'text-align': 'center'}),
157
                    html.Div([
158
                        html.Div([
159
                            html.Img(
160
                                id="slice_axial",
161
                            ),
162
                        ],
163
                            style={'float': 'left', 'margin-right': '5px'}
164
                        ),
165
                        html.Div([
166
                            html.Img(
167
                                id="cam_axial",
168
                            ),
169
                        ],
170
                        )
171
                    ],
172
173
                    ),
174
                    html.P(id="title_axial", style={'text-align': 'center'})
175
                ],
176
                    className="four columns"
177
                ),
178
                html.Div([
179
                    html.Div([
180
                        dcc.Slider(id='slider_coronal', updatemode='drag')
181
                    ],
182
                        style={'margin-right': '5px'}
183
184
                    ),
185
                    html.Hr(),
186
                    html.P(id="score_coronal", style={'text-align': 'center'}),
187
                    html.Div([
188
                        html.Div([
189
                            html.Img(
190
                                id="slice_coronal",
191
                            ),
192
                        ],
193
                            style={'float': 'left', 'margin-right': '5px'}
194
                        ),
195
                        html.Div([
196
                            html.Img(
197
                                id="cam_coronal",
198
                            ),
199
                        ],
200
                        )
201
                    ],
202
203
                    ),
204
                    html.P(id="title_coronal", style={'text-align': 'center'})
205
                ],
206
                    className="four columns"
207
                ),
208
                html.Div([
209
                    html.Div([
210
                        dcc.Slider(id='slider_sagittal', updatemode='drag')
211
                    ]),
212
                    html.Hr(),
213
                    html.P(id="score_sagittal", style={
214
                           'text-align': 'center'}),
215
                    html.Div([
216
                        html.Div([
217
                            html.Img(
218
                                id="slice_sagittal",
219
                            ),
220
                        ],
221
                            style={'float': 'left', 'margin-right': '5px'}
222
                        ),
223
                        html.Div([
224
                            html.Img(
225
                                id="cam_sagittal",
226
                            ),
227
                        ],
228
                        )
229
                    ],
230
231
                    ),
232
                    html.P(id="title_sagittal", style={'text-align': 'center'})
233
234
235
                ],
236
                    className="four columns"
237
                ),
238
239
            ],
240
            className='row'
241
        )
242
    ], className='twelve columns')
243
)
244
245
246
# select label --- begin
247
@app.callback(
248
    dash.dependencies.Output('cases', 'options'),
249
    [
250
        dash.dependencies.Input('label_radioitems', 'value'),
251
        dash.dependencies.Input('pred_radioitems', 'value'),
252
    ]
253
)
254
def set_label(selected_label, selected_pred):
255
    if (selected_label == 'acl') and (selected_pred == 'acl'):
256
        filtered_cases = predictions[(predictions['labels'] == 1) & 
257
                                     (predictions['preds'] >= 0.5)].index.tolist()
258
259
    elif (selected_label == 'acl') and (selected_pred == 'normal'):
260
        filtered_cases = predictions[(predictions['labels'] == 1) & 
261
                                     (predictions['preds'] < 0.5)].index.tolist()
262
263
    elif (selected_label == 'normal') and (selected_pred == 'acl'):
264
        filtered_cases = predictions[(predictions['labels'] == 0) & 
265
                                     (predictions['preds'] >= 0.5)].index.tolist()
266
267
    elif (selected_label == 'normal') and (selected_pred == 'normal'):
268
        filtered_cases = predictions[(predictions['labels'] == 0) & 
269
                                     (predictions['preds'] < 0.5)].index.tolist()                                 
270
271
    filtered_cases = [c + 1130 for c in filtered_cases]
272
    options = [{'label': fc, 'value': fc} for fc in filtered_cases]
273
    return options
274
# select label --- end
275
276
# set badge label --- begin
277
278
@app.callback(
279
    dash.dependencies.Output('label_badge', 'children'),
280
    [
281
        dash.dependencies.Input('label_radioitems', 'value'),
282
        dash.dependencies.Input('pred_radioitems', 'value'),
283
    ]
284
)
285
def set_badge_label(selected_label, selected_pred):
286
    if (selected_label == 'acl') and (selected_pred == 'acl'):
287
        text = 'true positive case'
288
289
    elif (selected_label == 'acl') and (selected_pred == 'normal'):
290
        text = 'false negative case'
291
292
    elif (selected_label == 'normal') and (selected_pred == 'acl'):
293
        text = 'false positive case'
294
295
    elif (selected_label == 'normal') and (selected_pred == 'normal'):
296
        text = 'true negative case'
297
298
    return text
299
300
# set badge label --- end
301
302
# set badge color --- begin
303
304
@app.callback(
305
    dash.dependencies.Output('label_badge', 'className'),
306
    [
307
        dash.dependencies.Input('label_radioitems', 'value'),
308
        dash.dependencies.Input('pred_radioitems', 'value'),
309
    ]
310
)
311
def set_badge_color(selected_label, selected_pred):
312
    if (selected_label == 'acl') and (selected_pred == 'acl'):
313
        className = 'badge badge-success'
314
315
    elif (selected_label == 'acl') and (selected_pred == 'normal'):
316
        className = 'badge badge-error'
317
318
    elif (selected_label == 'normal') and (selected_pred == 'acl'):
319
        className = 'badge badge-error'
320
321
    elif (selected_label == 'normal') and (selected_pred == 'normal'):
322
        className = 'badge badge-success'
323
324
    return className
325
326
# set badge color --- end
327
328
# set a case value --- begin
329
330
@app.callback(
331
    dash.dependencies.Output('cases', 'value'),
332
    [
333
        dash.dependencies.Input('label_radioitems', 'value'),
334
        dash.dependencies.Input('pred_radioitems', 'value'),
335
    ]
336
)
337
def set_badge_color(selected_label, selected_pred):
338
    if (selected_label == 'acl') and (selected_pred == 'acl'):
339
        filtered_cases = predictions[(predictions['labels'] == 1) & 
340
                                     (predictions['preds'] >= 0.5)].index.tolist()
341
342
    elif (selected_label == 'acl') and (selected_pred == 'normal'):
343
        filtered_cases = predictions[(predictions['labels'] == 1) & 
344
                                     (predictions['preds'] < 0.5)].index.tolist()
345
346
    elif (selected_label == 'normal') and (selected_pred == 'acl'):
347
        filtered_cases = predictions[(predictions['labels'] == 0) & 
348
                                     (predictions['preds'] >= 0.5)].index.tolist()
349
350
    elif (selected_label == 'normal') and (selected_pred == 'normal'):
351
        filtered_cases = predictions[(predictions['labels'] == 0) & 
352
                                     (predictions['preds'] < 0.5)].index.tolist()                                 
353
354
    filtered_cases = [c + 1130 for c in filtered_cases]
355
    case_value = np.random.choice(filtered_cases)
356
    return case_value
357
358
# set a case value --- end
359
360
361
# set summary --- begin
362
363
@app.callback(
364
    dash.dependencies.Output('summary', 'children'),
365
    [
366
        dash.dependencies.Input('cases', 'value'),
367
        dash.dependencies.Input('label_radioitems', 'value'),
368
        dash.dependencies.Input('pred_radioitems', 'value')
369
    ]
370
)
371
def set_summary(selected_case, selected_label, selected_pred):
372
   
373
    proba = predictions['preds'].tolist()[int(selected_case) - 1130]
374
    proba = np.round(proba, 4)
375
376
    if (selected_label == 'acl') and (selected_pred == 'acl'):
377
        status = 'correctly'
378
379
    elif (selected_label == 'acl') and (selected_pred == 'normal'):
380
        status = 'incorrectly'
381
382
    elif (selected_label == 'normal') and (selected_pred == 'acl'):
383
        status = 'incorrectly'
384
385
    elif (selected_label == 'normal') and (selected_pred == 'normal'):
386
        status = 'correctly'
387
388
    if selected_pred == 'acl':
389
        summary = f'This patient, denoted by the MRI exam n°{selected_case}, is {status} diagnosed with an ACL tear with an ACL tear probability of {proba}'
390
    elif selected_pred == 'normal':
391
        summary = f'This patient, denoted by the MRI exam n°{selected_case}, is {status} diagnosed to be normal with an ACL tear probability of {proba}'
392
 
393
394
    return summary
395
396
# set summary --- end
397
398
399
400
401
402
403
# set number of cases --- begin
404
405
@app.callback(
406
    dash.dependencies.Output('number_of_cases', 'children'),
407
    [
408
        dash.dependencies.Input('label_radioitems', 'value'),
409
        dash.dependencies.Input('pred_radioitems', 'value')
410
    ]
411
)
412
def set_number_cases(selected_label, selected_pred):
413
    if (selected_label == 'acl') and (selected_pred == 'acl'):
414
        n = predictions[(predictions['labels'] == 1) & 
415
                                     (predictions['preds'] >= 0.5)].shape[0]
416
417
    elif (selected_label == 'acl') and (selected_pred == 'normal'):
418
        n = predictions[(predictions['labels'] == 1) & 
419
                                     (predictions['preds'] < 0.5)].shape[0]
420
421
    elif (selected_label == 'normal') and (selected_pred == 'acl'):
422
        n = predictions[(predictions['labels'] == 0) & 
423
                                     (predictions['preds'] >= 0.5)].shape[0]
424
425
    elif (selected_label == 'normal') and (selected_pred == 'normal'):
426
        n = predictions[(predictions['labels'] == 0) & 
427
                                     (predictions['preds'] < 0.5)].shape[0]                                 
428
429
    msg = f"{n} MRI exams"
430
    return msg
431
432
# set number of cases --- end
433
434
435
# update axial slider --- begin
436
@app.callback(
437
    dash.dependencies.Output('slider_axial', 'value'),
438
    [
439
        dash.dependencies.Input('cases', 'value'),
440
    ]
441
)
442
def set_slider_value_axial(selected_case):
443
    mri = np.load(f'../data/valid/axial/{selected_case}.npy')
444
    number_slices = mri.shape[0]
445
    return number_slices // 2
446
447
448
@app.callback(
449
    dash.dependencies.Output('slider_axial', 'max'),
450
    [
451
        dash.dependencies.Input('cases', 'value'),
452
    ]
453
)
454
def set_slider_max_axial(selected_case):
455
    mri = np.load(f'../data/valid/axial/{selected_case}.npy')
456
    number_slices = mri.shape[0]
457
    return number_slices - 1
458
459
460
@app.callback(
461
    dash.dependencies.Output('slider_axial', 'marks'),
462
    [
463
        dash.dependencies.Input('cases', 'value'),
464
    ]
465
)
466
def set_slider_marks_axial(selected_case):
467
    mri = np.load(f'../data/valid/axial/{selected_case}.npy')
468
    number_slices = mri.shape[0]
469
    marks = {str(i): '{}'.format(i) for i in range(number_slices)[::2]}
470
    return marks
471
472
# update axial slider --- end
473
474
# update coronal slider --- begin
475
476
477
@app.callback(
478
    dash.dependencies.Output('slider_coronal', 'value'),
479
    [
480
        dash.dependencies.Input('cases', 'value'),
481
    ]
482
)
483
def set_slider_value_coronal(selected_case):
484
    mri = np.load(f'../data/valid/coronal/{selected_case}.npy')
485
    number_slices = mri.shape[0]
486
    return number_slices // 2
487
488
489
@app.callback(
490
    dash.dependencies.Output('slider_coronal', 'max'),
491
    [
492
        dash.dependencies.Input('cases', 'value'),
493
    ]
494
)
495
def set_slider_max_coronal(selected_case):
496
    mri = np.load(f'../data/valid/coronal/{selected_case}.npy')
497
    number_slices = mri.shape[0]
498
    return number_slices - 1
499
500
501
@app.callback(
502
    dash.dependencies.Output('slider_coronal', 'marks'),
503
    [
504
        dash.dependencies.Input('cases', 'value'),
505
    ]
506
)
507
def set_slider_marks_coronal(selected_case):
508
    mri = np.load(f'../data/valid/coronal/{selected_case}.npy')
509
    number_slices = mri.shape[0]
510
    marks = {str(i): '{}'.format(i) for i in range(number_slices)[::2]}
511
    return marks
512
513
# update coronal slider --- end
514
515
# update sagittal slider --- begin
516
517
518
@app.callback(
519
    dash.dependencies.Output('slider_sagittal', 'value'),
520
    [
521
        dash.dependencies.Input('cases', 'value'),
522
    ]
523
)
524
def set_slider_value_sagittal(selected_case):
525
    mri = np.load(f'../data/valid/sagittal/{selected_case}.npy')
526
    number_slices = mri.shape[0]
527
    return number_slices // 2
528
529
530
@app.callback(
531
    dash.dependencies.Output('slider_sagittal', 'max'),
532
    [
533
        dash.dependencies.Input('cases', 'value'),
534
    ]
535
)
536
def set_slider_max_sagittal(selected_case):
537
    mri = np.load(f'../data/valid/sagittal/{selected_case}.npy')
538
    number_slices = mri.shape[0]
539
    return number_slices - 1
540
541
542
@app.callback(
543
    dash.dependencies.Output('slider_sagittal', 'marks'),
544
    [
545
        dash.dependencies.Input('cases', 'value'),
546
    ]
547
)
548
def set_slider_marks_sagittal(selected_case):
549
    mri = np.load(f'../data/valid/sagittal/{selected_case}.npy')
550
    number_slices = mri.shape[0]
551
    marks = {str(i): '{}'.format(i) for i in range(number_slices)[::2]}
552
    return marks
553
554
# update sagittal slider --- end
555
556
# update slider --- END
557
558
# Axial
559
##########################################################################
560
561
# write number of slice axial - begin
562
563
564
@app.callback(
565
    dash.dependencies.Output('title_axial', 'children'),
566
    [
567
        dash.dependencies.Input('cases', 'value'),
568
        dash.dependencies.Input('slider_axial', 'value')
569
    ]
570
)
571
def write_num_slice_axial(selected_case, selected_slice):
572
    case = np.load(f'../data/valid/axial/{selected_case}.npy')
573
    num_slices = case.shape[0]
574
    title = f'Visualization of slice n°{selected_slice}/{num_slices} and its corresponding CAM'
575
    return title
576
# write number of slice axial - end
577
578
579
# write score axial - begin
580
@app.callback(
581
    dash.dependencies.Output('score_axial', 'children'),
582
    [
583
        dash.dependencies.Input('cases', 'value'),
584
    ]
585
)
586
def write_score_axial(selected_case):
587
    score = predictions.iloc[int(selected_case) - 1130]['axial']
588
    score = np.round(score, 4)
589
    msg = f"ACL tear proba on axial plane : {score}"
590
    return msg
591
# write score axial
592
593
594
# update slice axial --- begin
595
@app.callback(
596
    dash.dependencies.Output('slice_axial', 'src'),
597
    [
598
        dash.dependencies.Input('cases', 'value'),
599
        dash.dependencies.Input('slider_axial', 'value'),
600
601
    ])
602
def update_slice_axial(selected_case, selected_slice):
603
    s = np.load(f'../data/valid/axial/{selected_case}.npy')[selected_slice]
604
    cv2.imwrite(f'./slice_axial.png', s)
605
    encoded_image = base64.b64encode(open('./slice_axial.png', 'rb').read())
606
    return 'data:image/png;base64,{}'.format(encoded_image.decode())
607
# update slice axial --- end
608
# update cam axial --- begin
609
610
611
@app.callback(
612
    dash.dependencies.Output('cam_axial', 'src'),
613
    [
614
        dash.dependencies.Input('cases', 'value'),
615
        dash.dependencies.Input('slider_axial', 'value'),
616
617
    ])
618
def update_cam_axial(selected_case, selected_slice):
619
    selected_case = int(selected_case) - 1130
620
    selected_case = '0' * (4 - len(str(selected_case))) + str(selected_case)
621
    src = f'./CAMS/axial/{selected_case}/cams/{selected_slice}.png'
622
    encoded_image = base64.b64encode(open(src, 'rb').read())
623
    return 'data:image/png;base64,{}'.format(encoded_image.decode())
624
# update slice axial --- end
625
626
# Coronal
627
##########################################################################
628
629
# write number of slice coronal - begin
630
631
632
@app.callback(
633
    dash.dependencies.Output('title_coronal', 'children'),
634
    [
635
        dash.dependencies.Input('cases', 'value'),
636
        dash.dependencies.Input('slider_coronal', 'value')
637
    ]
638
)
639
def write_num_slice_coronal(selected_case, selected_slice):
640
    case = np.load(f'../data/valid/coronal/{selected_case}.npy')
641
    num_slices = case.shape[0]
642
    title = f'Visualization of slice n°{selected_slice}/{num_slices} and its corresponding CAM'
643
    return title
644
# write number of slice coronal - end
645
646
# write score coronal - begin
647
648
649
@app.callback(
650
    dash.dependencies.Output('score_coronal', 'children'),
651
    [
652
        dash.dependencies.Input('cases', 'value'),
653
    ]
654
)
655
def write_score_coronal(selected_case):
656
    score = predictions.iloc[int(selected_case) - 1130]['coronal']
657
    score = np.round(score, 4)
658
    msg = f"ACL tear proba on coronal plane : {score}"
659
    return msg
660
# write score coronal
661
662
663
# update slice coronal --- begin
664
@app.callback(
665
    dash.dependencies.Output('slice_coronal', 'src'),
666
    [
667
        dash.dependencies.Input('cases', 'value'),
668
        dash.dependencies.Input('slider_coronal', 'value'),
669
670
    ])
671
def update_slice_coronal(selected_case, selected_slice):
672
    s = np.load(f'../data/valid/coronal/{selected_case}.npy')[selected_slice]
673
    cv2.imwrite(f'./slice_coronal.png', s)
674
    encoded_image = base64.b64encode(open('./slice_coronal.png', 'rb').read())
675
    return 'data:image/png;base64,{}'.format(encoded_image.decode())
676
# update slice coronal --- end
677
# update cam coronal --- begin
678
679
680
@app.callback(
681
    dash.dependencies.Output('cam_coronal', 'src'),
682
    [
683
        dash.dependencies.Input('cases', 'value'),
684
        dash.dependencies.Input('slider_coronal', 'value'),
685
686
    ])
687
def update_cam_coronal(selected_case, selected_slice):
688
    selected_case = int(selected_case) - 1130
689
    selected_case = '0' * (4 - len(str(selected_case))) + str(selected_case)
690
    src = f'./CAMS/coronal/{selected_case}/cams/{selected_slice}.png'
691
    encoded_image = base64.b64encode(open(src, 'rb').read())
692
    return 'data:image/png;base64,{}'.format(encoded_image.decode())
693
694
# update slice coronal --- end
695
696
# Sagittal
697
##########################################################################
698
699
# write number of slice sagittal - begin
700
701
702
@app.callback(
703
    dash.dependencies.Output('title_sagittal', 'children'),
704
    [
705
        dash.dependencies.Input('cases', 'value'),
706
        dash.dependencies.Input('slider_sagittal', 'value')
707
    ]
708
)
709
def write_num_slice_sagittal(selected_case, selected_slice):
710
    case = np.load(f'../data/valid/sagittal/{selected_case}.npy')
711
    num_slices = case.shape[0]
712
    title = f'Visualization of slice n°{selected_slice}/{num_slices} and its corresponding CAM'
713
    return title
714
# write number of slice sagittal - end
715
716
# write score sagittal - begin
717
718
719
@app.callback(
720
    dash.dependencies.Output('score_sagittal', 'children'),
721
    [
722
        dash.dependencies.Input('cases', 'value'),
723
    ]
724
)
725
def write_score_sagittal(selected_case):
726
    score = predictions.iloc[int(selected_case) - 1130]['sagittal']
727
    score = np.round(score, 4)
728
    msg = f"ACL tear proba on sagittal plane : {score}"
729
    return msg
730
# write score sagittal
731
732
733
# update slice sagittal --- begin
734
@app.callback(
735
    dash.dependencies.Output('slice_sagittal', 'src'),
736
    [
737
        dash.dependencies.Input('cases', 'value'),
738
        dash.dependencies.Input('slider_sagittal', 'value'),
739
740
    ])
741
def update_slice_sagittal(selected_case, selected_slice):
742
    s = np.load(f'../data/valid/sagittal/{selected_case}.npy')[selected_slice]
743
    cv2.imwrite(f'./slice_sagittal.png', s)
744
    encoded_image = base64.b64encode(open('./slice_sagittal.png', 'rb').read())
745
    return 'data:image/png;base64,{}'.format(encoded_image.decode())
746
# update slice saigttal --- end
747
# update cam sagittal --- begin
748
749
750
@app.callback(
751
    dash.dependencies.Output('cam_sagittal', 'src'),
752
    [
753
        dash.dependencies.Input('cases', 'value'),
754
        dash.dependencies.Input('slider_sagittal', 'value'),
755
756
    ])
757
def update_cam_sagittal(selected_case, selected_slice):
758
    selected_case = int(selected_case) - 1130
759
    selected_case = '0' * (4 - len(str(selected_case))) + str(selected_case)
760
    src = f'./CAMS/sagittal/{selected_case}/cams/{selected_slice}.png'
761
    encoded_image = base64.b64encode(open(src, 'rb').read())
762
    return 'data:image/png;base64,{}'.format(encoded_image.decode())
763
# update slice coronal --- end
764
765
766
if __name__ == '__main__':
767
    app.run_server(debug=True)