1
+ from abc import ABC
2
+ import logging
3
+ import torch
4
+ import os
5
+ import pickle
6
+ import lightning as pl
7
+ from torchmetrics .classification import MulticlassAccuracy , MulticlassRecall , MulticlassPrecision , MulticlassF1Score , MulticlassConfusionMatrix
8
+ from torchmetrics import MetricCollection
9
+ import seaborn as sns
10
+ import matplotlib .pyplot as plt
11
+ import json
12
+ import pandas as pd
13
+
14
+ from nebula .core .utils .nebulalogger_tensorboard import NebulaTensorBoardLogger
15
+
16
+ logging .basicConfig (level = logging .INFO )
17
+
18
+ class Graphics ():
19
+ def __init__ (
20
+ self ,
21
+ scenario_start_time ,
22
+ scenario_name
23
+ ):
24
+ self .scenario_start_time = scenario_start_time
25
+ self .scenario_name = scenario_name
26
+ log_dir = os .path .join (os .environ ["NEBULA_LOGS_DIR" ], scenario_name )
27
+ self .nebulalogger = NebulaTensorBoardLogger (scenario_start_time , f"{ log_dir } " , name = "metrics" , version = f"trust" , log_graph = True )
28
+
29
+ def __log_figure (self , df , pillar , color , notion_y_pos = - 0.4 , figsize = (10 ,6 )):
30
+ filtered_df = df [df ['Pillar' ] == pillar ].copy ()
31
+
32
+ filtered_df .loc [:, 'Metric' ] = filtered_df ['Metric' ].astype (str ).str .replace ('_' , ' ' )
33
+ filtered_df .loc [:, 'Metric' ] = filtered_df ['Metric' ].apply (lambda x : str (x ).title ())
34
+
35
+ filtered_df .loc [:, 'Notion' ] = filtered_df ['Notion' ].astype (str ).str .replace ('_' , ' ' )
36
+ filtered_df .loc [:, 'Notion' ] = filtered_df ['Notion' ].apply (lambda x : str (x ).title ())
37
+
38
+ unique_notion_count = filtered_df ['Notion' ].nunique ()
39
+ palette = [color ] * unique_notion_count
40
+
41
+ plt .figure (figsize = figsize )
42
+ ax = sns .barplot (data = filtered_df , x = 'Metric' , y = 'Metric Score' , hue = 'Notion' , palette = palette , dodge = False )
43
+
44
+ x_positions = range (len (filtered_df ))
45
+
46
+ notion_scores = {}
47
+
48
+ for i in range (len (filtered_df )):
49
+ row = filtered_df .iloc [i ]
50
+ notion = row ['Notion' ]
51
+ notion_score = row ['Notion Score' ]
52
+ metric_score = row ['Metric Score' ]
53
+
54
+ if notion not in notion_scores :
55
+ metrics_for_notion = filtered_df [filtered_df ['Notion' ] == notion ]['Metric' ]
56
+ start_pos = x_positions [i ]
57
+ end_pos = x_positions [i + len (metrics_for_notion ) - 1 ]
58
+
59
+ notion_x_pos = (start_pos + end_pos ) / 2
60
+ ax .axhline (notion_score , ls = '--' , color = 'black' , lw = 0.5 , xmin = start_pos / len (x_positions ), xmax = (end_pos + 1 )/ len (x_positions ))
61
+ ax .text (notion_x_pos , notion_score + 0.01 , f"{ notion_score :.2f} " , ha = 'center' , va = 'bottom' , fontsize = 10 , color = 'black' ) # Color negro
62
+ notion_scores [notion ] = notion_score
63
+
64
+ ax .set_xticks (x_positions )
65
+ ax .set_xticklabels (filtered_df ['Metric' ], rotation = 45 , ha = 'right' , fontsize = 10 )
66
+
67
+ seen_notions = set ()
68
+ for i , (metric , notion ) in enumerate (zip (filtered_df ['Metric' ], filtered_df ['Notion' ])):
69
+ if notion not in seen_notions :
70
+ metrics_for_notion = filtered_df [filtered_df ['Notion' ] == notion ]['Metric' ]
71
+ start_pos = x_positions [i ]
72
+ end_pos = x_positions [i + len (metrics_for_notion ) - 1 ]
73
+
74
+ notion_x_pos = (start_pos + end_pos ) / 2
75
+
76
+ ax .text (notion_x_pos , notion_y_pos , notion , ha = 'center' , va = 'center' , fontsize = 10 , color = 'black' )
77
+
78
+ seen_notions .add (notion )
79
+
80
+ for i , v in enumerate (filtered_df ['Metric Score' ]):
81
+ ax .text (i , v + 0.01 , f"{ v :.2f} " , ha = 'center' , va = 'bottom' , fontsize = 10 , color = 'black' )
82
+
83
+ plt .xlabel ('Metrics and notions' , labelpad = 35 )
84
+ plt .ylabel ('Score' )
85
+ plt .title (f'Metrics and notion scores for the { pillar } pillar' )
86
+
87
+ ax .legend_ .remove ()
88
+
89
+ plt .tight_layout ()
90
+
91
+ self .nebulalogger .log_figure (ax .get_figure (), 0 , f"Trust/Pillar/{ pillar } " )
92
+ plt .close ()
93
+
94
+ def graphics (self ):
95
+ results_file = os .path .join (os .environ .get ("NEBULA_LOGS_DIR" ), self .scenario_name , "trustworthiness" , "nebula_trust_results.json" )
96
+ with open (results_file , 'r' ) as f :
97
+ results = json .load (f )
98
+
99
+ pillars_list = []
100
+ notion_names = []
101
+ notion_scores = []
102
+ metric_names = []
103
+ metric_scores = []
104
+
105
+ for pillar in results ["pillars" ]:
106
+ for key , value in pillar .items ():
107
+ pillar_name = key
108
+ if "notions" in value :
109
+ for notion in value ["notions" ]:
110
+ for notion_key , notion_value in notion .items ():
111
+ notion_name = notion_key
112
+ notion_score = notion_value ["score" ]
113
+ for metric in notion_value ["metrics" ]:
114
+ for metric_key , metric_value in metric .items ():
115
+ metric_name = metric_key
116
+ metric_score = metric_value ["score" ]
117
+
118
+ pillars_list .append (pillar_name )
119
+ notion_names .append (notion_name )
120
+ notion_scores .append (notion_score )
121
+ metric_names .append (metric_name )
122
+ metric_scores .append (metric_score )
123
+
124
+ df = pd .DataFrame ({
125
+ "Pillar" : pillars_list ,
126
+ "Notion" : notion_names ,
127
+ "Notion Score" : notion_scores ,
128
+ "Metric" : metric_names ,
129
+ "Metric Score" : metric_scores
130
+ })
131
+
132
+ self .__log_figure (df , 'robustness' , "#F8D3DF" )
133
+ self .__log_figure (df , "privacy" , "#DA8D8B" , - 0.2 )
134
+ self .__log_figure (df , "fairness" , "#DDDDDD" )
135
+ self .__log_figure (df , "explainability" , "#FCEFC3" )
136
+ self .__log_figure (df , "accountability" , "#8FAADC" , - 0.3 )
137
+ self .__log_figure (df , "architectural_soundness" , "#DBB9FA" , - 0.3 )
138
+ self .__log_figure (df , "sustainability" , "#BBFDAF" , - 0.5 , figsize = (12 ,8 ))
139
+
140
+ categories = [
141
+ "robustness" ,
142
+ "privacy" ,
143
+ "fairness" ,
144
+ "explainability" ,
145
+ "accountability" ,
146
+ "architectural_soundness" ,
147
+ "sustainability"
148
+ ]
149
+
150
+ scores = [results ["pillars" ][i ][category ]["score" ] for i , category in enumerate (categories )]
151
+
152
+ trust_score = results ["trust_score" ]
153
+ categories .append ("trust_score" )
154
+ scores .append (trust_score )
155
+
156
+ palette = ["#F8D3DF" , "#DA8D8B" , "#DDDDDD" , "#FCEFC3" , "#8FAADC" , "#DBB9FA" , "#BBFDAF" , "#BF9000" ]
157
+
158
+ plt .figure (figsize = (10 , 8 ))
159
+ ax = sns .barplot (x = categories , y = scores , palette = palette , hue = categories , legend = False )
160
+ ax .set_xlabel ("Pillar" )
161
+ ax .set_ylabel ("Score" )
162
+ ax .set_title ("Pillars and trust scores" )
163
+
164
+ for i , v in enumerate (scores ):
165
+ ax .text (i , v + 0.01 , f"{ v :.2f} " , ha = 'center' , va = 'bottom' , fontsize = 10 )
166
+
167
+ name_labels = [
168
+ "Robustness" ,
169
+ "Privacy" ,
170
+ "Fairness" ,
171
+ "Explainability" ,
172
+ "Accountability" ,
173
+ "Architectural Soundness" ,
174
+ "Sustainability" ,
175
+ "Trust Score"
176
+ ]
177
+
178
+ ax .set_xticks (range (len (categories )))
179
+ ax .set_xticklabels (name_labels , rotation = 45 )
180
+
181
+ self .nebulalogger .log_figure (ax .get_figure (), 0 , f"Trust/AllPillars" )
182
+ plt .close ()
0 commit comments