Commit 3940ede0 authored by Ossi Laine's avatar Ossi Laine
Browse files

Merge branch 'bug-handle-randomization-when-exporting-results' into 'dev'

Bug handle randomization when exporting results

See merge request tithei/pet-rating!3
parents bcb340f1 45404c92
......@@ -921,7 +921,9 @@ def statistics():
slider_answers = {}
for participant in participants:
if participant.answer_counter > 0:
answers = answer.query.filter_by(answer_set_idanswer_set=participant.idanswer_set).all()
answers = answer.query.filter_by(answer_set_idanswer_set=participant.idanswer_set)\
.order_by(answer.page_idpage)\
.all()
slider_answers[participant.session] = [ a.answer for a in answers]
slider_answers['mean'] = get_mean_from_slider_answers(slider_answers)
......
from sqlalchemy import and_
from flask import session
from app import db
from sqlalchemy import Column, Integer, String, Text, Boolean
from flask_wtf import FlaskForm
from wtforms_sqlalchemy.fields import QuerySelectField, QuerySelectMultipleField
from wtforms_sqlalchemy.fields import QuerySelectField, QuerySelectMultipleField
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import UserMixin
from app import login
......@@ -15,9 +17,10 @@ class background_question(db.Model):
__tablename__ = "background_question"
idbackground_question = db.Column(db.Integer, primary_key=True)
background_question = db.Column(db.String(120))
answers = db.relationship('background_question_answer', backref='question', lazy='dynamic')
answers = db.relationship(
'background_question_answer', backref='question', lazy='dynamic')
experiment_idexperiment = db.Column(db.Integer)
def __repr__(self):
return "<idbackground_question = '%s', background_question = '%s'>" % (self.idbackground_question, self.background_question)
......@@ -25,11 +28,12 @@ class background_question(db.Model):
class background_question_option(db.Model):
__tablename__ = "background_question_option"
idbackground_question_option = db.Column(db.Integer, primary_key=True)
background_question_idbackground_question = db.Column(db.Integer, db.ForeignKey('background_question.idbackground_question'))
background_question_idbackground_question = db.Column(
db.Integer, db.ForeignKey('background_question.idbackground_question'))
option = db.Column(db.String(120))
def __repr__(self):
return "<idbackground_question_option = '%s', background_question_idbackground_question = '%s', option = '%s'>" % (self.idbackground_question_option, self.background_question_idbackground_question, self.option)
return "<idbackground_question_option = '%s', background_question_idbackground_question = '%s', option = '%s'>" % (self.idbackground_question_option, self.background_question_idbackground_question, self.option)
class experiment (db.Model):
......@@ -51,7 +55,7 @@ class experiment (db.Model):
consent_text = db.Column(db.Text, index=True)
use_forced_id = db.Column(db.String(120))
embody_enabled = db.Column(db.Boolean, unique=False, default=False)
def __repr__(self):
return "<idexperiment = '%s', name='%s', instruction='%s', directoryname='%s', language='%s', status='%s', randomization='%s', short_instruction='%s', single_sentence_instruction='%s', is_archived='%s', creator_name='%s', research_notification_filename='%s', creation_time='%s', stimulus_size='%s', consent_text='%s', use_forced_id='%s', embody_enabled='%s'>" % (self.idexperiment, self.name, self.instruction, self.directoryname, self.language, self.status, self.randomization, self.short_instruction, self.single_sentence_instruction, self.is_archived, self.creator_name, self.research_notification_filename, self.creation_time, self.stimulus_size, self.consent_text, self.use_forced_id, self.embody_enabled)
......@@ -59,13 +63,16 @@ class experiment (db.Model):
class answer_set (db.Model):
__tablename__ = "answer_set"
idanswer_set = db.Column(db.Integer, primary_key=True)
experiment_idexperiment = db.Column(db.Integer, db.ForeignKey('experiment.idexperiment'))
experiment_idexperiment = db.Column(
db.Integer, db.ForeignKey('experiment.idexperiment'))
session = db.Column(db.String(120))
agreement = db.Column(db.String(120))
answer_counter = db.Column(db.Integer)
answer_type = db.Column(db.String(120))
registration_time = db.Column(db.DateTime, index=True, default=datetime.utcnow)
last_answer_time = db.Column(db.DateTime, index=True, default=datetime.utcnow)
registration_time = db.Column(
db.DateTime, index=True, default=datetime.utcnow)
last_answer_time = db.Column(
db.DateTime, index=True, default=datetime.utcnow)
def __repr__(self):
return "<idanswer_set = '%s', experiment_idexperiment = '%s', session = '%s', agreement = '%s', answer_counter = '%s', registration_time = '%s', last_answer_time = '%s'>" % (self.idanswer_set, self.experiment_idexperiment, self.session, self.agreement, self.answer_counter, self.registration_time, self.last_answer_time)
......@@ -74,17 +81,20 @@ class answer_set (db.Model):
class background_question_answer(db.Model):
__tablename__ = "background_question_answer"
idbackground_question_answer = db.Column(db.Integer, primary_key=True)
answer_set_idanswer_set = db.Column(db.Integer, db.ForeignKey('answer_set.idanswer_set'))
answer_set_idanswer_set = db.Column(
db.Integer, db.ForeignKey('answer_set.idanswer_set'))
answer = db.Column(db.String(120))
background_question_idbackground_question = db.Column(db.Integer, db.ForeignKey('background_question.idbackground_question'))
background_question_idbackground_question = db.Column(
db.Integer, db.ForeignKey('background_question.idbackground_question'))
def __repr__(self):
return "<idbackground_question_answer = '%s', answer_set_idanswer_set = '%s', answer = '%s', background_question_idbackground_question = '%s'>" % (self.idbackground_question_answer, self.answer_set_idanswer_set, self.answer, self.background_question_idbackground_question)
return "<idbackground_question_answer = '%s', answer_set_idanswer_set = '%s', answer = '%s', background_question_idbackground_question = '%s'>" % (self.idbackground_question_answer, self.answer_set_idanswer_set, self.answer, self.background_question_idbackground_question)
def background_question_answer_query():
return background_question_answer.query
"""
class ChoiceForm(FlaskForm):
opts = QuerySelectField(query_factory=background_question_answer_query, allow_blank=True)
......@@ -98,30 +108,33 @@ vastaukset = u.answers.all()
class question (db.Model):
__tablename__ = "question"
idquestion = db.Column(db.Integer, primary_key=True)
experiment_idexperiment = db.Column(db.Integer, db.ForeignKey('experiment.idexperiment'))
experiment_idexperiment = db.Column(
db.Integer, db.ForeignKey('experiment.idexperiment'))
question = db.Column(db.String(120))
left = db.Column(db.String(120))
right = db.Column(db.String(120))
def __repr__(self):
return "<idquestion = '%s', experiment_idexperiment = '%s', question = '%s', left = '%s', right = '%s'>" % (self.idquestion, self.experiment_idexperiment, self.question, self.left, self.right)
return "<idquestion = '%s', experiment_idexperiment = '%s', question = '%s', left = '%s', right = '%s'>" % (self.idquestion, self.experiment_idexperiment, self.question, self.left, self.right)
class embody_question (db.Model):
__tablename__ = "embody_question"
idembody = db.Column(db.Integer, primary_key=True)
experiment_idexperiment = db.Column(db.Integer, db.ForeignKey('experiment.idexperiment'))
experiment_idexperiment = db.Column(
db.Integer, db.ForeignKey('experiment.idexperiment'))
picture = db.Column(db.Text)
question = db.Column(db.Text)
def __repr__(self):
return "<idembody = '%s', experiment_idexperiment = '%s', picture = '%s', question = '%s'>" % (self.idembody, self.experiment_idexperiment, self.picture, self.question )
return "<idembody = '%s', experiment_idexperiment = '%s', picture = '%s', question = '%s'>" % (self.idembody, self.experiment_idexperiment, self.picture, self.question)
class page (db.Model):
__tablename__ = "page"
idpage = db.Column(db.Integer, primary_key=True)
experiment_idexperiment = db.Column(db.Integer, db.ForeignKey('experiment.idexperiment'))
experiment_idexperiment = db.Column(
db.Integer, db.ForeignKey('experiment.idexperiment'))
type = db.Column(db.String(120), index=True)
text = db.Column(db.Text)
media = db.Column(db.String(120), index=True)
......@@ -133,8 +146,10 @@ class page (db.Model):
class answer (db.Model):
__tablename__ = "answer"
idanswer = db.Column(db.Integer, primary_key=True)
question_idquestion = db.Column(db.Integer, db.ForeignKey('question.idquestion'))
answer_set_idanswer_set = db.Column(db.Integer, db.ForeignKey('answer_set.idanswer_set'))
question_idquestion = db.Column(
db.Integer, db.ForeignKey('question.idquestion'))
answer_set_idanswer_set = db.Column(
db.Integer, db.ForeignKey('answer_set.idanswer_set'))
answer = db.Column(db.String(120))
page_idpage = db.Column(db.Integer, db.ForeignKey('page.idpage'))
......@@ -145,9 +160,11 @@ class answer (db.Model):
class embody_answer (db.Model):
__tablename__ = "embody_answer"
idanswer = db.Column(db.Integer, primary_key=True)
answer_set_idanswer_set = db.Column(db.Integer, db.ForeignKey('answer_set.idanswer_set'))
answer_set_idanswer_set = db.Column(
db.Integer, db.ForeignKey('answer_set.idanswer_set'))
page_idpage = db.Column(db.Integer, db.ForeignKey('page.idpage'))
embody_question_idembody = db.Column(db.Integer, db.ForeignKey('embody_question.idembody'))
embody_question_idembody = db.Column(
db.Integer, db.ForeignKey('embody_question.idembody'))
coordinates = db.Column(db.Text)
def __repr__(self):
......@@ -161,17 +178,24 @@ class trial_randomization (db.Model):
randomized_idpage = db.Column(db.Integer)
answer_set_idanswer_set = db.Column(db.Integer)
experiment_idexperiment = db.Column(db.Integer)
def __repr__(self):
return "<idtrial_randomization = '%s', page_idpage = '%s', randomized_idpage = '%s', answer_set_idanswer_set = '%s', experiment_idexperiment = '%s'>" % (self.idtrial_randomization, self.page_idpage, self.randomized_idpage, self.answer_set_idanswer_set, self.experiment_idexperiment)
@classmethod
def get_randomized_page(cls, page_id):
return cls.query.filter(and_(
cls.answer_set_idanswer_set == session['answer_set'],
cls.page_idpage == page_id)).first()
class forced_id (db.Model):
__tablename__ = "forced_id"
idforced_id = db.Column(db.Integer, primary_key=True)
experiment_idexperiment = db.Column(db.Integer, db.ForeignKey('experiment.idexperiment'))
pregenerated_id = db.Column(db.String(120))
experiment_idexperiment = db.Column(
db.Integer, db.ForeignKey('experiment.idexperiment'))
pregenerated_id = db.Column(db.String(120))
def __repr__(self):
return "<idforced_id = '%s', experiment_idexperiment = '%s', pregenerated_id = '%s'>" % (self.idforced_id, self.experiment_idexperiment, self.pregenerated_id)
......@@ -184,16 +208,15 @@ class user(UserMixin, db.Model):
password_hash = db.Column(db.String(128))
def __repr__(self):
return '<user {}>'.format(self.username)
return '<user {}>'.format(self.username)
def set_password(self, password):
self.password_hash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
@login.user_loader
def load_user(id):
return user.query.get(int(id))
\ No newline at end of file
This diff is collapsed.
......@@ -48,6 +48,11 @@ $(document).ready(function()  {
//
var pageId = this.dataset.value.split('-')[0]
var embodyId = this.dataset.value.split('-')[1]
console.log(pageId)
console.log(embodyId)
socket.emit('draw', {page:pageId, embody:embodyId})
progressBarContainer.removeClass("hidden")
......
......@@ -37,10 +37,7 @@ task_blueprint = Blueprint("task", __name__,
def get_randomized_page(page_id):
"""if trial randomization is on we will still use the same functionality that is used otherwise
but we will pass the randomized pair of the page_id from trial randomization table to the task.html"""
return trial_randomization.query.filter(and_(
trial_randomization.answer_set_idanswer_set==session['answer_set'],
trial_randomization.page_idpage==page_id
)).first()
return trial_randomization.get_randomized_page(page_id)
def add_slider_answer(key, value, page_id=None):
......@@ -266,7 +263,6 @@ def task(page_num):
@task_blueprint.route('/completed')
def completed():
session.pop('user', None)
session.pop('exp_id', None)
session.pop('agree', None)
......
import os
import tempfile
from itertools import zip_longest
from flask import send_file
def map_values_to_int(values: dict):
......@@ -15,3 +18,19 @@ def calculate_mean(values: list) -> float:
def get_mean_from_slider_answers(answers):
return [calculate_mean(values) for values in map_values_to_int(answers)]
def saved_data_as_file(filename, data):
"""write CSV data to temporary file on host and send that file
to requestor"""
try:
fd, path = tempfile.mkstemp()
with os.fdopen(fd, 'w') as tmp:
tmp.write(data)
tmp.flush()
return send_file(path,
mimetype='text/csv',
as_attachment=True,
attachment_filename=filename)
finally:
os.remove(path)
......@@ -119,13 +119,11 @@ def timeit(method):
return timed
import sys
@timeit
def get_coordinates(idpage, idembody=None, select_clause=SELECT_BY_PAGE_AND_PICTURE):
"""Select all drawn points from certain stimulus and plot them onto
the human body"""
db = MyDB()
db.query(select_clause, (idpage,idembody))
......@@ -138,13 +136,11 @@ def get_coordinates(idpage, idembody=None, select_clause=SELECT_BY_PAGE_AND_PICT
image_path = db._db_cur.fetchone()[0]
image_path = './app' + image_path
# Draw image
plt = plot_coordinates(coordinates, image_path)
else:
plt = plot_coordinates(coordinates, DEFAULT_IMAGE_PATH)
# Save image to ./app/static/
img_filename = 'PAGE-' + str(idpage) + '-' + DATE_STRING + '.png'
plt.savefig(STATIC_PATH + img_filename)
......
'''
Script for testing embody drawing results from onni.utu.fi
Install requirements:
pip install numpy
pip install matplotlib
Usage:
Export data from onni.utu.fi and after that run the script in the same folder
by passing exported_file as a parameter to the script
$ python plot_image.py <exported_file>.csv
Program prints header of the file, from which you must select column where the
image data is. After you have selected the right column, program prints the
drawing results from embody answers.
If you want the program to draw default embody image to the background, then
you must put a copy of the 'dummy_6000.png' -file (this is the same that is used
in onni.utu.fu) to the same path as the script.
'''
import copy
import numpy as np
import matplotlib.pyplot as plt
import csv
import sys
import json
csv.field_size_limit(sys.maxsize)
def show_images(images, cols=1, titles=None):
"""Display a list of images in a single figure with matplotlib.
Parameters
---------
images: List of np.arrays compatible with plt.imshow.
cols (Default = 1): Number of columns in figure (number of rows is
set to np.ceil(n_images/float(cols))).
titles: List of titles corresponding to each image. Must have
the same length as titles.
"""
# default embody image for the background
try:
background = True
default_img = plt.imread("./dummy_600.png")
except FileNotFoundError:
background = False
# get a copy of the gray color map
my_cmap = copy.copy(plt.cm.get_cmap('gray'))
# set how the colormap handles 'bad' values
my_cmap.set_bad(alpha=0)
assert((titles is None) or (len(images) == len(titles)))
n_images = len(images)
if titles is None:
titles = ['Image (%d)' % i for i in range(1, n_images + 1)]
fig = plt.figure()
for n, (image, title) in enumerate(zip(images, titles)):
a = fig.add_subplot(cols, np.ceil(n_images/float(cols)), n + 1)
# draw points from users answers
plt.imshow(image, cmap=my_cmap)
# draw default background image with transparency on top of the points
if background:
plt.imshow(default_img, extent=[0, 200, 600, 0], alpha=0.33)
a.set_title(title)
fig.set_size_inches(np.array(fig.get_size_inches()) * n_images)
plt.show()
if __name__ == '__main__':
images = []
titles = []
# filename = 'experiment_1_2020-05-20.csv'
filename = sys.argv[1]
with open(filename, 'r+') as csvfile:
for row_no, row in enumerate(csv.reader(csvfile, delimiter=';')):
# parse header
if row_no == 0:
for column, title in enumerate(row):
print("Column (no. {}): {}".format(column, title))
print('Enter the column number which has image data:')
x = int(input())
continue
try:
np_array = np.array(eval(row[x]))
except NameError:
print(
"Column didn't contain image data. Try again with different column number.")
np_array = np.transpose(np_array)
images.append(np_array)
# add id of the answerer to the image
titles.append(row[0])
show_images(images, titles=titles)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment