#1 by gmauter
Hello, I'm building an experiment where the subject will be shown an image each round dependent on their decision. For example, if they choose option 1, they will be shown the first image in the array. I've tried to initialize this image array in the constants class, but when i try to draw from the array in vars_for_template, i get an error saying "TypeError: 'NoneType' object is not subscriptable". Also, when I print the value of the array, it returns 'null'. I'm rather new to python, so not sure if this is a syntax error, or if I'm going about this the wrong with in regards to initializing the image array in class C and then drawing from the array in vars_for_template Here's a brief rundown of the code.. class C(BaseConstants): images = ['image1', 'image2', 'image3', 'image4'] class Player(BasePlayer): choice = models.StringField() class Choice(Page): form_model = 'player' form_fields = ['choice'] def before_next_page(player: Player, timeout_happened): player.choice = player.choice class Reveal(Page): form_model = 'player' form_fields = ['choice'] timeout_seconds = 2 @staticmethod def vars_for_template(player: Player): choice = player.choice images = C.images if player.choice = "1" return dict( image = "images/{}.png".format(C.images[0]) ) Any and all help is greatly appreciated! Thanks
#2 by BonnEconLab
Your question implies that there is a (simple) mapping from a participant’s choice to the image being displayed as feedback. More specifically, it seems that choice “1” will should lead to “image1.png” being displayed, choice “2” should lead to “image2.png” being displayed, etc. As long as this is the case, you don’t need any array to convert the input to the respective file name at all. Here is an adjusted __init__.py file: from otree.api import * doc = """ Providing feedback via an image. """ # MODELS class C(BaseConstants): NAME_IN_URL = 'zzz_feedback_via_image' PLAYERS_PER_GROUP = None NUM_ROUNDS = 4 #images = ['image1', 'image2', 'image3', 'image4'] # Unnecessary class Subsession(BaseSubsession): pass class Group(BaseGroup): pass class Player(BasePlayer): #choice = models.StringField() choice = models.StringField(choices = ["1", "2", "3", "4"]) # This restricts the choice to discrete values # PAGES class Choice(Page): form_model = 'player' form_fields = ['choice'] # Unnecessary: #def before_next_page(player: Player, timeout_happened): # player.choice = player.choice class Reveal(Page): #form_model = 'player' # Unnecessary #form_fields = ['choice'] # Unnecessary timeout_seconds = 2 @staticmethod def vars_for_template(player: Player): #choice = player.choice # Unnecessary #images = C.images # Unnecessary # This works: #if player.choice == "1": # Second = and : added # return dict( # image = "images/{}.png".format(C.images[0]) # ) # Better: return dict( image = "images/image{}.png".format(player.choice), ) page_sequence = [ Choice, Reveal, ] I’ve tested the code above: it works. I have also cleaned up your code — there were several unnecessary lines in the code that you posted.
#3 by gmauter (edited )
This is great, thank you so much for the response! I also appreciate you cleaning up the code, I'm just starting to figure out oTree but still unsure about where I need to declare variables and what not. The mapping of image to choice is actually not quite as simple as I led on. I figured I'd pose the question this way for simplicity's sake but I now realize that the task may be a bit more complicated. The images are not actually "image1", "image2", etc., but instead identified by colors. For ex: "green.png", "blue.png", etc. I realize this increases the complexity of the task. I attempted this snippet of your code: if player.choice == "1": # Second = and : added return dict( image = "images/{}.png".format(c.images[0]) ) which still returns the NoneType error I was getting. Sorry for the unclear original question, hopefully it's still possible to do given the increased complexity. Thanks again for the reply.