Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow_repeats prevent same condition for a given worker #322

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions psiturk/default_configs/local_config_defaults.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ psiturk_keywords = stroop
organization_name = New Great University
browser_exclude_rule = MSIE, mobile, tablet
allow_repeats = false
allow_repeat_conditions = false
always_show_instructions = true

[Database Parameters]
database_url = sqlite:///participants.db
Expand Down
16 changes: 13 additions & 3 deletions psiturk/example/static/js/task.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,13 @@ var psiTurk = new PsiTurk(uniqueId, adServerLoc, mode);

var mycondition = condition; // these two variables are passed by the psiturk server process
var mycounterbalance = counterbalance; // they tell you which condition you have been assigned to
var didAlready = didAlready; // if they did the experiment already, this will be true (will be false otherwise)
var num_conds = num_conds; // this is the number of conditions specified in the config.txt file
var num_counters = num_counters; // this is the number of counterbalances specified in the config.txt file
var num_conds_completed = num_conds_completed; // if they did the experiment already, how many conditions they completed (will be 0 by default)
// they are not used in the stroop code but may be useful to you
var always_show_instructions = always_show_instructions; // if this is false, then if the participant repeats, it will skip over instructions
// always_show_instructions is used to skip over instructions if the participant repeats (below)

// All pages to be loaded
var pages = [
Expand Down Expand Up @@ -220,8 +226,12 @@ var currentview;
* Run Task
******************/
$(window).load( function(){
psiTurk.doInstructions(
instructionPages, // a list of pages you want to display in sequence
function() { currentview = new StroopExperiment(); } // what you want to do when you are done with instructions
if ( (didAlready == true) & (always_show_instructions == false) ) {
currentview = new StroopExperiment();
} else {
psiTurk.doInstructions(
instructionPages, // a list of pages you want to display in sequence
function() { currentview = new StroopExperiment(); } // what you want to do when you are done with instructions
};
);
});
7 changes: 7 additions & 0 deletions psiturk/example/templates/error.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ <h1>Sorry, there was an error</h1>
<p>Because this is a Psychology experiment, you can only complete this HIT once.</p>
<p>Please release the HIT so someone else can perform the experiment.</p>

<!-- The below error is to prevent repeat participants (if enabled) from completing any condition more than once. -->
{% elif errornum == 1021 %}

<p>Sorry, our records indicate that you have already completed (or attempted to complete) all of the possible conditions for this experiment.</p>
<p>Because this is a Psychology experiment, you can participate in each condition only once.</p>
<p>Please release the HIT so someone else can perform the experiment.</p>

{% else %}

<p>Sorry, there was an unexpected error in our processing of your HIT.</p>
Expand Down
5 changes: 5 additions & 0 deletions psiturk/example/templates/exp.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@
var counterbalance = {{ counterbalance }}; // a number indexing counterbalancing conditions
var adServerLoc = "{{ adServerLoc }}"; // the location of your ad (so you can send user back at end of experiment)
var mode = "{{ mode }}";
var didAlready = {{ didAlready }}; // this will indicate whether they did already (for repeats, to skip instructions, etc.)
var always_show_instructions = {{ always_show_instructions }}; // if this is false, then if the participant repeats, it will skip over instructions
var num_conds = {{ num_conds }}; // this is the number of conditions specified in the config.txt file
var num_counters = {{ num_counters }}; // this is the number of counterbalances specified in the config.txt file
var num_conds_completed = {{ num_conds_completed }}; // this is the number of counterbalances specified in the config.txt file
</script>

<!-- utils.js and psiturk.js provide the basic psiturk functionality -->
Expand Down
56 changes: 45 additions & 11 deletions psiturk/experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ def shutdown_session(_=None):
# Experiment counterbalancing code
# ================================

def get_random_condcount():
def get_random_condcount(condsAlreadyDone):
"""
HITs can be in one of three states:
- jobs that are finished
Expand Down Expand Up @@ -160,13 +160,22 @@ def get_random_condcount():
condcount = (participant.cond, participant.counterbalance)
if condcount in counts:
counts[condcount] += 1
mincount = min(counts.values())
minima = [hsh for hsh, count in counts.iteritems() if count == mincount]
chosen = choice(minima)
#conds += [ 0 for _ in range(1000) ]
#conds += [ 1 for _ in range(1000) ]
app.logger.info("given %(a)s chose %(b)s" % {'a': counts, 'b': chosen})

# below is to exclude the cond/counterbalance combos
# that this participant has already done
allow_repeat_conditions = CONFIG.getboolean('HIT Configuration', 'allow_repeat_conditions')
if not allow_repeat_conditions:
unwanted = [x for x in counts if x in condsAlreadyDone]
for unwanted_key in unwanted: del counts[unwanted_key]
if bool(counts):
mincount = min(counts.values())
minima = [hsh for hsh, count in counts.iteritems() if count == mincount]
chosen = choice(minima)
#conds += [ 0 for _ in range(1000) ]
#conds += [ 1 for _ in range(1000) ]
app.logger.info("given %(a)s chose %(b)s" % {'a': counts, 'b': chosen})
else:
# there are no more conditions for this subject to do, so raise error
raise ExperimentError('already_did_all_conds')
return chosen


Expand Down Expand Up @@ -402,16 +411,36 @@ def start_exp():
filter(Participant.workerid == worker_id).\
filter(Participant.assignmentid == assignment_id).\
all()
# added for repeats
matchesConds = Participant.query.\
filter(Participant.workerid == worker_id).\
all()
# get all the conditions they have done and submitted or completed already
condsAlreadyDone = [(record.cond, record.counterbalance) \
for record in matchesConds \
if (record.status in [COMPLETED,SUBMITTED,CREDITED,BONUSED])]
else:
matches = Participant.query.\
filter(Participant.workerid == worker_id).\
all()

# added for repeats
condsAlreadyDone = []

# record number of conditions completed (if repeats are allowed) in order to prevent
# a subject from repeating again if they have completed all possible conditions
# and also if we want to inform the participant how many they have completed)
num_conds_completed = len(condsAlreadyDone)
# this is so we can skip instructions, certain questionnaires, etc. fif we want
didAlready = 'false'
if num_conds_completed > 0:
didAlready = 'true'

numrecs = len(matches)
if numrecs == 0:
# Choose condition and counterbalance
subj_cond, subj_counter = get_random_condcount()

# (Will exclude conditions the subject has already done)
subj_cond, subj_counter = get_random_condcount(condsAlreadyDone)

worker_ip = "UNKNOWN" if not request.remote_addr else \
request.remote_addr
browser = "UNKNOWN" if not request.user_agent.browser else \
Expand Down Expand Up @@ -492,6 +521,11 @@ def start_exp():
counterbalance=part.counterbalance,
adServerLoc=ad_server_location,
mode = mode,
didAlready = didAlready,
always_show_instructions = CONFIG.get('HIT Configuration', 'always_show_instructions'),
num_conds = CONFIG.get('Task Parameters', 'num_conds'),
num_counters = CONFIG.get('Task Parameters', 'num_counters'),
num_conds_completed = num_conds_completed,
contact_address=CONFIG.get('HIT Configuration', 'contact_email_on_error')
)

Expand Down
6 changes: 6 additions & 0 deletions psiturk/experiment_errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class ExperimentError(Exception):
already_started_exp=1008,
already_started_exp_mturk=1009,
already_did_exp_hit=1010,
already_did_all_conds=1021,
tried_to_quit=1011,
intermediate_save=1012,
improper_inputs=1013,
Expand Down Expand Up @@ -87,6 +88,11 @@ class ExperimentError(Exception):
The experiment has already been completed.
""")

error_descriptions['already_did_all_conds'] = unwrap(
"""
The participant has already completed all conditions.
""")

error_descriptions['tried_to_quit'] = unwrap(
"""
The experiment was ended prematurely and something went wrong while
Expand Down
7 changes: 6 additions & 1 deletion psiturk/psiturk_js/psiturk.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,12 @@ var PsiTurk = function(uniqueId, adServerLoc, mode) {
questiondata: {},
eventdata: [],
useragent: "",
mode: ""
mode: "",
didAlready: false,
always_show_instructions: true,
num_conds: 1,
num_counters: 1,
num_conds_completed: 0
},

initialize: function() {
Expand Down