Anniek commited on
Commit
b0ff21d
·
1 Parent(s): ae67462

Upload 7 files

Browse files
pages/1-explanationpage.py ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from uuid import uuid4
3
+ from streamlit_extras.switch_page_button import switch_page
4
+ import random
5
+ import pandas as pd
6
+ import xgboost as xgb
7
+ import copy
8
+
9
+ header1, header2, header3 = st.columns([1,2,1])
10
+ body1, body2, body3 =st.columns([1,2,1])
11
+ footer1, footer2, footer3 =st.columns([1,2,1])
12
+
13
+ if 'nextPage' not in st.session_state:
14
+ st.session_state.nextPage = random.randint(0, len(st.session_state.pages)-1)
15
+ # st.write(st.session_state.nextPage)
16
+
17
+
18
+ @st.cache_data
19
+ def loadData():
20
+ train_df = pd.read_csv('assets/train_df.csv')
21
+ test_df = pd.read_csv('assets/test_df.csv')
22
+ test_with_names = pd.read_csv('assets/test_with_names.csv')
23
+ # test_with_names.drop('PassengerId', axis=1, inplace=True)
24
+ X_train = train_df.drop("Survived", axis=1)
25
+ Y_train = train_df["Survived"]
26
+ X_test = test_df.drop('PassengerId', axis=1)
27
+ X_test_names = test_with_names.copy()
28
+ title_df = pd.DataFrame({'Title indices': [1,2,3,4,5],
29
+ 'Title': ['Mr', 'Miss', 'Mrs', 'Master', 'Rare'] })
30
+ gender_df = pd.DataFrame({'Gender indices': [0,1],
31
+ 'Sex': ['Male', 'Female'] })
32
+ ports_df = pd.DataFrame({'Ports indices': [0,1,2],
33
+ 'Embarked': ['Southampton', 'Cherbourg', 'Quenstown'] })
34
+ return X_train, Y_train, X_test, X_test_names, title_df, gender_df, ports_df, train_df
35
+
36
+ if 'X_train' not in st.session_state:
37
+ st.session_state.X_train, st.session_state.Y_train, st.session_state.X_test, st.session_state.X_test_names, st.session_state.title_df, st.session_state.gender_df, st.session_state.ports_df, st.session_state.train_df = loadData()
38
+ # st.dataframe(st.session_state.X_train)
39
+ # st.session_state.X_train, st.session_state.Y_train, st.session_state.X_test, st.session_state.X_test_names= loadData()
40
+
41
+
42
+
43
+
44
+ with header2:
45
+ st.title("Who survived and why?")
46
+ # st.dataframe(st.session_state.X_train)
47
+ # st.write("For debugging:")
48
+ # st.write(st.session_state.participantID)
49
+ # X_train, Y_train, X_test= loadData()
50
+
51
+ with body2:
52
+ st.header("The Titanic")
53
+ st.markdown("In the year 1912, the Titanic left from Southampton to New York City, but it never arrived. On April 15, it crashed into an iceberg and sunk. Of the estimated 2,224 passengers and crew aboard, more than 1,500 died, making it the deadliest sinking of a single ship up to that time. ")
54
+ st.image('assets/titanic.jpg')
55
+ st.header('Explanation experiment')
56
+ st.markdown('''In this experiment we will show you two different profiles of passengers.
57
+ Using Machine Learning (ML) we will show a prediction whether they would have survived the disaster.
58
+ This prediction is accompanied by each time a different type of explanation.''')
59
+ st.markdown("After seeing 2 profiles, you will be asked to evaluate the explanation you have just seen.")
60
+
61
+ st.subheader('Demographic information')
62
+ st.markdown("Before you start with the study we would like to ask you to first answer these questions")
63
+
64
+
65
+
66
+ with footer2:
67
+ with st.form("demographic_form", clear_on_submit=True):
68
+ gender = st.radio("How do you identify your gender", ('Female', 'Male', 'Non-binary', 'Other', 'Prefer not to say'))
69
+ age = st.radio("How old are you?", ('18-25', '26-35', '36-45', '46-55', '56-65', '66-75', '75+'))
70
+ educationlevel = st.radio("What is your highest level of education?",
71
+ ('elementary school', 'high school', 'MBO', 'HBO', 'University'))
72
+ st.markdown('**AI literacy**')
73
+ st.markdown('Please rate to what extent you have the skills/knowledge listed below. 0 means that he ability is hardly or not at all pronounced, whereas a value of 10 means that the ability is very well or almost perfectly pronounced')
74
+ q1 = st.slider('I know the most important concepts of the topic "artificial intelligence"', 0, 10)
75
+ q2 = st.slider("I know definitions of artificial intelligence", 0, 10 )
76
+ q3 = st.slider("I can assess what the limitations and opportunities of using an AI are", 0, 10)
77
+ q4 = st.slider("I can assess what advantages and disadvantages the use of an artificial intelligence entails", 0, 10)
78
+ q5 = st.slider("I can think of new uses for AI.", 0, 10)
79
+ q6 = st.slider("I can imagine possible future uses of AI", 0, 10)
80
+
81
+ st.markdown('''On the next page you will see a profile of one of the passengers of the Titanic,
82
+ a prediction of whether they would have survived and an explanation for why the model made this prediction. Have a look at this and then generate a new profile by clicking on the button.
83
+ You can look at 2 profiles, next you will be asked to evaluate the explanation.
84
+ These steps will be repeated in total 4 times after which you will be asked some final questions. ''')
85
+
86
+ submitted = st.form_submit_button("Start the experiment")
87
+
88
+ if submitted:
89
+ st.session_state.oocsi.send('EngD_HAII_demographics', {
90
+ 'participant_ID': st.session_state.participantID,
91
+ 'gender': gender,
92
+ 'age': age,
93
+ 'educationLevel': educationlevel,
94
+ 'q1': q1,
95
+ 'q2': q2,
96
+ 'q3': q3,
97
+ 'q4': q4,
98
+ 'q5': q5,
99
+ 'q6': q6,
100
+ })
101
+ # if st.button("Start the experiment "):
102
+
103
+ switch_page(st.session_state.pages[st.session_state.nextPage])
pages/2_SHAP.py ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pandas as pd
3
+ import numpy as np
4
+ from oocsi_source import OOCSI
5
+ from uuid import uuid4
6
+ from streamlit_extras.switch_page_button import switch_page
7
+ import random
8
+ import shap
9
+ from IPython.display import display_html
10
+ import xgboost as xgb
11
+ import matplotlib.pyplot as plt
12
+
13
+ # st.markdown("""<style>
14
+ # .stSlider {
15
+ # padding-bottom: 20px;
16
+ # }
17
+ # </style> """,
18
+ # unsafe_allow_html=True)
19
+
20
+ #Delete this page from the array of pages to visit, this way it cannot be visited twice
21
+ if 'profile1' not in st.session_state:
22
+ st.session_state.pages.remove("SHAP")
23
+ st.session_state.profile1= 'deleted'
24
+ if (len(st.session_state.pages)>0):
25
+ st.session_state.nextPage1 = random.randint(0, len(st.session_state.pages)-1)
26
+ st.session_state.lastQuestion= 'no'
27
+ else:
28
+ st.session_state.lastQuestion= 'yes'
29
+
30
+
31
+ if 'index1' not in st.session_state:
32
+ st.session_state.index1= 0
33
+
34
+ if 'profileIndex' not in st.session_state:
35
+ st.session_state.profileIndex= st.session_state.profileIndices[st.session_state.index1]
36
+
37
+ header1, header2, header3 = st.columns([1,2,1])
38
+ characteristics1, characteristics2, characteristics3 = st.columns([1,2,1])
39
+ prediction1, prediction2, prediction3 =st.columns([1,2,1])
40
+ explanation1, explanation2, explanation3 = st.columns([1,5,1])
41
+ footer1, footer2, footer3 =st.columns([1,2,1])
42
+ evaluation1, evaluation2, evaluation3 = st.columns([1,2,1])
43
+
44
+
45
+
46
+
47
+ name= st.session_state.X_test_names.loc[st.session_state.profileIndex, "Name"]
48
+
49
+ @st.cache_resource
50
+ def trainModel(X_train,Y_train):
51
+ model = xgb.XGBClassifier().fit(X_train, Y_train)
52
+ return model
53
+
54
+
55
+ @st.cache_resource
56
+ def getSHAPvalues(_model,X_train, Y_train, X_test):
57
+ # compute SHAP values
58
+ explainer = shap.Explainer(_model, X_test)
59
+ shap_values = explainer(X_test)
60
+ return shap_values
61
+
62
+
63
+
64
+
65
+ def shapPlot(X_test, _shap_values):
66
+ return shap.plots.waterfall(shap_values[st.session_state.profileIndex])
67
+
68
+ with header2:
69
+ st.header('Explanation - SHAP Values')
70
+ st.markdown(''' The SHAP value algorithm (SHapley Additive exPlanations) is a way to reverse-engineer the output of any predictive machine learning model.
71
+ the technique helps to understand the decision took by a complex model. The classical models will typically answer the question 'how much' whereas the SHAP
72
+ model will focus on the 'why'.
73
+
74
+ Finally, the representation of the SHAP value will show how much each feature are contributing to the final prediction made by the model. For the Titanic dataset, each feature
75
+ will analyse each the contribution of each will be presented for different persons explaining the reason why this person survived the shipwreck or not.
76
+ ''')
77
+ st.subheader(name, anchor='top')
78
+ # st.write("For debugging:")
79
+ # st.write(st.session_state.participantID)
80
+ XGBmodel= trainModel(st.session_state.X_train, st.session_state.Y_train)
81
+
82
+ with characteristics2:
83
+ # initialize list of lists
84
+ data = st.session_state.X_test.iloc[st.session_state.profileIndex].values.reshape(1, -1)
85
+ # Create the pandas DataFrame
86
+ df = pd.DataFrame(data, columns=st.session_state.X_test.columns)
87
+ st.dataframe(df)
88
+
89
+
90
+
91
+ with prediction2:
92
+ # st.header("Prediction")
93
+ prediction = XGBmodel.predict(st.session_state.X_test.iloc[st.session_state.profileIndex].values.reshape(1, -1))
94
+ probability = XGBmodel.predict_proba(st.session_state.X_test.iloc[st.session_state.profileIndex].values.reshape(1, -1))
95
+
96
+ if prediction == 0:
97
+ prob = round((probability[0][0]*100),2)
98
+ st.markdown("The model predicts with {}% probability that {} will :red[**not survive**]".format(prob, name) )
99
+
100
+ else:
101
+ prob = round((probability[0][1]*100),2)
102
+ st.markdown("The model predicts with {}% probability that {} will :green[**survive**]".format(prob, name) )
103
+
104
+
105
+ with explanation2:
106
+ st.subheader("Explanation")
107
+ # with st.spinner("Please be patient, we are generating a new explanation"):
108
+ shap_values= getSHAPvalues(XGBmodel, st.session_state.X_train, st.session_state.Y_train, st.session_state.X_test)
109
+ st.set_option('deprecation.showPyplotGlobalUse', False)
110
+ fig = shap.plots.waterfall(shap_values[st.session_state.profileIndex])
111
+ st.pyplot(fig, bbox_inches='tight')
112
+ data_indices = pd.concat([d.reset_index(drop=True) for d in [st.session_state.ports_df, st.session_state.title_df, st.session_state.gender_df]], axis=1)
113
+ # st.dataframe(st.session_state.ports_df)
114
+ # st.dataframe(st.session_state.title_df)
115
+ # st.dataframe(st.session_state.gender_df)
116
+ st.dataframe(data_indices)
117
+
118
+ with footer2:
119
+
120
+ if (st.session_state.index1 < len(st.session_state.profileIndices)-1):
121
+ if st.button("New profile"):
122
+
123
+ st.session_state.index1 = st.session_state.index1+1
124
+ st.session_state.profileIndex = st.session_state.profileIndices[st.session_state.index1]
125
+ st.experimental_rerun()
126
+ else:
127
+ def is_user_active():
128
+ if 'user_active1' in st.session_state.keys() and st.session_state['user_active1']:
129
+ return True
130
+ else:
131
+ return False
132
+ if is_user_active():
133
+ # st.markdown("You have reached the end of the profiles")
134
+ # if st.button("Continue to evaluation"):
135
+ # st.write(" ")
136
+ with st.form("my_form1", clear_on_submit=True):
137
+ st.subheader("Evaluation")
138
+ st.write("These questions only ask for your opinion about this specific explanation")
139
+ q1 = st.select_slider(
140
+ '**1**- From the explanation, I **understand** how the algorithm works:',
141
+ options=['totally disagree', 'disagree', 'neutral' , 'agree', 'totally agree'])
142
+
143
+ q2 = st.select_slider(
144
+ '**2**- This explanation of how the algorithm works is **satisfying**:',
145
+ options=['totally disagree', 'disagree', 'neutral' , 'agree', 'totally agree'])
146
+
147
+ q3 = st.select_slider(
148
+ '**3**- This explanation of how the algorithm works has **sufficient detail**:',
149
+ options=['totally disagree', 'disagree', 'neutral' , 'agree', 'totally agree'])
150
+
151
+ q4 = st.select_slider(
152
+ '**4**- This explanation of how the algorithm works seems **complete**:',
153
+ options=['totally disagree', 'disagree', 'neutral' , 'agree', 'totally agree'])
154
+
155
+ q5 = st.select_slider(
156
+ '**5**- This explanation of how the algorithm works **tells me how to use it**:',
157
+ options=['totally disagree', 'disagree', 'neutral' , 'agree', 'totally agree'])
158
+
159
+ q6 = st.select_slider(
160
+ '**6**- This explanation of how the algorithm works is **useful to my goals**:',
161
+ options=['totally disagree', 'disagree', 'neutral' , 'agree', 'totally agree'])
162
+
163
+ q7 = st.select_slider(
164
+ '**7**- This explanation of the algorithm shows me how **accurate** the algorithm is:',
165
+ options=['totally disagree', 'disagree', 'neutral' , 'agree', 'totally agree'])
166
+
167
+ q8 = st.select_slider(
168
+ '**8**- This explanation lets me judge when I should **trust and not trust** the algorithm:',
169
+ options=['totally disagree', 'disagree', 'neutral' , 'agree', 'totally agree'])
170
+
171
+ # Every form must have a submit button.
172
+ submitted = st.form_submit_button("Submit")
173
+ if submitted:
174
+ st.write("question 1", q1)
175
+ st.session_state.oocsi.send('EngD_HAII', {
176
+ 'participant_ID': st.session_state.participantID,
177
+ 'type of explanation': 'SHAP',
178
+ 'q1': q1,
179
+ 'q2': q2,
180
+ 'q3': q3,
181
+ 'q4': q4,
182
+ 'q5': q5,
183
+ 'q6': q6,
184
+ 'q7': q7,
185
+ 'q8': q8,
186
+
187
+ })
188
+ if (st.session_state.lastQuestion =='yes'):
189
+ switch_page('finalPage')
190
+ else:
191
+ st.session_state.profileIndex =st.session_state.profileIndices[0]
192
+ switch_page(st.session_state.pages[st.session_state.nextPage1])
193
+ else:
194
+ if st.button('Continue to evaluation'):
195
+ st.session_state['user_active1']=True
196
+ st.experimental_rerun()
pages/3_DecisionTree.py ADDED
@@ -0,0 +1,264 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pandas as pd
3
+ import numpy as np
4
+ from oocsi_source import OOCSI
5
+ from uuid import uuid4
6
+ from streamlit_extras.switch_page_button import switch_page
7
+ import random
8
+ import dtreeviz
9
+ import xgboost as xgb
10
+ from dtreeviz.trees import dtreeviz
11
+ from sklearn.tree import DecisionTreeClassifier
12
+ import graphviz as graphviz
13
+ from sklearn.datasets import make_moons
14
+ import base64
15
+
16
+ # import os
17
+ # os.environ["PATH"] += os.pathsep + 'D:/Program Files (x86)/Graphviz2.38/bin/'
18
+
19
+ # st.markdown("""<style>
20
+ # .stSlider {
21
+ # padding-bottom: 20px;
22
+ # }
23
+ # </style> """,
24
+ # unsafe_allow_html=True)
25
+
26
+ #Delete this page from the array of pages to visit, this way it cannot be visited twice
27
+ if 'profile2' not in st.session_state:
28
+ st.session_state.pages.remove("DecisionTree")
29
+ st.session_state.profile2= 'deleted'
30
+ if (len(st.session_state.pages)>0):
31
+ st.session_state.nextPage2 = random.randint(0, len(st.session_state.pages)-1)
32
+ st.session_state.lastQuestion= 'no'
33
+ else:
34
+ st.session_state.lastQuestion= 'yes'
35
+
36
+
37
+ if 'index2' not in st.session_state:
38
+ st.session_state.index2= 0
39
+
40
+
41
+ if 'profileIndex' not in st.session_state:
42
+ st.session_state.profileIndex= st.session_state.profileIndices[st.session_state.index2]
43
+
44
+ name= st.session_state.X_test_names.loc[st.session_state.profileIndex, "Name"]
45
+
46
+
47
+
48
+ header1, header2, header3 = st.columns([1,2,1])
49
+ characteristics1, characteristics2, characteristics3 = st.columns([1,2,1])
50
+ prediction1, prediction2, prediction3 =st.columns([1,2,1])
51
+ explanation1, explanation2, explanation3 = st.columns([1,2,1])
52
+ footer1, footer2, footer3 =st.columns([1,2,1])
53
+ evaluation1, evaluation2, evaluation3 = st.columns([1,2,1])
54
+
55
+
56
+ @st.cache_resource
57
+ def loadData():
58
+ train_df = pd.read_csv('assets/train_df.csv')
59
+ test_df = pd.read_csv('assets/test_df.csv')
60
+ X_train = train_df.drop("Survived", axis=1)
61
+ Y_train = train_df["Survived"]
62
+ X_test = test_df.drop("PassengerId", axis=1).copy()
63
+ return X_train, Y_train, X_test
64
+
65
+ @st.cache_resource
66
+ def trainModel(X_train,Y_train):
67
+ model = xgb.XGBClassifier().fit(X_train, Y_train)
68
+ return model
69
+
70
+ # @st.cache_resource
71
+ def createTree(_model, X_train, Y_train, X_test):
72
+ # X, y = make_moons(n_samples=20, noise=0.25, random_state=3)
73
+ # treeclf = DecisionTreeClassifier(random_state=0)
74
+ # treeclf.fit(X, y)
75
+ # viz_model= dtreeviz(treeclf, X, y, target_name="Classes",
76
+ # feature_names=["f0", "f1"], class_names=["c0", "c1"])
77
+ # clf = DecisionTreeClassifier(max_depth=3)
78
+ # clf.fit(X_train, Y_train)
79
+
80
+ # Y_pred = clf.predict(X_test)
81
+ # acc_decision_tree2 = round(clf.score(X_train, Y_train) * 100, 2)
82
+ # viz_model = dtreeviz(clf,
83
+ # X_train, Y_train,
84
+ # feature_names=X_train.columns,
85
+ # target_name='Survived',
86
+ # class_names=['Dead', 'Alive'],
87
+ # X=X_test.iloc[1]
88
+ # )
89
+ viz_model = dtreeviz(_model,
90
+ X_train, Y_train,
91
+ tree_index=0,
92
+ feature_names=list(X_train.columns),
93
+ target_name='Survived',
94
+ class_names=['Dead', 'Alive'],
95
+ X=X_test.iloc[st.session_state.profileIndex],
96
+ #depth_range_to_display=(0, 2),
97
+ show_just_path=True,
98
+ # orientation ='LR',
99
+ )
100
+ #path = "/assets/images/prediction_path" + str(st.session_state.profileIndex) +".svg"
101
+ viz_model.save("/assets/images/prediction_path.svg")
102
+ return viz_model
103
+
104
+ def render_svg(svg):
105
+ """Renders the given svg string."""
106
+ b64 = base64.b64encode(svg.encode('utf-8')).decode("utf-8")
107
+ html = r'<img src="data:image/svg+xml;base64,%s"/>' % b64
108
+ st.write(html, unsafe_allow_html=True)
109
+
110
+
111
+ with header2: #header2
112
+ st.header("Explanation - Decision Tree")
113
+ st.markdown('''Decision Tree models are a non-parametric supervised learning method
114
+ commonly used for classification and regression.
115
+ They are constructed using two kinf of elements: Nodes and branches. At each node (intersection),
116
+ one of the data features is evaluated to split the observations into different paths.
117
+
118
+
119
+ At typical decision example is shown in the graph below.
120
+ ''')
121
+
122
+ st.image('assets/Decision_tree.jpg',caption = 'Example of a decision tree')
123
+
124
+ st.markdown(''' The Root Node starts the graph. It is usually the variable that splits the more lcearly the data.
125
+ Then, intermediate nodes are vsisble were different varaibales are evaluated but no final prediction is made yet.
126
+ Finally, leaf nodes are present where the predicrtions (numerical of categoriacl) are made.
127
+
128
+ For the Titanic dataset, the prediction will be whether the studied person survived the shipwreck.
129
+ ''')
130
+
131
+ st.subheader(name)
132
+ XGBmodel= trainModel(st.session_state.X_train, st.session_state.Y_train)
133
+ # st.write("For debugging:")
134
+ # st.write(st.session_state.participantID)
135
+
136
+ with characteristics2:
137
+ # initialize list of lists
138
+ data = st.session_state.X_test.iloc[st.session_state.profileIndex].values.reshape(1, -1)
139
+ # Create the pandas DataFrame
140
+ df = pd.DataFrame(data, columns=st.session_state.X_test.columns)
141
+ st.dataframe(df)
142
+
143
+
144
+ with prediction2:
145
+ prediction = XGBmodel.predict(st.session_state.X_test.iloc[st.session_state.profileIndex].values.reshape(1, -1))
146
+ probability = XGBmodel.predict_proba(st.session_state.X_test.iloc[st.session_state.profileIndex].values.reshape(1, -1))
147
+ if prediction == 0:
148
+ prob = round((probability[0][0]*100),2)
149
+ st.markdown("The model predicts with {}% probability that {} will :red[**not survive**]".format(prob, name) )
150
+ else:
151
+ prob = round((probability[0][1]*100),2)
152
+ st.markdown("The model predicts with {}% probability that {} will :green[**survive**]".format(prob, name) )
153
+
154
+ with explanation2:
155
+ st.subheader("Visualization - Decision Tree")
156
+ # st.markdown('''Decision Tree model are a non-parametric supervised learning method
157
+ # commonly used for classification and regression.
158
+ # They are constructed using two kinf of elements: Nodes and branches. At each node (intersection),
159
+ # one of the data features is evaluated to split the observations into different paths.
160
+
161
+
162
+ # At typical decision example is shown in the graph below.
163
+ # ''')
164
+
165
+ # st.image('assets/Decision_tree.jpg')
166
+
167
+ # st.markdown(''' The Root Node starts the graph. It is usually the variable that splits the more lcearly the data.
168
+ # Then, intermediate nodes are vsisble were different varaibales are evaluated but no final prediction is made yet.
169
+ # Finally, leaf nodes are present where the predicrtions (numerical of categoriacl) are made.
170
+
171
+ # For the Titanic dataset, the prediction will be whether the studied person survived the shipwreck.
172
+ # ''')
173
+
174
+
175
+
176
+ with st.spinner("Please be patient, we are generating a new explanation"):
177
+ viz_model = createTree(XGBmodel, st.session_state.X_train, st.session_state.Y_train, st.session_state.X_test)
178
+ # st.image("/assets/images/prediction_path.svg", width =200, use_column_width=True)
179
+ #viz_model.view()
180
+ # read in svg prediction path and display
181
+ path = "/assets/images/prediction_path" + str(st.session_state.profileIndex) +".svg"
182
+ # st.success("Done!")
183
+ with open("/assets/images/prediction_path.svg", "r") as f:
184
+ svg = f.read()
185
+ render_svg(svg)
186
+
187
+ st.text("")
188
+
189
+ with footer2:
190
+ if (st.session_state.index2 < len(st.session_state.profileIndices)-1):
191
+ if st.button("New profile"):
192
+ st.session_state.index2 = st.session_state.index2+1
193
+ st.session_state.profileIndex = st.session_state.profileIndices[st.session_state.index2]
194
+ st.experimental_rerun()
195
+ else:
196
+ def is_user_active():
197
+ if 'user_active2' in st.session_state.keys() and st.session_state['user_active2']:
198
+ return True
199
+ else:
200
+ return False
201
+ if is_user_active():
202
+ # if st.button("Continue to evaluation"):
203
+ # st.write(" ")
204
+ with st.form("my_form2", clear_on_submit=True):
205
+ st.subheader("Evaluation")
206
+ st.write("These questions only ask for your opinion about this specific explanation")
207
+ q1 = st.select_slider(
208
+ '**1**- From the explanation, I **understand** how the algorithm works:',
209
+ options=['totally disagree', 'disagree', 'neutral' , 'agree', 'totally agree'])
210
+
211
+ q2 = st.select_slider(
212
+ '**2**- This explanation of how the algorithm works is **satisfying**:',
213
+ options=['totally disagree', 'disagree', 'neutral' , 'agree', 'totally agree'])
214
+
215
+ q3 = st.select_slider(
216
+ '**3**- This explanation of how the algorithm works has **sufficient detail**:',
217
+ options=['totally disagree', 'disagree', 'neutral' , 'agree', 'totally agree'])
218
+
219
+ q4 = st.select_slider(
220
+ '**4**- This explanation of how the algorithm works seems **complete**:',
221
+ options=['totally disagree', 'disagree', 'neutral' , 'agree', 'totally agree'])
222
+
223
+ q5 = st.select_slider(
224
+ '**5**- This explanation of how the algorithm works **tells me how to use it**:',
225
+ options=['totally disagree', 'disagree', 'neutral' , 'agree', 'totally agree'])
226
+
227
+ q6 = st.select_slider(
228
+ '**6**- This explanation of how the algorithm works is **useful to my goals**:',
229
+ options=['totally disagree', 'disagree', 'neutral' , 'agree', 'totally agree'])
230
+
231
+ q7 = st.select_slider(
232
+ '**7**- This explanation of the algorithm shows me how **accurate** the algorithm is:',
233
+ options=['totally disagree', 'disagree', 'neutral' , 'agree', 'totally agree'])
234
+
235
+ q8 = st.select_slider(
236
+ '**8**- This explanation lets me judge when I should **trust and not trust** the algorithm:',
237
+ options=['totally disagree', 'disagree', 'neutral' , 'agree', 'totally agree'])
238
+
239
+ # Every form must have a submit button.
240
+ submitted = st.form_submit_button("Submit")
241
+ if submitted:
242
+ # st.write("question 1", q1)
243
+ st.session_state.oocsi.send('EngD_HAII', {
244
+ 'participant_ID': st.session_state.participantID,
245
+ 'type of explanation': 'Decision tree',
246
+ 'q1': q1,
247
+ 'q2': q2,
248
+ 'q3': q3,
249
+ 'q4': q4,
250
+ 'q5': q5,
251
+ 'q6': q6,
252
+ 'q7': q7,
253
+ 'q8': q8,
254
+
255
+ })
256
+ if (st.session_state.lastQuestion =='yes'):
257
+ switch_page('finalPage')
258
+ else:
259
+ st.session_state.profileIndex =st.session_state.profileIndices[0]
260
+ switch_page(st.session_state.pages[st.session_state.nextPage2])
261
+ else:
262
+ if st.button('Continue to evaluation'):
263
+ st.session_state['user_active2']=True
264
+ st.experimental_rerun()
pages/4_counterfactual.py ADDED
@@ -0,0 +1,215 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pandas as pd
3
+ import numpy as np
4
+ import copy
5
+ from oocsi_source import OOCSI
6
+ from uuid import uuid4
7
+ from streamlit_extras.switch_page_button import switch_page
8
+ import random
9
+ # import shap
10
+ import dice_ml
11
+ from dice_ml.utils import helpers
12
+ import xgboost as xgb
13
+ import matplotlib.pyplot as plt
14
+ from sklearn.ensemble import RandomForestClassifier
15
+
16
+
17
+ # st.markdown("""<style>
18
+ # .stSlider {
19
+ # padding-bottom: 20px;
20
+ # }
21
+ # </style> """,
22
+ # unsafe_allow_html=True)
23
+
24
+ # st.session_state.Y_train
25
+ # st.session_state.X_test
26
+ # st.session_state.X_test_names
27
+
28
+
29
+ #Delete this page from the array of pages to visit, this way it cannot be visited twice
30
+ if 'profile3' not in st.session_state:
31
+ st.session_state.pages.remove("counterfactual")
32
+ st.session_state.profile3= 'deleted'
33
+ if (len(st.session_state.pages)>0):
34
+ st.session_state.nextPage3 = random.randint(0, len(st.session_state.pages)-1)
35
+ st.session_state.lastQuestion= 'no'
36
+ else:
37
+ st.session_state.lastQuestion= 'yes'
38
+
39
+
40
+ if 'index3' not in st.session_state:
41
+ st.session_state.index3= 0
42
+
43
+
44
+ if 'profileIndex' not in st.session_state:
45
+ st.session_state.profileIndex= st.session_state.profileIndices[st.session_state.index3]
46
+
47
+ header1, header2, header3 = st.columns([1,2,1])
48
+ characteristics1, characteristics2, characteristics3 = st.columns([1,2,1])
49
+ prediction1, prediction2, prediction3 =st.columns([1,2,1])
50
+ explanation1, explanation2, explanation3 = st.columns([1,10,1])
51
+ footer1, footer2, footer3 =st.columns([1,2,1])
52
+ evaluation1, evaluation2, evaluation3 = st.columns([1,2,1])
53
+
54
+
55
+
56
+ name= st.session_state.X_test_names.loc[st.session_state.profileIndex, "Name"]
57
+
58
+
59
+ @st.cache_resource
60
+ def trainModel(X_train,Y_train):
61
+ model_1 = RandomForestClassifier().fit(X_train, Y_train) ## Random forest because XGBoost doesn't work with counterfactuals
62
+ return model_1
63
+
64
+
65
+ @st.cache_resource
66
+ def getcounterfactual_values(_model,X_prediction, X_train):
67
+ # compute counterfactual values
68
+ train_df = pd.read_csv('assets/train_df.csv')
69
+ continous_col=["Age", 'Fare', 'Siblings_spouses', 'Title', 'Parents_children','relatives' ]
70
+ # test_df_counter = X_test.copy()
71
+ # test_df_counter['Survived'] = X_prediction
72
+ dice_data = dice_ml.Data(dataframe=train_df,continuous_features=continous_col, outcome_name='Survived')
73
+ dice_model= dice_ml.Model(model=_model, backend="sklearn")
74
+ explainer = dice_ml.Dice(dice_data, dice_model, method="random")
75
+ return explainer
76
+
77
+
78
+
79
+ def Counterfactualsplot(X_test, explainer):
80
+ e1 = explainer.generate_counterfactuals(
81
+ X_test[1:2],total_CFs=4, desired_class="opposite",
82
+ features_to_vary = ['Age','Pclass', 'Sex','Siblings_spouses', 'Parents_children', 'Embarked', 'relatives', 'Title'] ) ## Deck, Fare
83
+ e1.cf_examples_list[0].final_cfs_df.to_csv(path_or_buf=rf'assets\counterfactuals_{name}.csv', index=False)
84
+ counter_csv = pd.read_csv(f'assets\counterfactuals_{name}.csv')
85
+ return st.dataframe(counter_csv, width=10000)
86
+
87
+ with header2:
88
+ st.header("Explanation - Counterfactuals")
89
+ st.markdown('''A counterfactual explanation describes a situation where if a specific event had not occurred, the conclusion would have been different
90
+ and a specific outcome would not have occurred. In machine learning, counterfactuals are used to explain prediction of individuals instances. The prediction
91
+ of the model will be analysed and certain conditions/features that created this prediction will be modified to obtain an different outcome for the model.''')
92
+
93
+ st.markdown('''As displayed in the graph below, the relation betwwen the inputs andthe prediciton is modified by the feature values that creates a simple causal
94
+ relationshhip betwen inputs and predictions.
95
+ ''')
96
+
97
+ st.image('assets/counterfactual.jpg', caption = 'Causal relation between inputs and predictions', use_column_width = 'always' )
98
+
99
+ st.markdown('''A counterfactual explanation of a prediction will then describe the smallest amount of change that is necessary to make to change the output
100
+ prediction to a predefine one.''')
101
+ st.subheader(name, anchor='top')
102
+ # st.write("For debugging:")
103
+ # st.write(st.session_state.participantID)
104
+ random_forest= trainModel(st.session_state.X_train, st.session_state.Y_train)
105
+
106
+ with characteristics2:
107
+ # initialize list of lists
108
+ data = st.session_state.X_test.iloc[st.session_state.profileIndex].values.reshape(1, -1)
109
+ # Create the pandas DataFrame
110
+ df = pd.DataFrame(data, columns=st.session_state.X_test.columns)
111
+ st.dataframe(df)
112
+
113
+
114
+ with prediction2:
115
+ # st.header("Prediction")
116
+ prediction = random_forest.predict(st.session_state.X_test.iloc[st.session_state.profileIndex].values.reshape(1, -1))
117
+ prediction_all = random_forest.predict(st.session_state.X_test.values)
118
+ probability = random_forest.predict_proba(st.session_state.X_test.iloc[st.session_state.profileIndex].values.reshape(1, -1))
119
+ if prediction == 0:
120
+ prob = round((probability[0][0]*100),2)
121
+ st.markdown("The model predicts with {}% probability that {} will :red[**not survive**]".format(prob, name) )
122
+ else:
123
+ prob = round((probability[0][1]*100),2)
124
+ st.markdown("The model predicts with {}% probability that {} will :green[**survive**]".format(prob, name) )
125
+
126
+ with explanation2:
127
+ st.subheader("Explanation")
128
+ st.markdown("counterfactual, more text here")
129
+
130
+
131
+
132
+ # with st.spinner("Please be patient, we are generating a new explanation"):
133
+ explainer= getcounterfactual_values(random_forest, prediction_all, st.session_state.X_test)
134
+ st.set_option('deprecation.showPyplotGlobalUse', False)
135
+ e1=Counterfactualsplot(st.session_state.X_test, explainer)
136
+ data_indices = pd.concat([d.reset_index(drop=True) for d in [st.session_state.ports_df, st.session_state.title_df, st.session_state.gender_df]], axis=1)
137
+ st.dataframe(data_indices)
138
+
139
+ with footer2:
140
+ if (st.session_state.index3 < len(st.session_state.profileIndices)-1):
141
+ if st.button("New profile"):
142
+ st.session_state.index3 = st.session_state.index3+1
143
+ st.session_state.profileIndex = st.session_state.profileIndices[st.session_state.index3]
144
+ st.experimental_rerun()
145
+ else:
146
+ def is_user_active():
147
+ if 'user_active3' in st.session_state.keys() and st.session_state['user_active3']:
148
+ return True
149
+ else:
150
+ return False
151
+ if is_user_active():
152
+ # if st.button("Continue to evaluation"):
153
+ # st.write(" ")
154
+ with st.form("my_form3", clear_on_submit=True):
155
+ st.subheader("Evaluation")
156
+ st.write("These questions only ask for your opinion about this specific explanation")
157
+ q1 = st.select_slider(
158
+ '**1**- From the explanation, I **understand** how the algorithm works:',
159
+ options=['totally disagree', 'disagree', 'neutral' , 'agree', 'totally agree'])
160
+
161
+ q2 = st.select_slider(
162
+ '**2**- This explanation of how the algorithm works is **satisfying**:',
163
+ options=['totally disagree', 'disagree', 'neutral' , 'agree', 'totally agree'])
164
+
165
+ q3 = st.select_slider(
166
+ '**3**- This explanation of how the algorithm works has **sufficient detail**:',
167
+ options=['totally disagree', 'disagree', 'neutral' , 'agree', 'totally agree'])
168
+
169
+ q4 = st.select_slider(
170
+ '**4**- This explanation of how the algorithm works seems **complete**:',
171
+ options=['totally disagree', 'disagree', 'neutral' , 'agree', 'totally agree'])
172
+
173
+ q5 = st.select_slider(
174
+ '**5**- This explanation of how the algorithm works **tells me how to use it**:',
175
+ options=['totally disagree', 'disagree', 'neutral' , 'agree', 'totally agree'])
176
+
177
+ q6 = st.select_slider(
178
+ '**6**- This explanation of how the algorithm works is **useful to my goals**:',
179
+ options=['totally disagree', 'disagree', 'neutral' , 'agree', 'totally agree'])
180
+
181
+ q7 = st.select_slider(
182
+ '**7**- This explanation of the algorithm shows me how **accurate** the algorithm is:',
183
+ options=['totally disagree', 'disagree', 'neutral' , 'agree', 'totally agree'])
184
+
185
+ q8 = st.select_slider(
186
+ '**8**- This explanation lets me judge when I should **trust and not trust** the algorithm:',
187
+ options=['totally disagree', 'disagree', 'neutral' , 'agree', 'totally agree'])
188
+
189
+ # Every form must have a submit button.
190
+ submitted = st.form_submit_button("Submit")
191
+ if submitted:
192
+ # st.write("question 1", q1)
193
+ st.session_state.oocsi.send('EngD_HAII', {
194
+ 'participant_ID': st.session_state.participantID,
195
+ 'type of explanation': 'counterfactual',
196
+ 'q1': q1,
197
+ 'q2': q2,
198
+ 'q3': q3,
199
+ 'q4': q4,
200
+ 'q5': q5,
201
+ 'q6': q6,
202
+ 'q7': q7,
203
+ 'q8': q8,
204
+
205
+ })
206
+ if (st.session_state.lastQuestion =='yes'):
207
+ switch_page('finalPage')
208
+ else:
209
+ st.session_state.profileIndex =st.session_state.profileIndices[0]
210
+ switch_page(st.session_state.pages[st.session_state.nextPage3])
211
+ else:
212
+ if st.button('Continue to evaluation'):
213
+ st.session_state['user_active3']=True
214
+ st.experimental_rerun()
215
+
pages/5_visualMap.py ADDED
@@ -0,0 +1,179 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pandas as pd
3
+ import numpy as np
4
+ from oocsi_source import OOCSI
5
+ from uuid import uuid4
6
+ from streamlit_extras.switch_page_button import switch_page
7
+ import random
8
+ import shap
9
+ import xgboost as xgb
10
+ import matplotlib.pyplot as plt
11
+ import streamlit.components.v1 as components
12
+
13
+
14
+ #Delete this page from the array of pages to visit, this way it cannot be visited twice
15
+ if 'profile4' not in st.session_state:
16
+ st.session_state.pages.remove("visualMap")
17
+ st.session_state.profile4= 'deleted'
18
+ if (len(st.session_state.pages)>0):
19
+ st.session_state.nextPage4 = random.randint(0, len(st.session_state.pages)-1)
20
+ st.session_state.lastQuestion= 'no'
21
+ else:
22
+ st.session_state.lastQuestion= 'yes'
23
+
24
+
25
+ if 'index4' not in st.session_state:
26
+ st.session_state.index4= 0
27
+
28
+ if 'profileIndex' not in st.session_state:
29
+ st.session_state.profileIndex= st.session_state.profileIndices[st.session_state.index4]
30
+
31
+
32
+
33
+ header1, header2, header3 = st.columns([1,2,1])
34
+ characteristics1, characteristics2, characteristics3 = st.columns([1,2,1])
35
+ prediction1, prediction2, prediction3 =st.columns([1,2,1])
36
+ explanationheader1,explanationheader2, explanationheader3 = st.columns([1,2,1])
37
+ explanation1, explanation2, explanation3 = st.columns([1,6,1])
38
+ footer1, footer2, footer3 =st.columns([1,2,1])
39
+ evaluation1, evaluation2, evaluation3 = st.columns([1,2,1])
40
+
41
+
42
+
43
+ name= st.session_state.X_test_names.loc[st.session_state.profileIndex, "Name"]
44
+
45
+
46
+ @st.cache_resource
47
+ def trainModel(X_train,Y_train):
48
+ model = xgb.XGBClassifier().fit(X_train, Y_train)
49
+ return model
50
+
51
+
52
+ @st.cache_resource
53
+ def getSHAPvalues(_model,X_train, Y_train, X_test):
54
+ # compute SHAP values
55
+ explainer = shap.Explainer(_model, X_test)
56
+ shap_values = explainer(X_test)
57
+ return shap_values
58
+
59
+
60
+
61
+
62
+ def shapPlot(X_test, _shap_values):
63
+ return shap.plots.waterfall(shap_values[st.session_state.profileIndex])
64
+
65
+
66
+ with header2:
67
+ st.header('Visual Method for XAI')
68
+ st.markdown('''In this part, a new method of Explainability was implemented using more visual techniques for communicating of the model
69
+ predictions and the features influence. The values showed when clicked on each feature (title, Age, deck, ...) were obtained using the SHAP algorithm.
70
+ Let yourself play with it and tell us how easy it was to understand the model prediciton and the influence of the features!
71
+
72
+ ''')
73
+ st.markdown("Click on the image to see how each attribute contributed and hover over them to see the SHAP values")
74
+ # st.subheader(name, anchor='top')
75
+ st.write("For debugging:")
76
+ st.write(st.session_state.participantID)
77
+ XGBmodel= trainModel(st.session_state.X_train, st.session_state.Y_train)
78
+
79
+ with characteristics2:
80
+ # initialize list of lists
81
+ data = st.session_state.X_test.iloc[st.session_state.profileIndex].values.reshape(1, -1)
82
+ # Create the pandas DataFrame
83
+ df = pd.DataFrame(data, columns=st.session_state.X_test.columns)
84
+ # st.dataframe(df)
85
+
86
+
87
+
88
+ with prediction2:
89
+ st.subheader("Prediction")
90
+ prediction = XGBmodel.predict(st.session_state.X_test.iloc[st.session_state.profileIndex].values.reshape(1, -1))
91
+ probability = XGBmodel.predict_proba(st.session_state.X_test.iloc[st.session_state.profileIndex].values.reshape(1, -1))
92
+ if prediction == 0:
93
+ prob = round((probability[0][0]*100),2)
94
+ st.markdown("The model predicts with {}% probability that {} will :red[**not survive**]".format(prob, name) )
95
+ else:
96
+ prob = round((probability[0][1]*100),2)
97
+ st.markdown("The model predicts with {}% probability that {} will :green[**survive**]".format(prob, name) )
98
+
99
+ # with explanationheader2:
100
+ # st.subheader("Explanation")
101
+ # st.markdown("Click on the image to see how each attribute contributed and hover over them to see the SHAP values")
102
+
103
+ with explanation2:
104
+ components.iframe("https://observablehq.com/embed/d177ef99668b6553@1065?cells=viewof+button%2Cchart2", scrolling=False, height=683)
105
+
106
+
107
+ with footer2:
108
+
109
+ def is_user_active():
110
+ if 'user_active4' in st.session_state.keys() and st.session_state['user_active4']:
111
+ return True
112
+ else:
113
+ return False
114
+ # if st.button('press here to edit'):
115
+ if is_user_active():
116
+ with st.form("my_form4", clear_on_submit=True):
117
+ st.subheader("Evaluation")
118
+ st.write("These questions only ask for your opinion about this specific explanation")
119
+ q1 = st.select_slider(
120
+ '**1**- From the explanation, I **understand** how the algorithm works:',
121
+ options=['totally disagree', 'disagree', 'neutral' , 'agree', 'totally agree'])
122
+
123
+ q2 = st.select_slider(
124
+ '**2**- This explanation of how the algorithm works is **satisfying**:',
125
+ options=['totally disagree', 'disagree', 'neutral' , 'agree', 'totally agree'])
126
+
127
+ q3 = st.select_slider(
128
+ '**3**- This explanation of how the algorithm works has **sufficient detail**:',
129
+ options=['totally disagree', 'disagree', 'neutral' , 'agree', 'totally agree'])
130
+
131
+ q4 = st.select_slider(
132
+ '**4**- This explanation of how the algorithm works seems **complete**:',
133
+ options=['totally disagree', 'disagree', 'neutral' , 'agree', 'totally agree'])
134
+
135
+ q5 = st.select_slider(
136
+ '**5**- This explanation of how the algorithm works **tells me how to use it**:',
137
+ options=['totally disagree', 'disagree', 'neutral' , 'agree', 'totally agree'])
138
+
139
+ q6 = st.select_slider(
140
+ '**6**- This explanation of how the algorithm works is **useful to my goals**:',
141
+ options=['totally disagree', 'disagree', 'neutral' , 'agree', 'totally agree'])
142
+
143
+ q7 = st.select_slider(
144
+ '**7**- This explanation of the algorithm shows me how **accurate** the algorithm is:',
145
+ options=['totally disagree', 'disagree', 'neutral' , 'agree', 'totally agree'])
146
+
147
+ q8 = st.select_slider(
148
+ '**8**- This explanation lets me judge when I should **trust and not trust** the algorithm:',
149
+ options=['totally disagree', 'disagree', 'neutral' , 'agree', 'totally agree'])
150
+
151
+ # Every form must have a submit button.
152
+ submitted = st.form_submit_button("Submit")
153
+ if submitted:
154
+ #st.write("question 1", q1)
155
+ st.session_state.oocsi.send('EngD_HAII', {
156
+ 'participant_ID': st.session_state.participantID,
157
+ 'type of explanation': 'visualmap',
158
+ 'q1': q1,
159
+ 'q2': q2,
160
+ 'q3': q3,
161
+ 'q4': q4,
162
+ 'q5': q5,
163
+ 'q6': q6,
164
+ 'q7': q7,
165
+ 'q8': q8,
166
+
167
+ })
168
+ if (st.session_state.lastQuestion =='yes'):
169
+ switch_page('finalPage')
170
+ else:
171
+ st.session_state.profileIndex =st.session_state.profileIndices[0]
172
+ switch_page(st.session_state.pages[st.session_state.nextPage4])
173
+ else:
174
+ if st.button('Continue to evaluation'):
175
+ st.session_state['user_active4']=True
176
+ st.experimental_rerun()
177
+
178
+
179
+
pages/6_finalpage.py ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import streamlit.components.v1 as components
3
+ from streamlit_extras.switch_page_button import switch_page
4
+ from oocsi_source import OOCSI
5
+
6
+ header1, header2, header3 = st.columns([1,4,1])
7
+ image1, image2, image3 = st.columns([1,50,1])
8
+ body1, body2, body3 =st.columns([1,2,1])
9
+
10
+
11
+ with header2:
12
+ st.title("Comparing the different methods")
13
+ st.markdown("This is the final section of this experiment, please rate and compare the different methods")
14
+
15
+ with image2:
16
+ st.image('assets/images/overview methods.png')
17
+
18
+ with body2:
19
+ with st.form("my_form"):
20
+ st.write("As a final evaluation, please rate the different types of explanations (0-10). This is a general grade that you you would give to the different explanation methods.")
21
+
22
+
23
+ shap = st.slider('SHAP', 0, 10)
24
+ dt = st.slider('Decision tree', 0, 10)
25
+ counterfactual = st.slider("Counterfactual", 0, 10)
26
+ visualmap = st.slider("Visual map", 0, 10)
27
+ favourite = st.radio("What was your favourite type of epxlanation?", ('SHAP', 'Decision tree', 'Counterfactual', 'Visual map'))
28
+ why = st.text_area('Please explain why', "")
29
+ # Every form must have a submit button.
30
+
31
+ submitted = st.form_submit_button("Submit")
32
+ if submitted:
33
+ st.session_state.oocsi.send('EngD_HAII_comparison', {
34
+ 'participant_ID': st.session_state.participantID,
35
+ 'shap': shap,
36
+ 'decisiontree': dt,
37
+ 'counterfactual': counterfactual,
38
+ 'visualmap': visualmap,
39
+ 'favourite': favourite,
40
+ 'why': why
41
+ })
42
+ st.balloons()
43
+ switch_page('thankyou')
44
+ # Execute your app
45
+ # embed streamlit docs in a streamlit app
46
+
47
+
pages/7_thankyou.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import streamlit.components.v1 as components
3
+ from streamlit_extras.switch_page_button import switch_page
4
+ from oocsi_source import OOCSI
5
+
6
+ header1, header2, header3 = st.columns([1,2,1])
7
+ body1, body2, body3 =st.columns([1,2,1])
8
+
9
+
10
+ with header2:
11
+ st.balloons()
12
+ st.title("Thank you for completing this survey")
13
+ st.write("You can now close this tab")