File size: 9,474 Bytes
d79174d
 
 
 
1b60893
d79174d
 
 
 
1b60893
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d79174d
 
 
 
 
 
 
 
 
 
1b60893
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d79174d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1b60893
 
 
 
 
d79174d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1b60893
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d79174d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1b60893
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# General functions and routines used in the dashboard

import streamlit as st
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from PIL import Image

##### Page-unspecific functions

def assert_uploaded_frame(uploaded_df):
    # Set up variables checked for
    asserted_columns = {
      'Prompt_no':pd.api.types.is_integer_dtype,
      'Score':pd.api.types.is_bool_dtype,
      'Task':pd.api.types.is_object_dtype,
      'File_name':pd.api.types.is_object_dtype}
    asserted_column_names = ['Prompt_no','Score','Task','File_name']

    # Check whether all needed column names are present
    existing_column_names = [(x in uploaded_df.columns) for x in asserted_column_names]
    assert all(existing_column_names), "The uploaded dataframe is missing a column needed for import. Your table needs to contain the columns: 'Prompt_no', 'Score', 'Task', 'File_name' "

    # Check whether all needed columns have correct dtypes
    correct_column_dtypes = []
    for i_item in asserted_columns.items():
        dtype_test = i_item[1](uploaded_df[i_item[0]].dtype)
        correct_column_dtypes.append(dtype_test)
    assert all(correct_column_dtypes), "Incorrect dtypes in uploaded dataframe."

def assert_multi_frame_upload(list_of_uploaded_dfs):
    # Apply uploaded frame assert to list of frames
    for i_df in list_of_uploaded_dfs:
        assert_uploaded_frame(i_df)

##### Dashboard main page
def prompt_to_csv(df):
    df_download = df
    df_download['Filename']='p'+df_download['ID'].astype('str')+'_1.png'
    df_download = df[['Prompt','Filename']].drop_duplicates(subset='Filename')
    return df_download.to_csv().encode('utf-8')

##### Manual assessment

def delete_last_manual_rating():
    '''
    Routine to delete last manual rating and hence to return to it
    '''
    if len(st.session_state['manual_rating_history'])>0:

        if st.button('Return to last rated image'):
            # The list contains sublists of images rated together, here we loop over these images to reset all of them
            deleted_picture_index_list = st.session_state['manual_rating_history'].pop()
            for i_picind in deleted_picture_index_list:
                st.session_state['eval_df'].loc[
                    i_picind,'manual_eval_completed']=False
                st.session_state['eval_df'].loc[
                    i_picind,'manual_eval_task_score']=np.nan  
            st.experimental_rerun() 

def add_previous_manual_assessments():
    '''
    This is a routine to allow the user to upload prior manual ratings and override
    current ratings. This way the user can restart a manual assessment.
    '''
    # Create dict to translate uploaded score into str format used during manual assessment
    Bool_str_dict = {True:'Yes',False:'No'}

    st.subheader('Add previous assessments')
    st.write('Upload results of previous assessment (as downloaded from summary page) to add these results and skip these images in your current manual assessment. Note that you can only add results for images which you have uploaded using the same file name.')

    uploaded_ratings = st.file_uploader('Select .csv for upload', accept_multiple_files=False)
    if uploaded_ratings != None:
        try:
            uploaded_ratings_df = pd.read_csv(uploaded_ratings)
            
            # Run standard assert pipeline
            assert_uploaded_frame(uploaded_ratings_df)

            # Show matching image count and instructions
            overlapping_files_df =pd.merge(st.session_state['eval_df'],uploaded_ratings_df,on='File_name',how='inner')
            st.write('Number of matching file names found: '+ str(len(overlapping_files_df)))
            st.write('Click "Add results" button to add / override current ratings with uploaded ratings.')
        except UnicodeDecodeError:
            st.write('WARNING: The uploaded file has to be a .csv downloaded from the "Assessment summary" page.')


    submitted = st.button("Add results")
    if submitted:
        try:
            for row in uploaded_ratings_df.itertuples():
                st.session_state['eval_df'].loc[
                    st.session_state['eval_df']['File_name']==row.File_name,'manual_eval']=True
                st.session_state['eval_df'].loc[
                    st.session_state['eval_df']['File_name']==row.File_name,'manual_eval_completed']=True
                st.session_state['eval_df'].loc[
                    st.session_state['eval_df']['File_name']==row.File_name,'manual_eval_task_score']=Bool_str_dict[row.Score]

            # Reset page after ratings were submitted
            st.experimental_rerun()
        except NameError:
            st.write('You need to upload a .csv file before you can add results.')


##### Assessment summary

