from otree.api import * doc = """ Your app description """ class C(BaseConstants): NAME_IN_URL = 'emAndRel' PLAYERS_PER_GROUP = None NUM_ROUNDS = 1 DURATION_PICTURES = 10 #Needed to show the choices in random order (depending on a participants player number) CHOICES_TOPIC = ['Environment','Race Relations','Guns and Firearms','Immigration','Environment','Race Relations','Guns and Firearms','Immigration'] CHEAP_TICKET_PRICE = 0.02 ENDOWMENT_PURCHASE = 2 class Subsession(BaseSubsession): pass class Group(BaseGroup): pass class Player(BasePlayer): #treatment factors inducedEmotion = models.IntegerField() consequentialRelevance = models.IntegerField() agentialRelevance = models.IntegerField() myTicketPrice = models.FloatField() myTopic = models.StringField() myPreferredOrganization = models.StringField() myPreferredOrganizationOption1 = models.StringField() myPreferredOrganizationOption2 = models.StringField() myPreferredOrganizationOption3 = models.StringField() purchasedTickets = models.IntegerField(choices=[[0, '0'], [1, '1'], [2, '2'], [3, '3'], [4, '4'], [5, '5'], [6, '6'], [7, '7'], [8, '8'], [9, '9'], [10, '10']]) controlQuestionPurchase = models.IntegerField() controlQuestionPurchaseNrTickets = models.IntegerField() myOrganizationIdeology = models.FloatField() checksliderMyOrganizationIdeology = models.FloatField(initial=-1, blank=True) checkTotalPurchase = models.StringField() finalControl = models.StringField() topicRelevance1 = models.StringField() topicRelevance2 = models.StringField() topicRelevance3 = models.StringField() topicRelevance4 = models.StringField() truthfully = models.IntegerField(choices=[[0, 'No'], [1, 'Yes'], [-1, 'Maybe']]) #demographics and controls gender = models.IntegerField(choices=[[-1, 'none of the above'], [1, 'Man'], [0, 'Woman']]) age = models.IntegerField(min=12, max=100) education = models.IntegerField(choices=[[0, 'less than high school degree'], [1, 'high school degree or equivalent'], [2, 'some college'], [3, '2-year college degree'], [4, 'bachelor/4-year college degree'],[5,'some graduate school'], [6, 'graduate degree (e.g. JD/MD/MA/PhD))']]) income = models.IntegerField(choices=[[0, 'Less than $10,000'], [1, '$10,000 to $19,999'], [2, '$20,000 to $29,999'], [3, '$30,000 to $39,999'], [4, '$40,000 to $49,999'], [5, '5$0,000 to $59,999'], [6, '$60,000 to $69,999'], [7, '$70,000 to $79,999'], [8, '$80,000 to $89,999'], [9, '$90,000 to $99,999'], [10, '$100,000 to $109,999'], [11, '$110,000 to $119,999'], [12, '$120,000 to $129,999'], [13, '$130,000 to $139,999'], [14, '$140,000 to $149,999'], [15, 'More than $150,000']]) #race (needs to be implemented as bools per value because multiple options may apply for the same person) white = models.BooleanField(blank=True) black = models.BooleanField(blank=True) hispanic = models.BooleanField(blank=True) asian = models.BooleanField(blank=True) native = models.BooleanField(blank=True) otherRace = models.BooleanField(blank=True) ideology = models.FloatField() checksliderIdeology = models.FloatField(initial=-1, blank=True) partisanship = models.FloatField() checksliderPartisanship = models.FloatField(initial=-1, blank=True) #for the randomization of order in which pictures are shown orderPicture1 = models.IntegerField() orderPicture2 = models.IntegerField() orderPicture3 = models.IntegerField() orderPicture4 = models.IntegerField() orderPicture5 = models.IntegerField() #answer to control question regarding which pictures were seen controlQuestion = models.StringField() #emotions (note, because of randomization of the order in which we ask for emotions, we have both, # the number of an emotion, which differs per participant, and the emotion itself) upset = models.FloatField() angry = models.FloatField() anxious = models.FloatField() afraid = models.FloatField() disgusted = models.FloatField() happy = models.FloatField() peaceful = models.FloatField() content = models.FloatField() delighted = models.FloatField() enthusiastic = models.FloatField() upsetOrder = models.IntegerField() angryOrder = models.IntegerField() anxiousOrder = models.IntegerField() afraidOrder = models.IntegerField() disgustedOrder = models.IntegerField() happyOrder = models.IntegerField() peacefulOrder = models.IntegerField() contentOrder = models.IntegerField() delightedOrder = models.IntegerField() enthusiasticOrder = models.IntegerField() emotion1 = models.FloatField() emotion2 = models.FloatField() emotion3 = models.FloatField() emotion4 = models.FloatField() emotion5 = models.FloatField() emotion6 = models.FloatField() emotion7 = models.FloatField() emotion8 = models.FloatField() emotion9 = models.FloatField() emotion10 = models.FloatField() checksliderEmotion1 = models.FloatField(initial=-1, blank=True) checksliderEmotion2 = models.FloatField(initial=-1, blank=True) checksliderEmotion3 = models.FloatField(initial=-1, blank=True) checksliderEmotion4 = models.FloatField(initial=-1, blank=True) checksliderEmotion5 = models.FloatField(initial=-1, blank=True) checksliderEmotion6 = models.FloatField(initial=-1, blank=True) checksliderEmotion7 = models.FloatField(initial=-1, blank=True) checksliderEmotion8 = models.FloatField(initial=-1, blank=True) checksliderEmotion9 = models.FloatField(initial=-1, blank=True) checksliderEmotion10 = models.FloatField(initial=-1, blank=True) feelingRightNow = models.StringField() bonus = models.FloatField(initial=0) comments = models.StringField(blank = True) email = models.StringField(blank = True) #randomization of answer categories per participant def topicRelevance1_choices(player): choices = C.CHOICES_TOPIC[player.id_in_group%4:player.id_in_group%4+4] return choices def topicRelevance2_choices(player): choices = C.CHOICES_TOPIC[player.id_in_group%4:player.id_in_group%4+4] return choices def topicRelevance3_choices(player): choices = C.CHOICES_TOPIC[player.id_in_group%4:player.id_in_group%4+4] return choices def topicRelevance4_choices(player): choices = C.CHOICES_TOPIC[player.id_in_group%4:player.id_in_group%4+4] return choices def controlQuestion_choices(player): options = ["Dog","Birds","Fire","Money"] if(player.inducedEmotion == 1): #enthusiasm condtion options = ["Puppy","Cat","Baby","Money"] return options def myPreferredOrganization_choices(player): options = [player.myPreferredOrganizationOption1,player.myPreferredOrganizationOption2,player.myPreferredOrganizationOption3] return options def controlQuestionPurchase_choices(player): import random potentialPurchases = random.sample(range(0, 10), 4) if player.controlQuestionPurchaseNrTickets in potentialPurchases: potentialPurchases.remove(player.controlQuestionPurchaseNrTickets) options = [[1,"$" + "{:.2f}".format(C.ENDOWMENT_PURCHASE - potentialPurchases[0] * player.myTicketPrice)], [2,"$" + "{:.2f}".format(C.ENDOWMENT_PURCHASE - player.controlQuestionPurchaseNrTickets * player.myTicketPrice)], [3,"$" + "{:.2f}".format(C.ENDOWMENT_PURCHASE - potentialPurchases[1] * player.myTicketPrice)], [4,"$" + "{:.2f}".format(C.ENDOWMENT_PURCHASE - potentialPurchases[2] * player.myTicketPrice)]] return options ########################################## PAGES ########################################## class welcome(Page): @staticmethod def before_next_page(player, timeout_happened): import random # assignign treatment factors player.inducedEmotion = random.randint(0,1) #0 = anxiety ; 1 = enthusiasm player.consequentialRelevance = random.randint(0,1) # 0 = low, 1 = high player.agentialRelevance = random.randint(0,1) #player.agentialRelevance = 1 if player.consequentialRelevance == 0 else 0 # 0 = low, 1 = high #!!!!! Because of mistake 160 needed with change below. After, switch back if(player.consequentialRelevance == 0): player.myTicketPrice=C.CHEAP_TICKET_PRICE if(player.consequentialRelevance == 1): player.myTicketPrice = C.CHEAP_TICKET_PRICE * 10 #here we randomize the order in which pictures are shown orderPictures = list(range(1,6)) random.shuffle(orderPictures) player.orderPicture1 = orderPictures[0] player.orderPicture2 = orderPictures[1] player.orderPicture3 = orderPictures[2] player.orderPicture4 = orderPictures[3] player.orderPicture5 = orderPictures[4] #here we randomize the order in which we ask for emotions of participants orderEmotions = list(range(1,11)) random.shuffle(orderEmotions) player.upsetOrder = orderEmotions[0] player.angryOrder = orderEmotions[1] player.anxiousOrder = orderEmotions[2] player.afraidOrder = orderEmotions[3] player.disgustedOrder = orderEmotions[4] player.happyOrder = orderEmotions[5] player.peacefulOrder = orderEmotions[6] player.contentOrder = orderEmotions[7] player.delightedOrder = orderEmotions[8] player.enthusiasticOrder = orderEmotions[9] #randomly determining how many tickets are bought in the control question player.controlQuestionPurchaseNrTickets = random.randint(0,10) class respondTruthfully(Page): form_model = 'player' form_fields = ['truthfully'] class preQuestion(Page): form_model = 'player' form_fields = ['education', 'gender', 'age','income', 'white', 'black', 'hispanic', 'asian', 'native', 'otherRace', 'partisanship', 'checksliderPartisanship', 'ideology', 'checksliderIdeology'] @staticmethod def error_message(player, values): if player.checksliderPartisanship < 0: return 'It seems you did not move the slider under question 7, which is needed to continue. If your response for that question is supposed to be in the center, please move the slider a little and then move it back to the center, so it is clear that you actively chose the center.' if player.checksliderIdeology < 0: return 'It seems you did not move the slider under question 6, which is needed to continue. If your response for that question is supposed to be in the center, please move the slider a little and then move it back to the center, so it is clear that you actively chose the center.' @staticmethod def live_method(player, data): t = data['slider'] thisValue = float(data['v']) if t == 7: player.partisanship = thisValue player.checksliderPartisanship = thisValue if t == 6: player.ideology = thisValue player.checksliderIdeology = thisValue @staticmethod def js_vars(player): return dict( partisanship = player.field_maybe_none('partisanship'), ideology = player.field_maybe_none('ideology') ) class introPictures(Page): pass class picture1(Page): timeout_seconds = C.DURATION_PICTURES class picture2(Page): timeout_seconds = C.DURATION_PICTURES class picture3(Page): timeout_seconds = C.DURATION_PICTURES class picture4(Page): timeout_seconds = C.DURATION_PICTURES class picture5(Page): timeout_seconds = C.DURATION_PICTURES class pictureControlQuestion(Page): form_model = 'player' form_fields = ['controlQuestion'] class emotionCheck(Page): form_model = 'player' form_fields = ['emotion1','emotion2','emotion3','emotion4','emotion5', 'emotion6','emotion7','emotion8','emotion9','emotion10', 'checksliderEmotion1','checksliderEmotion2','checksliderEmotion3','checksliderEmotion4','checksliderEmotion5', 'checksliderEmotion6','checksliderEmotion7','checksliderEmotion8','checksliderEmotion9','checksliderEmotion10', 'feelingRightNow'] @staticmethod def error_message(player, values): if player.checksliderEmotion1 < 0: return 'It seems you did not move the slider under question 1, which is needed to continue. If your response for that question is supposed to be in the center, please move the slider a little and then move it back to the center, so it is clear that you actively chose the center.' if player.checksliderEmotion2 < 0: return 'It seems you did not move the slider under question 2, which is needed to continue. If your response for that question is supposed to be in the center, please move the slider a little and then move it back to the center, so it is clear that you actively chose the center.' if player.checksliderEmotion3 < 0: return 'It seems you did not move the slider under question 3, which is needed to continue. If your response for that question is supposed to be in the center, please move the slider a little and then move it back to the center, so it is clear that you actively chose the center.' if player.checksliderEmotion4 < 0: return 'It seems you did not move the slider under question 4, which is needed to continue. If your response for that question is supposed to be in the center, please move the slider a little and then move it back to the center, so it is clear that you actively chose the center.' if player.checksliderEmotion5 < 0: return 'It seems you did not move the slider under question 5, which is needed to continue. If your response for that question is supposed to be in the center, please move the slider a little and then move it back to the center, so it is clear that you actively chose the center.' if player.checksliderEmotion6 < 0: return 'It seems you did not move the slider under question 6, which is needed to continue. If your response for that question is supposed to be in the center, please move the slider a little and then move it back to the center, so it is clear that you actively chose the center.' if player.checksliderEmotion7 < 0: return 'It seems you did not move the slider under question 7, which is needed to continue. If your response for that question is supposed to be in the center, please move the slider a little and then move it back to the center, so it is clear that you actively chose the center.' if player.checksliderEmotion8 < 0: return 'It seems you did not move the slider under question 8, which is needed to continue. If your response for that question is supposed to be in the center, please move the slider a little and then move it back to the center, so it is clear that you actively chose the center.' if player.checksliderEmotion9 < 0: return 'It seems you did not move the slider under question 9, which is needed to continue. If your response for that question is supposed to be in the center, please move the slider a little and then move it back to the center, so it is clear that you actively chose the center.' if player.checksliderEmotion10 < 0: return 'It seems you did not move the slider under question 10, which is needed to continue. If your response for that question is supposed to be in the center, please move the slider a little and then move it back to the center, so it is clear that you actively chose the center.' @staticmethod def live_method(player, data): t = data['slider'] thisValue = float(data['v']) if t == 1: player.emotion1 = thisValue player.checksliderEmotion1 = thisValue if t == 2: player.emotion2 = thisValue player.checksliderEmotion2 = thisValue if t == 3: player.emotion3 = thisValue player.checksliderEmotion3 = thisValue if t == 4: player.emotion4 = thisValue player.checksliderEmotion4 = thisValue if t == 5: player.emotion5 = thisValue player.checksliderEmotion5 = thisValue if t == 6: player.emotion6 = thisValue player.checksliderEmotion6 = thisValue if t == 7: player.emotion7 = thisValue player.checksliderEmotion7 = thisValue if t == 8: player.emotion8 = thisValue player.checksliderEmotion8 = thisValue if t == 9: player.emotion9 = thisValue player.checksliderEmotion9 = thisValue if t == 10: player.emotion10 = thisValue player.checksliderEmotion10 = thisValue @staticmethod def js_vars(player): return dict( emotion1 = player.field_maybe_none('emotion1'), emotion2 = player.field_maybe_none('emotion2'), emotion3 = player.field_maybe_none('emotion3'), emotion4 = player.field_maybe_none('emotion4'), emotion5 = player.field_maybe_none('emotion5'), emotion6 = player.field_maybe_none('emotion6'), emotion7 = player.field_maybe_none('emotion7'), emotion8 = player.field_maybe_none('emotion8'), emotion9 = player.field_maybe_none('emotion9'), emotion10 = player.field_maybe_none('emotion10') ) @staticmethod def before_next_page(player, timeout_happened): #here we match the emotions that participants indicated in a random order with the values for emotions in our database enteredEmotions = [player.emotion1,player.emotion2,player.emotion3,player.emotion4,player.emotion5, player.emotion6,player.emotion7,player.emotion8,player.emotion9,player.emotion10] player.upset = enteredEmotions[player.upsetOrder - 1] player.angry = enteredEmotions[player.angryOrder - 1] player.anxious = enteredEmotions[player.anxiousOrder - 1] player.afraid = enteredEmotions[player.afraidOrder - 1] player.disgusted = enteredEmotions[player.disgustedOrder - 1] player.happy = enteredEmotions[player.happyOrder - 1] player.peaceful = enteredEmotions[player.peacefulOrder - 1] player.content = enteredEmotions[player.contentOrder - 1] player.delighted = enteredEmotions[player.delightedOrder - 1] player.enthusiastic = enteredEmotions[player.enthusiasticOrder - 1] class chooseTopicMostRelevant(Page): form_model = 'player' form_fields = ['topicRelevance1','topicRelevance2','topicRelevance3','topicRelevance4'] @staticmethod def error_message(player, values): choices = [values['topicRelevance1'], values['topicRelevance2'], values['topicRelevance3'], values['topicRelevance4']] if(len(set(choices)) != len(choices)): return 'The same topic cannot be chosen for different levels of importance. Please change such that each topic is only chosen once.' @staticmethod def before_next_page(player, timeout_happened): if(player.agentialRelevance == 0): player.myTopic = player.topicRelevance4 if(player.agentialRelevance == 1): player.myTopic = player.topicRelevance1 import random if (player.myTopic == 'Environment'): options = ["Greenpeace", "The National Wildlife Federation", "The Heartland Institute"] if (player.myTopic == 'Race Relations'): options = ["Black Lives Matter", "The National Police Accountability Project", "The American Civil Rights Institute"] if (player.myTopic == 'Guns and Firearms'): options = ["The Coalition to Stop Gun Violence", "Mayors Against Illegal Guns", "National Rifle Association"] if (player.myTopic == 'Immigration'): options = ["The Young Center for Immigrant Children's Rights", "Migration Policy Institute", "The Center for Immigration Studies"] random.shuffle(options) player.myPreferredOrganizationOption1 = options[0] player.myPreferredOrganizationOption2 = options[1] player.myPreferredOrganizationOption3 = options[2] class presentationOrganizations(Page): form_model = 'player' form_fields = ['myPreferredOrganization'] class purchaseTicketsControlQuestion(Page): form_model = 'player' form_fields = ['controlQuestionPurchase'] @staticmethod def error_message(player, values): choice = values['controlQuestionPurchase'] if(choice != 2): return 'Your answer is not correct. Your bonus would be your endowment ($' + str(C.ENDOWMENT_PURCHASE) + \ ') - the price per ticket ($' + str(player.myTicketPrice) + \ ') * the quantity purchased (in this case ' + str(player.controlQuestionPurchaseNrTickets) + '). Please try again.' class purchaseTickets(Page): form_model = 'player' form_fields = ['purchasedTickets'] class purchaseCheck(Page): form_model = 'player' form_fields = ['myOrganizationIdeology','checksliderMyOrganizationIdeology','checkTotalPurchase'] @staticmethod def error_message(player, values): if player.checksliderMyOrganizationIdeology < 0: return 'It seems you did not move the slider, which is needed to continue. If your response for that question is supposed to be in the center, please move the slider a little and then move it back to the center, so it is clear that you actively chose the center.' @staticmethod def live_method(player, data): t = data['slider'] thisValue = float(data['v']) if t == 1: player.myOrganizationIdeology = thisValue player.checksliderMyOrganizationIdeology = thisValue @staticmethod def js_vars(player): return dict( myOrganizationIdeology = player.field_maybe_none('myOrganizationIdeology'), ) def before_next_page(player, timeout_happened): player.bonus = C.ENDOWMENT_PURCHASE - player.purchasedTickets * player.myTicketPrice + (0.5 if player.controlQuestion == "Money" else 0) player.payoff = player.payoff + player.bonus class finalCheck(Page): form_model = 'player' form_fields = ['finalControl','comments','email'] @staticmethod def error_message(player, values): typedIn = values['finalControl'] if typedIn != "interest": return "You typed in the wrong word. Please correct the spelling (including capitalization) and retype the word 'interest'." class completionCode(Page): pass page_sequence = [welcome, respondTruthfully,preQuestion, chooseTopicMostRelevant, introPictures,picture1,picture2,picture3,picture4,picture5,emotionCheck,pictureControlQuestion, presentationOrganizations,purchaseTicketsControlQuestion,purchaseTickets,purchaseCheck, finalCheck,completionCode ]