A customizable Ebbinghaus illusion

(0 comments)

The Ebbinghaus illusion is a famous visual effect based on the perception of the relative size. Two circles of the same size are surrounded in one case by obviously larger circles and in the other by obviously smaller circles. The former is perceived as being smaller than the latter, as illustrated below.

Ebbinghaus Illusion

The following code generates SVG images illustrating the Ebbinghaus illusion, in which several of the properties of the arrangement of circles can be customized. The customizable parameters are:

  • filename: the name of the SVG file to write.
  • width, height: the size of the SVG image in pixels.
  • r: the radius of the central circle.
  • r_smaller: the radii of the small surrounding circles.
  • r_larger: the radii of the large surrounding circles.
  • nsmall: the number of small circles.
  • nlarge: the number of large circles.
  • dist_ratio_small: the distance between the edge of the central circle and the centre of each small circle expressed as a ratio of the small circle radius (should be greater than 1 or the circles will overlap).
  • dist_ratio_large: the distance between the edge of the central circle and the centre of each large circle expressed as a ratio of the large circle radius (should be greater than 1 or the circles will overlap).
  • centre_color: a colour specification (HTML name or hex string) for the colour of the central circles.
  • surrounding_color: a colour specification (HTML name or hex string) for the colour of the surrounding circles.
  • separation: the separation of the central circles in pixels.

Default values for these parameters are provided to the ebbinghaus function.

import math

def svg_preamble(width=600, height=450):
    return ('<svg width="{}" height="{}"'
          ' xmlns="http://www.w3.org/2000/svg"'
          ' xmlns:xlink= "http://www.w3.org/1999/xlink">'.format(width,height))

def ebbinghaus(filename='ebbinghaus.svg', width=600, height=450, r=35,
                 r_smaller=15, r_larger=50, nsmall=10, nlarge=6,
                 dist_ratio_small=1.2, dist_ratio_large=1.5,
                 centre_colour='tomato', surrounding_colour='silver',
                 separation=350):
    """The Ebbinghaus illusion.

    Write an SVG image of the Ebbinghaus circles illusion with the following
    parameters:

    filename: the name of the SVG file to write.
    width, height: the size of the SVG image in pixels.
    r: the radius of the central circle.
    r_smaller: the radii of the small surrounding circles.
    r_larger: the radii of the large surrounding circles.
    nsmall: the number of small circles.
    nlarge: the number of large circles.
    dist_ratio_small: the distance between the edge of the central circle and
        the centre of each small circle expressed as a ratio of the small
        circle radius (should be greater than 1 or the circles will overlap).
    dist_ratio_large: the distance between the edge of the central circle and
        the centre of each large circle expressed as a ratio of the large
        circle radius (should be greater than 1 or the circles will overlap).
    centre_color: a colour specification (HTML name or hex string) for the
        colour of the central circles.
    surrounding_color: a colour specification (HTML name or hex string) for the
        colour of the surrounding circles.
    separation: the separation of the central circles in pixels.


    """

    # Centres of the circles surrounded by larger and smaller circles.
    x1, y1 = (r_larger + r) * 2, height/2
    x2, y2 = x1 + separation, y1

    def svg_circle(r, x0, y0, s_class):
        """A circle at (x0, y0) with radius r and class s_class."""

        return ('<circle cx="{:.1f}" cy="{:.1f}" r="{:.1f}" class="{}"/>'
                        .format(x0, y0, r, s_class))

    def arrange_circles(cr, r, x0, y0, n, s_class):
        """Arrange circles on the circumference of a larger circle.

        Arrange n circles of radius r on a circle of radius cr, centered
        at (x0, y0) and attach style class s_class to them."""

        for i in range(n):
            th = 2 * math.pi * i / n
            x = x0 + cr * math.cos(th)
            y = y0 + cr * math.sin(th)
            print(svg_circle(r, x, y, s_class), file=fo)

    with open(filename, 'w') as fo:
        print(svg_preamble(), file=fo)
        print('<style>\n    /* <![CDATA[ */', file=fo)
        print('      .inner {{fill: {};}}'.format(centre_colour), file=fo)
        print('      .smaller, .larger {{fill: {};}}'.format(
                                             surrounding_colour), file=fo)
        print('    /* ]]> */\n</style>', file=fo)

        print(svg_circle(r, x1, y1, 'inner'), file=fo)
        print(svg_circle(r, x2, y2, 'inner'), file=fo)

        arrange_circles(r + r_larger*dist_ratio_large, r_larger, x1, y1,
                        nlarge, 'larger')
        arrange_circles(r + r_smaller*dist_ratio_small, r_smaller, x2, y2,
                        nsmall,'smaller')

        print('</svg>', file=fo)

The figure above was generated with:

ebbinghaus('ebbinghaus1.svg', dist_ratio_small=1.5, dist_ratio_large=1.7,
           separation=330)

Moving the smaller circles further from the central circle they surround arguably makes the illusion less striking, an effect discussed by B. Roberts, M. G. Harris and T. A. Yates, Perception 34, 847 (2005):

ebbinghaus('ebbinghaus2.svg', dist_ratio_small=3, dist_ratio_large=1.7,
           separation=330)

Lesser-spotted Ebbinghaus Illusion

Current rating: 3.2

Comments

Comments are pre-moderated. Please be patient and your comment will appear soon.

There are currently no comments

New Comment

required

required (not published)

optional

required