The Dot-Spot task for experiment
This page briefly describes the Dot-Spot task used in Asset Price Dynamics and Endogenous Trader Overconfidence (2019) by Steffen Ahrens, Ciril Bosch-Rosa, and Rasmus Pank Roulund, and how to use the code. We also provide a simple otree example and the full otree source code to our experiment.
Dot-Spot example (see also the otree demo)
In our experiment, we show participants Dot-Spot matrices, each for six seconds, and then ask them to answer the following questions,
- Please give us your best estimate for the number of red dots.
- How far away do you think your estimate is from the true answer?
Click here to reveal correct number dots
This example has red dots and blue dots.
Overview of code to generate Dot-Spots
We use something like the following d3.v3.js
javascript function
to display Dot-Spot tasks in the browser (e.g. for experiments using otree).
var add_dotspot = function(_data, _anchor = "dotspot-div"){ var radius = 3.5; // dots size var stroke_width = .5; // stroke on dots var size = 500; // canvas size var margin = 20; // canvas margin var chart = d3.select('#' + _anchor) .classed("svg-container", true) .append('svg') .attr("id", "dotspot") .attr('width', size + margin) .attr('height', size + margin) .attr("preserveAspectRatio", "xMinYMin meet") .attr("viewBox", [0, 0, size, size].join(" ")) .attr("style", ("border: 1px solid black;" + "background-color: white;")); var x = d3.scale.linear() .domain([d3.min(_data.map(d => d.x)), d3.max(_data.map(d => d.x))]) .range([ margin, size - margin]); var y = d3.scale.linear() .domain([d3.min(_data.map(d => d.y)), d3.max(_data.map(d => d.y))]) .range([ size - margin, margin]); var points_layer = chart.append("g"); points_layer.selectAll(".dot") .data(_data) .enter().append("circle") .attr("class", "dot") .attr("r", radius) .attr("cx", d => x(d.x)) .attr("cy", d => y(d.y)) .style("fill", d => d.color) .style("stroke-width", String(stroke_width)) .style("stroke", d => d3.rgb(d.color ).darker(1.3)) }
It takes two arguments, _data
and _anchor
. _data
is a list of objects
with keys x
, y
, and color
, e.g. something like this,
_data = [{"x": 0, "y": 0, "color": "blue"}, ..., {"x": 20, "y": 20, "color": "red"}]
_anchor
is a html id that the Dot-Spot canvas is written in.
Data can be generated in a number of ways.
Here is a the javascript code used on this page:
var generate_dotspot_data = function(dots=20, number_of_reds=200, epsilon=5) { var eps = d3.shuffle(d3.range(-epsilon, epsilon)).pop(); var r = d3.range(number_of_reds + eps).map(x => "red"); var b = d3.range(dots*dots - r.length).map(x => "blue"); var colors = d3.shuffle([].concat(r, b)); return ([].concat(...d3.range(dots).map( x => d3.range(dots).map( y => ({"x": x, "y": y, "color": colors.pop()}))))); }
Here is a Python example similar to the one we used in our otree program:
def generate_dotspot_data(dots=20, number_of_reds=None, epsilon = None): """Generate dotspot dataset. Parameters ---------- dots: number of dots per axis. Total number of dots is dots*dots number_of_reds: number of red dots in data epsilon: if not None, an integer between [-epsilon;epsilon] is added to number_of_reds Returns ------- List of dictonaries with the keys x, y and color. """ import random from itertools import product total = dots*dots reds = total // 2 if number_of_reds is None else number_of_reds eps = random.randint(-epsilon, epsilon) if epsilon else 0 reds += eps colors = ["red"]*reds + ["blue"]*(total - reds) random.shuffle(colors) base = product(range(dots), range(dots)) return [{"x": x, "y": y, "color": col} for (x, y), col in zip(base, colors)]
Simple otree Dot-Spot example
The source code to a simplified otree is provided here. You can also try the demo.
Full otree code for our experiment
I will provide the entire otree code used in our paper in due course (after a final review of code clarity, comments, etc.).