Interactive and iterated experiments

Interactive experiments allow multiple participants to interact with each other, synchronously as well as asynchronously.

Creating a complex experiment

In order for interactivity to work, the magpie server needs to be aware of the rough structure of the experiment. When creating the experiment on the server, we have to select Complex experiment to indicate that there is a dependency between different realizations of the same experiment.

Complex experiments have three defining characteristics:

  • Variants
  • Chains
  • Generations
  • Collaborators

An example experiment with 2 collaborators per generation, 3 generations per chain, and 2 groups per variant and 2 variants

Collaborators

The number of collaborators indicates how many participants are in one session interacting live together. In an experiment where pairs of people should work together, there would be 2 collaborators (see schema above).

Generations

The number of generations indicates how many iterations the experiment should have. For example in an iterated narration experiment (think Game of telephone) there would be one generation for each step in the retelling of the story (possibly with multiple collaborators each).

Chains

A chain contains a line of generations. For example in an iterated narration experiment, every chain would develop their story independently.

Variants

A variant contains multiple chains and defines the independent variables for those chains. In an iterated narration experiment variants would be different initial stories, for example.

The experiment tuple

These characteristics indicate the total number of required participants, obtained by multiplying them. Each participant can thus also be assigned a unique tri-tuple, indicating their collaborator number, generation number and chain number and variant number.

Building interactive experiments

Before participants can interact with other participants in their chain, the browser needs to connect to the magpie server and wait for other participants.

This routine is conveniently encapsulated in the ConnectInteractiveScreen component, which by default displays the following text:

This screen sets up the socket connection for the interactive experiment and waits for other participants to join so that the number of required participants to start an interactive experiment is met.

You can however replace it by entering your own text inside the component:

<ConnectInteractiveScreen>
    Please wait for other participants...
</ConnectInteractiveScreen>

This screen will jump to the next screen in your experiment once a sufficient number of participants have joined the current chain.

Interactivity

Interactivity is enabled by a socket connection from each participant to the server.

Chat

To allow participants to communicate, you can add the Chat component to your screens, which uses this socket under the hood:

<Experiment>
    <ConnectInteractiveScreen />

    <Screen>
        <p>Please discuss the text you have just read.</p>
        <Chat :data.sync="$magpie.measurements.chat" />
    </Screen>

</Experiment>

Socket

In order to build more complex interactions, you can use magpie's socket directly.

This is a simplified Chat component that showcases how magpie's socket works:

<template>
  <div class="chat">
    <div ref="box" class="chat-box">
      <!-- Show all messages sent so far -->
      <p
        v-for="(message, i) in messages"
        :key="i"
      >{{ message.message }}</p>
    </div>
    <!-- Allow sending messages via Send button or via enter-->
    <div class="chat-input">
      <textarea
        ref="text"
        cols="50"
        placeholder="Type your message to the other participant here."
        @keydown.enter.prevent="send"
      ></textarea>
      <button @click.stop="send()">Send</button>
    </div>
  </div>
</template>

<script>
export default {
  name: 'Chat',
  data() {
    return {
      messages: [],
    };
  },
  socket: {
    // for each chat_message socket event (including our own) we get a callback
    // and add the message to our stack of messages
    chat_message(payload) {
      this.messages.push(payload);
    }
  },
  methods: {
    // Get message text and send a chat_message event down the socket
    send() {
      const message = this.$refs.text.value;
      this.$magpie.socket.broadcast('chat_message', {
        message,
        participantId: this.$magpie.socket.participantId,
        time: Date.now()
      });
    },
  }
};
</script>

Here, we define an array of messages in our component data. Whenever a socket event with the name chat_message arrives, we add it to the array of messages, as defined by the chat_message function in the socket option of our component.

To send our own messages, we have a send method, which takes the value of the input field and broadcasts a chat_message event to all other participants in our chain using $magpie.socket.broadcast.

The template then renders all chat messages and displays the input field for entering messages.

Active participants

If you would like to know how many participants are currently active in the current screen, you can watch $magpie.socket.active, which is an array with the IDs of all participants currently active in the current screen.

Iterated experiments

Interactive experiments do not have to be synchronous. Imagine for example an iterated narration experiment, where participants have to read and relay a story to each other successively, similar to the game of Telephone.

Waiting for the previous iteration

Similar to how we need for all participants to arrive in an interactive experiment, in an iterated experiment, we need to wait for the results of previous iteration. This routine is encapsulated in AwaitIteratedResultScreen.

<AwaitIteratedResultScreen>
    Please wait for other participants...
</AwaitIteratedResultScreen>

This screen will jump to the next screen in your experiment once the results of the previous iteration become available.

Accessing previous results

Once the AwaitIteratedResultScreen has yielded to the next screen, the results from the previous iteration are available in $magpie.socket.lastIterationResults.

The iteration number is available in $magpie.socket.generation.

Balancing randomization

Magpie's complex experiments can also be utilized to implement balanced randomization.

In this case, we use the variant to let the magpie backend sort participants into groups. chains should then be the number of participants per variant, and generations can be 1 for this experiment (unless you want to create an iterated experiment). After ConnectInteractiveScreen has yielded to the next screen, we can access the assigned variant in $magpie.socket.