def print_results_tabs(file_upload, results_df):
    '''
    #Routine used to give user the choice between showing results as bar chart or table
    '''
    # Create a tab for bar chart and one for table data
    fig, table = multi_comparison_plotI(results_df=results_df, uploaded_df_list=file_upload)
    tab1, tab2 = st.tabs(["Bar chart", "Data table"])
    with tab1:
      st.pyplot(fig)

    with tab2:
        st.write(table)


def pre_assessment_visualisation(type_str):
    '''
    Routine used to allow user to visualise uploaded results before completing any assessments
    '''
    st.write('Complete {0} assessment or upload .csv with saved {0} assessment to generate summary.'.format(type_str))

    # Display file uploader
    file_upload = st.file_uploader("Upload .csv with saved {0} assessment to plot prior results.".format(type_str), accept_multiple_files=True)
    if len(file_upload) > 0:
        print_results_tabs(file_upload=file_upload, results_df=None)


def multi_comparison_plotI(results_df = None, uploaded_df_list = []):
    # If list of uploaded_dfs is provided and we transform them into pd.Dfs
    # Multiple file uploader returns empty list as default
    file_upload_names = [x.name for x in uploaded_df_list]
    plot_df_list = [pd.read_csv(x) for x in uploaded_df_list]

    # Assert that all uploaded df's have correct format
    assert_multi_frame_upload(plot_df_list)

    # Add file name as model name
    for i_df in range(len(file_upload_names)):
        plot_df_list[i_df]= plot_df_list[i_df].assign(Model=file_upload_names[i_df])

    # If results df is provided, add it to list of dfs to plot
    if type(results_df) == pd.DataFrame:
        plot_df_list.append(results_df)

    # Concat all frames to joined dataframe
    plot_df = pd.concat(plot_df_list)

    # Calculate the grouped percentage scores per task category and model
    grouped_series = plot_df.groupby(['Task','Model'])['Score'].sum()/plot_df.groupby(['Task','Model'])['Score'].count()*100
    grouped_series = grouped_series.rename('Percentage correct')

    # Create plot
    eval_share = grouped_series.reset_index()
    # Add small amount to make the bars on plot not disappear
    eval_share['Percentage correct'] = eval_share['Percentage correct']+1

    # Create plot
    fig = plt.figure(figsize=(12, 3))
    sns.barplot(data=eval_share,x='Task',y='Percentage correct',hue='Model', palette='GnBu')
    plt.xticks(rotation=-65)
    plt.xlabel(' ')
    plt.ylim(0, 100)
    return fig,grouped_series




############## Functions no longer used, to be deleted

def plot_style_simple(results_df, return_table = False):
    '''
    Simple plot function for plotting just one dataframe of results
    '''
    eval_sum = results_df.groupby('Task')['Score'].sum()
    eval_count = results_df.groupby('Task')['Score'].count()
    eval_share = (eval_sum/eval_count)*100

    if return_table:
        return_series = results_df.groupby('Task')['Score'].sum()/results_df.groupby('Task')['Score'].count()*100
        return_series = return_series.rename('Percentage correct')
        return return_series

    # Add small amount to make the bars on plot not disappear
    eval_share = eval_share+1

    fig = plt.figure(figsize=(12, 3))
    sns.barplot(x=eval_share.index, y=eval_share.values, palette='GnBu')
    plt.xticks(rotation=-65)
    plt.ylabel('Percentage correct')
    plt.xlabel(' ')
    return fig

def plot_style_combined(results_df, uploaded_df = None, return_table=False):
    '''
    Plot function which can plot to dataframe for comparison
    '''
    # Create joined dataframe of results and uploadd_df
    uploaded_results_df = uploaded_df
    manual_results_df['Model']='Current'
    uploaded_results_df['Model']='Uploaded'
    results_df = pd.concat([manual_results_df,uploaded_results_df])

    # Create scores for plot
    eval_sum = results_df.groupby(['Model','Task'])['Score'].sum()
    eval_count = results_df.groupby(['Model','Task'])['Score'].count()
    eval_share = (eval_sum/eval_count)*100
    eval_share = eval_share.reset_index()

    if return_table:
        return_series = results_df.groupby(['Task','Model'])['Score'].sum()/results_df.groupby(['Task','Model'])['Score'].count()*100
        return_series = return_series.rename('Percentage correct')
        return return_series

    # Add small amount to make the bars on plot not disappear
    eval_share['Score'] = eval_share['Score']+1

    # Create plot
    fig = plt.figure(figsize=(12, 3))
    sns.barplot(data=eval_share,x='Task',y='Score',hue='Model', palette='GnBu')
    plt.xticks(rotation=-65)
    plt.ylabel('Percentage correct')
    plt.xlabel(' ')
    return fig