oTree Forum >

set array of images to draw from each round

#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.

Write a reply

Set forum username