diff --git a/source/tools/data.py b/source/tools/data.py index 2126524..4fec2d8 100644 --- a/source/tools/data.py +++ b/source/tools/data.py @@ -56,6 +56,8 @@ class Data: ['qmri', 3, 10, 'T1w'], ['qmri', 4, 5, 'T1w'], ['qmri', 5, 7, 'T2w'], + ['spine', 2, 10, 'GMT2w'], + ['spine', 5, 5, 'GMT2w'], ['qmri', 2, 1, 'DWI_FA'], ['qmri', 2, 1, 'DWI_MD'], ['qmri', 2, 1, 'DWI_RD'], ['qmri', 3, 3, 'DWI_FA'], ['qmri', 3, 3, 'DWI_MD'], ['qmri', 3, 3, 'DWI_RD'], ['qmri', 6, 8, 'DWI_FA'], ['qmri', 6, 8, 'DWI_MD'], ['qmri', 6, 8, 'DWI_RD'] diff --git a/source/tools/plot.py b/source/tools/plot.py index 6b41be6..8c018fc 100644 --- a/source/tools/plot.py +++ b/source/tools/plot.py @@ -19,7 +19,7 @@ class Plot: """ - colours = [(31, 119, 180), (174, 199, 232), (255, 127, 14), (190, 77, 80), (0, 132, 53), + colours = [(31, 119, 180), (174, 199, 232), (255, 127, 14), (190, 77, 80), (229, 153, 50), (0, 132, 53), (255, 187, 120), (44, 160, 44), (152, 223, 138), (214, 39, 40), (255, 152, 150), (148, 103, 189), (197, 176, 213), (140, 86, 75), (196, 156, 148), (227, 119, 194), (247, 182, 210), (127, 127, 127), (199, 199, 199), @@ -108,7 +108,7 @@ def display(self, env, fig_id = None): init_notebook_mode(connected = True) config={ 'showLink': False, - 'displayModeBar': False, + 'displayModeBar': True, 'toImageButtonOptions': { 'format': 'png', # one of png, svg, jpeg, webp 'filename': 'custom_image', @@ -266,7 +266,7 @@ def display(self, env, fig_id = None): dict(label="MTR", method="update", args=[{"visible": [True] + [False]*(num_subjects*2) + [True]*num_subjects + [False]*num_subjects + [False]*2 + [True]*1 +[False]*1 + [False]*2 + [True]*1 +[False]*1 + [False]*(num_subjects*2) + [True]*num_subjects + [False]*num_subjects + [False]*2 + [True]*1 +[False]*1 + [False]*2 + [True]*1 +[False]*1}, - self.set_trace_layout(matrix=matrix, metric='MTR', title='MTR [a.u.]', tissues=['WM', 'GM']) ]), + self.set_trace_layout(matrix=matrix, metric='MTR', title='MTR [%]', tissues=['WM', 'GM']) ]), dict(label="MTsat", method="update", args=[{"visible": [True] + [False]*(num_subjects*3) + [True]*num_subjects + [False]*3 + [True]*1 + [False]*3 + [True]*1 + [False]*(num_subjects*3) + [True]*num_subjects + [False]*3 + [True]*1 + [False]*3 + [True]*1}, @@ -284,7 +284,7 @@ def display(self, env, fig_id = None): dict(label="DWI_FA", method="update", args=[{"visible": [True] + [True]*num_subjects + [False]*(num_subjects*2) + [True]*1 + [False]*2 + [True]*1 + [False]*2 + [True]*num_subjects + [False]*(num_subjects*2) + [True]*1 + [False]*2 + [True]*1 + [False]*2}, - self.set_trace_layout(matrix=matrix, metric='DWI_FA', title='DWI_FA [a.u.]', tissues=['CC_1', 'MCP'])]), + self.set_trace_layout(matrix=matrix, metric='DWI_FA', title='DWI_FA', tissues=['CC_1', 'MCP'])]), dict(label="DWI_MD", method="update", args=[{"visible": [True] + [False]*num_subjects + [True]*num_subjects + [False]*(num_subjects) + [False]*1 + [True]*1 +[False]*1 + [False]*1 + [True]*1 +[False]*1 + [False]*num_subjects + [True]*num_subjects + [False]*(num_subjects) + [False]*1 + [True]*1 +[False]*1 + [False]*1 + [True]*1 +[False]*1}, @@ -306,7 +306,7 @@ def display(self, env, fig_id = None): dict(label="DWI_FA", method="update", args=[{"visible": [True] + [True]*num_subjects + [False]*(num_subjects*2) + [True]*1 + [False]*2 + [True]*1 + [False]*2 + [True]*num_subjects + [False]*(num_subjects*2) + [True]*1 + [False]*2 + [True]*1 + [False]*2 + [True]*num_subjects + [False]*(num_subjects*2) + [True]*1 + [False]*2 + [True]*1 + [False]*2}, - self.set_trace_layout(matrix=matrix, metric='DWI_FA', title='DWI_FA [a.u.]', tissues=['genu', 'body', 'splenium'])]), + self.set_trace_layout(matrix=matrix, metric='DWI_FA', title='DWI_FA', tissues=['genu', 'body', 'splenium'])]), dict(label="DWI_MD", method="update", args=[{"visible": [True] + [False]*num_subjects + [True]*num_subjects + [False]*(num_subjects) + [False]*1 + [True]*1 +[False]*1 + [False]*1 + [True]*1 +[False]*1 + [False]*num_subjects + [True]*num_subjects + [False]*(num_subjects) + [False]*1 + [True]*1 +[False]*1 + [False]*1 + [True]*1 +[False]*1 + [False]*num_subjects + [True]*num_subjects + [False]*(num_subjects) + [False]*1 + [True]*1 +[False]*1 + [False]*1 + [True]*1 +[False]*1, @@ -371,7 +371,7 @@ def display(self, env, fig_id = None): dict(label="DWI_FA", method="update", args=[{"visible": [True] + [True]*num_subjects + [False]*(num_subjects*5) + [True]*1 + [False]*5 + [True]*1 + [False]*5}, - self.set_trace_layout(matrix=matrix, metric='DWI_FA', title='DWI_FA [a.u.]')]), + self.set_trace_layout(matrix=matrix, metric='DWI_FA', title='DWI_FA')]), dict(label="DWI_MD", method="update", args=[{"visible": [True] + [False]*num_subjects + [True]*num_subjects + [False]*(num_subjects*4) + [False]*1 + [True]*1 +[False]*4 + [False]*1 + [True]*1 +[False]*4}, @@ -383,7 +383,7 @@ def display(self, env, fig_id = None): dict(label="MTR", method="update", args=[{"visible": [True] + [False]*(num_subjects*3) + [True]*num_subjects + [False]*(num_subjects*2) + [False]*3 + [True]*1 +[False]*2 + [False]*3 + [True]*1 +[False]*2}, - self.set_trace_layout(matrix=matrix, metric='MTR', title='MTR [a.u.]')]), + self.set_trace_layout(matrix=matrix, metric='MTR', title='MTR [%]')]), dict(label="MTsat", method="update", args=[{"visible": [True] + [False]*(num_subjects*4) + [True]*num_subjects + [False]*num_subjects + [False]*4 + [True]*1 +[False]*1 + [False]*4 + [True]*1 +[False]*1}, @@ -416,11 +416,11 @@ def display(self, env, fig_id = None): x_button=1.4 elif self.dataset.data_type == 'brain-diffusion': yaxis_range = [self.get_val(np.append(matrix['CC_1']['DWI_FA'], matrix['MCP']['DWI_FA'], axis=0), 'min'), self.get_val(np.append(matrix['CC_1']['DWI_FA'], matrix['MCP']['DWI_FA'], axis=0), 'max')] - yaxis_title = 'DWI_FA [a.u.]' + yaxis_title = 'DWI_FA' x_button=1.3 elif self.dataset.data_type == 'brain-diffusion-cc': yaxis_range = [self.get_val(np.append(matrix['genu']['DWI_FA'], matrix['splenium']['DWI_FA'], axis=0), 'min'), self.get_val(np.append(matrix['genu']['DWI_FA'], matrix['splenium']['DWI_FA'], axis=0), 'max')] - yaxis_title = 'DWI_FA [a.u.]' + yaxis_title = 'DWI_FA' x_button=1.3 y_button=0.5 elif self.dataset.data_type == 'spine': @@ -438,7 +438,7 @@ def display(self, env, fig_id = None): yaxis_title = 'Area [mm2]' else: yaxis_range = [self.get_val(matrix['DWI_FA'], 'min'), self.get_val(matrix['DWI_FA'], 'max')] - yaxis_title = 'DWI_FA [a.u.]' + yaxis_title = 'DWI_FA' x_button=1.28 width = 680 height = 540 @@ -504,7 +504,7 @@ def display_paper_fig2(self, env, fig_id = None): init_notebook_mode(connected = True) config={ 'showLink': False, - 'displayModeBar': False, + 'displayModeBar': True, 'toImageButtonOptions': { 'format': 'png', # one of png, svg, jpeg, webp 'filename': 'custom_image', @@ -624,7 +624,7 @@ def display_paper_fig2(self, env, fig_id = None): fig.update_yaxes( type="linear", title={ - 'text':'MTR [a.u.]', + 'text':'MTR [%]', 'standoff':0 }, showgrid=False, @@ -850,7 +850,7 @@ def display_paper_fig3(self, env, fig_id = None): init_notebook_mode(connected = True) config={ 'showLink': False, - 'displayModeBar': False, + 'displayModeBar': True, 'toImageButtonOptions': { 'format': 'png', # one of png, svg, jpeg, webp 'filename': 'custom_image', @@ -915,7 +915,7 @@ def display_paper_fig3(self, env, fig_id = None): fig.update_yaxes( type="linear", title={ - 'text':'DWI_FA [a.u.]', + 'text':'DWI_FA', 'standoff':0 }, showgrid=False, @@ -1197,7 +1197,7 @@ def display_paper_fig4(self, env, fig_id = None): init_notebook_mode(connected = True) config={ 'showLink': False, - 'displayModeBar': False, + 'displayModeBar': True, 'toImageButtonOptions': { 'format': 'png', # one of png, svg, jpeg, webp 'filename': 'custom_image', @@ -1261,7 +1261,8 @@ def display_paper_fig4(self, env, fig_id = None): linewidth=2, tickfont = dict(size=self.y_label_tick_font_size-5), title_font = dict(size = self.general_font_size-5), - range = [self.get_val(matrix['T1w'], 'min'), self.get_val(matrix['T1w'], 'max')], + autorange=False, + range = [40, 100], row=1, col=1 ) @@ -1292,7 +1293,8 @@ def display_paper_fig4(self, env, fig_id = None): tickfont = dict(size=self.y_label_tick_font_size-5), tickformat='s', title_font = dict(size = self.general_font_size-5), - range = [self.get_val(matrix['T2w'], 'min'), self.get_val(matrix['T2w'], 'max')], + autorange=False, + range = [40, 100], row=1, col=2 ) fig.update_xaxes( @@ -1421,7 +1423,7 @@ def display_paper_fig5(self, env, fig_id = None): init_notebook_mode(connected = True) config={ 'showLink': False, - 'displayModeBar': False, + 'displayModeBar': True, 'toImageButtonOptions': { 'format': 'png', # one of png, svg, jpeg, webp 'filename': 'custom_image', @@ -1512,7 +1514,7 @@ def display_paper_fig5(self, env, fig_id = None): fig.update_yaxes( type="linear", title={ - 'text':'MTR [a.u.]', + 'text':'MTR [%]', 'standoff':0 }, showgrid=False, @@ -1570,7 +1572,7 @@ def display_paper_fig5(self, env, fig_id = None): fig.update_yaxes( type="linear", title={ - 'text':'DWI_FA [a.u.]', + 'text':'DWI_FA', 'standoff':0 }, showgrid=False, @@ -1996,7 +1998,6 @@ def add_points(self, figb, matrix, trace_name, num_sessions, tissue=None, fig_id name= name_T1w, marker_color=marker_color), row=row_T1w, col=col_T1w) - marker_color="rgb"+str(Plot.colours[3]) marker_symbol=symbols[5] if fig_id == 'spine-csa-wm' or fig_id == 'paper_fig4': @@ -2304,7 +2305,7 @@ def add_std_area(self, figb, matrix, trace_name, line, tissue=None, fig_id=None, if tissue == 'WM' or tissue == 'CC_1' or tissue=='genu': fillcolor='rgba(31, 119, 180, 0.15)' elif tissue == 'splenium': - fillcolor='rgba(0, 132, 53, 0.15)' + fillcolor='rgba(229, 153, 50 0.15)' else: fillcolor='rgba(190, 77, 80, 0.15)' @@ -2501,6 +2502,8 @@ def set_trace_layout(self, matrix, metric, title, tissues=None): yaxis_range = [self.get_val(np.append(pre_concat, matrix[tissues[2]][metric], axis=0), 'min'), self.get_val(np.append(pre_concat, matrix[tissues[2]][metric], axis=0), 'max')] else: yaxis_range = [self.get_val(matrix[metric], 'min'), self.get_val(matrix[metric], 'max')] + if metric=='T1w' or metric=='T2w': + yaxis_range = [40,100] if metric=='DWI_MD' or metric=='DWI_RD': return {"yaxis": dict( range = yaxis_range, diff --git a/source/tools/stats.py b/source/tools/stats.py index b950d46..08fb25f 100644 --- a/source/tools/stats.py +++ b/source/tools/stats.py @@ -79,7 +79,58 @@ def build_df(self, tissue = None): else: self.df = df - def build_stats_table(self): + def ICC(self, metric): + + if 'WM' in self.database.keys() or 'CC_1' in self.database.keys() or 'genu' in self.database.keys(): + df = self.df[metric] + else: + df = self.df[metric].to_list() + + num_subjects = len(df) + + ICC = np.zeros(6) + + subjectVariance = np.zeros(6) # Array of variance within each subject + subjectMeans = np.zeros(6) # Array of mean within each subject + + wsVariance = None # within-subject variance (i.e. mean of subjectVariance) + bsVariance = None # between-subject variance (i.e. variance of subjectMeans) + + # wsVariance + for idx, subject in enumerate(df): + subject_data = np.array([x for x in subject if str(x) != 'nan']) + + num_sessions = len(subject_data) + subjectMeans[idx] = np.mean(subject_data) + + subjectVariance[idx] = np.divide(np.sum(np.square(subject_data-subjectMeans[idx])), (num_sessions-1)) + + wsVariance = np.mean(subjectVariance) + + # wsVariance + grandMean = np.nanmean(df) + + bsVariance = np.divide(np.sum(np.square(subjectMeans-grandMean)), (num_subjects-1)) + + # ICC (intraclass correlation coefficient) + + ICC = np.divide(np.square(bsVariance), (np.square(bsVariance) + np.square(wsVariance))) + + ## COVs + + # wsVariance + subjectCOVs = np.zeros(6) + for idx, subject in enumerate(subjectVariance): + subjectCOVs[idx] = np.sqrt(subjectVariance[idx])/subjectMeans[idx] + + wsCOV = np.mean(subjectCOVs) * 100 + + #bsVariance + bsCOV = np.std(subjectMeans)/grandMean * 100 + + return ICC, wsCOV, bsCOV + + def build_stats_table(self): metrics = self.df.keys() columns = [] col_vals = [] @@ -91,6 +142,9 @@ def build_stats_table(self): 'intrasubject COV mean [%]': col_vals, 'intrasubject COV std [%]': col_vals, 'intersubject mean COV [%]': col_vals, + 'ICC': col_vals, + 'wsCOV': col_vals, + 'bsCOV': col_vals } self.stats_table = pd.DataFrame.from_dict(df_setup, orient='index', columns=columns) @@ -103,6 +157,12 @@ def build_stats_table(self): intrasub_mean = np.nanmean(self.df[metric], axis=1) self.stats_table[self.database2table[metric]]['intersubject mean COV [%]'] = np.divide(np.std(intrasub_mean),np.mean(intrasub_mean)) * 100 + + ICC, wsCOV, bsCOV = self.ICC(metric) + self.stats_table[self.database2table[metric]]['ICC'] = ICC + self.stats_table[self.database2table[metric]]['wsCOV'] = wsCOV + self.stats_table[self.database2table[metric]]['bsCOV'] = bsCOV + else: intrasub_cov = np.divide(np.nanstd(self.df[metric].tolist(), axis=1), np.nanmean(self.df[metric].tolist(), axis=1)) * 100 self.stats_table[self.database2table[metric]]['intrasubject COV mean [%]'] = np.mean(intrasub_cov) @@ -110,3 +170,8 @@ def build_stats_table(self): intrasub_mean = np.nanmean(self.df[metric].tolist(), axis=1) self.stats_table[self.database2table[metric]]['intersubject mean COV [%]'] = np.divide(np.std(intrasub_mean),np.mean(intrasub_mean)) * 100 + + ICC, wsCOV, bsCOV = self.ICC(metric) + self.stats_table[self.database2table[metric]]['ICC'] = ICC + self.stats_table[self.database2table[metric]]['wsCOV'] = wsCOV + self.stats_table[self.database2table[metric]]['bsCOV'] = bsCOV