def remove_slider(): """ Remove a slider from the user page. :return: Redirects to researcher.config """ check_access_right(forbidden='user', redirect_url='control.index') slider_name = request.args.get('slider_name') removed = False with open(current_app.input_fields, 'r') as f: lines = f.readlines() with open(current_app.input_fields, 'w') as f: for line in lines: if (line[-len(slider_name):] != slider_name) and ( line[-len(slider_name) - 1:] != slider_name + '\n'): f.write(line) else: removed = True if removed: flash('Slider "' + slider_name + '" has been removed.') else: flash('Slider "' + slider_name + '" does not exist. Nothing removed.') return redirect(url_for('researcher.config'))
def remove_video(): """ Remove a video from the available videos. :return: Redirects to researcher.config """ check_access_right(forbidden='user', redirect_url='control.index') vid_id = request.args.get('vid_id') vid_name = request.args.get('vid_name') removed = False with open(current_app.vid_file, 'r') as f: lines = f.readlines() with open(current_app.vid_file, 'w') as f: for line in lines: if vid_id not in line: f.write(line) else: removed = True if removed: flash('Video "' + vid_name + '" has been removed.') else: flash('Video "' + vid_name + '" not found. Nothing removed.') return redirect(url_for('researcher.config'))
def config(): """ Display the configuarion page, where the user can add or remove videos or change the database this is connected to. :return: Renders the website """ check_access_right(forbidden='user', redirect_url='control.index') vid_dict, _ = get_videos() field_list = get_input_fields() oneDsliders = [x for x in field_list if x[0] == 'slider'] twoDsliders = [x for x in field_list if x[0] == '2dslider'] with open(current_app.user_instructions_file, 'r') as f: instructions = f.read() return render_template("researcher/config.html", vid_dict=vid_dict, dbs=current_app.dbs, cur_db=current_app.config['DB'], instructions=instructions, oneDsliders=oneDsliders, twoDsliders=twoDsliders)
def add_video(): """ Add a new video to the list of available videos. :return: Redirects to researcher.config. """ check_access_right(forbidden='user', redirect_url='control.index') vid_id = request.form.get('vid_id') vid_name = request.form.get('vid_name') if (not vid_id) or (not vid_name): flash("You need to provide a video ID (or its URL) and video name in " "order to add a video") else: if not vid_id.isdigit(): # If the whole video url is given vid_id = vid_id.split('/')[-1] if not vid_id.isdigit(): flash('Error, the URL seems to have the wrong format. It ' 'should end in a number, like for example ' '"https://vimeo.com/65107797"') return (redirect(url_for('researcher.config'))) with open(current_app.vid_file, 'a') as f: f.write('\n' + vid_id + ':' + vid_name) flash('Video "' + vid_name + '" was successfully added.') return redirect(url_for('researcher.config'))
def export_all(): """ Export all the data stored in MongoDB to a file Operation is not allowed for role user. :return: """ check_access_right(forbidden='user', redirect_url='control.index') b, data = collect_mongodbobjects() if b: bytes_buffer = BytesIO() with StringIO() as str_buffer: data.to_csv(str_buffer, index=False) str_buffer.seek(0) bytes_buffer.write(str_buffer.getvalue().encode('utf-8')) bytes_buffer.seek(0) filename = 'video_annotations_{date:%Y-%m-%d_%H-%M-%S}.csv'.format( date=datetime.datetime.now()) return send_file(bytes_buffer, as_attachment=True, attachment_filename=filename, mimetype='text/csv') else: flash('No data to export!') return render_template('control/data.html', data='', headers='')
def user(): """ Display the main user page. [The videos that can be accessed have to be defined with name and vimeo ID in a dictionary here.] This is not accessible for somebody with the role researcher. :return: Main webpage """ # videos = {'Omelette':'65107797', 'Happiness':'28374299'} check_access_right(forbidden='researcher', redirect_url='control.index') currentVideo, vid_dict, _ = get_video_information( cur_vid_id=request.args.get('vid')) field_list = get_input_fields() oneDsliders = [x for x in field_list if x[0]=='slider'] twoDsliders = [x for x in field_list if x[0]=='2dslider'] if len(oneDsliders) > 2: oneDsliders = oneDsliders[:2] flash('Currently, at most two one-dimensional sliders are supported.') if len(twoDsliders) > 1: twoDsliders = twoDsliders[:1] flash('Currently, only one (or zero) two-dimensional sliders are ' 'supported.') return render_template('user/user.html', vid_dict=vid_dict, currentVideo=currentVideo, oneDsliders=oneDsliders, twoDsliders=twoDsliders)
def instructions(): """ Display the instruction page for the researcher. This is not accessible for somebody with the role user. :return: User instructions page. """ check_access_right(forbidden='user', redirect_url='user.userinstructions') return render_template('researcher/instructions.html')
def delete_all(): """ Delete all data that is stored in the MongoDB database. Operation is not allowed for role user. :return: User feedback string """ check_access_right(forbidden='user', redirect_url='control.index') current_app.d.delete_many({}) current_app.config['CACHE'] = SimpleCache(default_timeout=1e15) flash('All data deleted!') return redirect(url_for('researcher.data'))
def userinstructions(): """ Display the instruction page for the user, which looks different depending on whether the person accessing has the role user or researcher :return: User instructions webpage. """ check_access_right(forbidden='', redirect_url='control.index') with open(current_app.user_instructions_file, 'r') as f: instructions = f.read() return render_template('user/userinstructions.html', instructions=instructions)
def save_user_instructions(): """ Let's the researcher change the user instructions. :return: """ check_access_right(forbidden='user', redirect_url='control.index') instructions = request.form.get('user_instructions') with open(current_app.user_instructions_file, 'w') as f: f.write(instructions) f.close() flash('Instructions saved!') return redirect(url_for('researcher.config'))
def change_db(): """ Change the internal database in config['DB'] according to the database provided by the form. :return: Redirects to the configuration page for the researcher. """ check_access_right(forbidden='user', redirect_url='control.index') new_db = request.form.get('db') current_app.config['DB'] = new_db current_app.d = DatabaseClient() flash('Database changed to "' + current_app.dbs[new_db] + '".') current_app.config['CACHE'] = SimpleCache(default_timeout=1e15) return redirect(url_for('researcher.config'))
def add_slider(): """ Add a slider to the user page. :return: Redirects to researcher.config. """ check_access_right(forbidden='user', redirect_url='control.index') slider_type = request.form.get('slider_type') min_val = request.form.get('min') max_val = request.form.get('max') def_val = request.form.get('def') name = request.form.get('name') if (not min_val) or (not max_val) or (not def_val) or (not name): flash("You need to provide values to all fields in order to add a " "slider!") return redirect(url_for('researcher.config')) if slider_type == 'slider': with open(current_app.input_fields, 'a') as f: f.write('\n' + slider_type + ':' + min_val + ':' + max_val + ':' + def_val + ':' + name) flash('Slider "' + name + '" was successfully added.') elif slider_type == '2dslider': min_val2 = request.form.get('min2') max_val2 = request.form.get('max2') def_val2 = request.form.get('def2') name2 = request.form.get('name2') if (not min_val2) or (not max_val2) or (not def_val2) or (not name2): flash("You need to provide values to all fields in order to add a " "slider!") return redirect(url_for('researcher.config')) with open(current_app.input_fields, 'a') as f: f.write('\n' + slider_type + ':' + min_val + ':' + min_val2 + ':' + max_val + ':' + max_val2 + ':' + def_val + ':' + def_val2 + ':' + name + ':' + name2) flash('Slider "' + name + ':' + name2 + '" was successfully added.') else: flash( 'Error, slider could not be added. Try reloading the page and trying again.' ) return (redirect(url_for('researcher.config')))
def data(): """ Function to print all data that is stored in the MongoDB database. Operation is not allowed for role user. :return: Webpage displaying currently stored data """ check_access_right(forbidden='user', redirect_url='control.index') b, data = collect_mongodbobjects() if b: # The names of the data fields: headers = list(data) # And a list of their contents: data_rows = list(data.values) return render_template('researcher/data.html', data=data_rows, headers=headers) else: return render_template('researcher/data.html', data='', headers='')
def chart(): """ Display the web page for the researcher view. This webpage is only for the role researcher. :return: Researcher view webpage """ check_access_right(forbidden='user', redirect_url='control.index') # Get the data: currentVideo, vid_dict, _ = get_video_information( request.args.get('vid'), request.args.get('cluster')) _, data = collect_mongodbobjects(currentVideo[0]) if _ == False or data.empty: return render_template( "researcher/chart.html", the_div="There are no observations for this video!", the_script="", vid_dict=vid_dict, currentVideo=currentVideo, currentVariable='-', variable_list=[]) data, currentVariable, variable_list = extract_variable( data, request.args.get('variable')) # Group by username and extract timestamps and values for each user grouped_data = data.groupby('username') data_by_user = [user for _, user in grouped_data] ts = [ np.array(t) for t in (data_by_user[i]['timestamp'].apply(lambda x: float(x)) for i in range(len(data_by_user))) ] vals = [ np.array(val) for val in (data_by_user[i][currentVariable].apply(lambda x: float(x)) for i in range(len(data_by_user))) ] vals = [v for v in vals if len(v) > 1] ts = [t for t in ts if len(t) > 1] # # Make sure all data starts and ends at the same time for each user, if the # # data doesn't suggest otherwise start and end value are 50. max_ts = [max(t) for t in ts] min_ts = [min(t) for t in ts] # Create the interpolation xs = [ np.linspace(min_ts[i], max_ts[i], int(max_ts[i] - min_ts[i])) for i in range(len(max_ts)) ] interpolators = [PchipInterpolator(t, val) for (t, val) in zip(ts, vals)] user_timeseries = [[xs[i], interpolator(xs[i])] for i, interpolator in enumerate(interpolators)] # Create the Bokeh plot TOOLS = 'save,pan,box_zoom,reset,wheel_zoom,hover' p = figure(title="Valence ratings by timestamp", y_axis_type="linear", plot_height=500, tools=TOOLS, active_scroll='wheel_zoom', plot_width=900) p.xaxis.axis_label = 'Timestamp (seconds)' p.yaxis.axis_label = 'Valence rating' for i, tseries in enumerate(user_timeseries): p.line(tseries[0], tseries[1], line_color=Spectral6[i % 6], line_width=1.5, name=data_by_user[i]['username'].iloc[0]) for i in range(len(ts)): for j in range(len(ts[i])): p.circle(ts[i][j], vals[i][j], fill_color=Spectral6[i % 6], line_color='black', radius=0.5) p.select_one(HoverTool).tooltips = [('Time', '@x'), ('Valence', '@y'), ('User', '$name')] script, div = components(p) return render_template("researcher/chart.html", the_div=div, the_script=script, vid_dict=vid_dict, currentVideo=currentVideo, variable_list=variable_list, currentVariable=currentVariable)
def clusters(): """ Display correlation plot for the researcher. This webpage is only for the role researcher. :return: Correlation plot """ check_access_right(forbidden='user', redirect_url='control.index') currentVideo, vid_dict, n_clusters = get_video_information( request.args.get('vid'), request.args.get('cluster')) _, data = collect_mongodbobjects(currentVideo[0]) ### set desired amount of clusters clustervals = np.arange(1, 10, 1) if _ == False or data.empty: return render_template("researcher/clusters.html", the_div="There is no data for this video!", the_script="", vid_dict=vid_dict, currentVideo=currentVideo, currentCluster=n_clusters, clustervals=clustervals, currentVariable='-', variable_list=[]) data, currentVariable, variable_list = extract_variable( data, request.args.get('variable')) interpolators, max_t = get_interpolators(data, currentVariable) xs = np.arange(0, int(max_t) + 1.5, 1) # Generate data user_timeseries = [[interpolator(xs)] for interpolator in interpolators] seed = np.random.randint(0, int(1e5), 1)[0] np.random.seed(seed) # Set cluster count # n_clusters = 3 if n_clusters > np.array(user_timeseries).shape[0]: n_clusters = np.array(user_timeseries).shape[0] # Euclidean k-means km = TimeSeriesKMeans(n_clusters=n_clusters, verbose=True, random_state=seed) y_pred = km.fit_predict(user_timeseries) # Generate plots and calculate statistics all_plots = "" all_scripts = "" plots = [] ### TODO MAYBE: intra-cluster correlation with rpy2. Might not work with matrices """ valmatrix = np.empty([24,151]) for iii in range(24): valmatrix[iii, :] = user_timeseries[iii][0] print(type(valmatrix), valmatrix.shape) print(type(valmatrix[0]), len(valmatrix[0])) print(type(valmatrix[0][0])) r_icc = importr("ICC", lib_loc="C:/Users/Lauri Lode/Documents/R/win-library/3.4") #m = r.matrix(FloatVector(valmatrix.flatten()), nrow=24) df = DataFrame({"groups": IntVector(y_pred), "values": FloatVector(valmatrix.flatten())}) icc_res = r_icc.ICCbare("groups", "values", data=df) icc_val = icc_res[0] print("ICC" + str(icc_val))""" for yi in range(n_clusters): p = figure() n = 0 values = km.cluster_centers_[yi].ravel() centerMean = np.mean(km.cluster_centers_[yi].ravel()) varsum = 0 for xx in range(0, len(y_pred)): if y_pred[xx] == yi: n = n + 1 for iii in range(len(user_timeseries[xx][0])): varsum = varsum + eucl(user_timeseries[xx][0][iii], values[iii]) / len( user_timeseries[xx][0]) p.line(range(0, len(user_timeseries[xx][0])), user_timeseries[xx][0], line_width=0.3) varsum = np.sqrt(varsum) titleString = "C#" + str(yi + 1) + ", n: " + str(n) + ", μ: " + str( np.round(centerMean, decimals=3)) + ", σ: " + str( np.round(varsum, decimals=3)) + ", σ²: " + str( np.round(varsum**2, decimals=3)) t = Title() t.text = titleString p.title = t p.line(range(0, len(values)), values, line_width=2) plots.append(p) # Get plot codes script, div = components( gridplot(plots, ncols=3, plot_width=350, plot_height=300)) return render_template("researcher/clusters.html", the_div=div, the_script=script, vid_dict=vid_dict, currentVideo=currentVideo, currentCluster=n_clusters, clustervals=clustervals, variable_list=variable_list, currentVariable=currentVariable)