Pi Monte Carlo

Estimation of π by randomly sampling points and counting how many of them fall inside or outside a unit circle. This example is based on work by Cameron Yick.

Vega JSON Specification <>

{
  "$schema": "https://vega.github.io/schema/vega/v5.json",
  "description": "Estimating the value of π via random sampling methods.",
  "autosize": "pad",
  "padding": 5,
  "height": 380,

  "data": [
    {
      "name": "random_data",
      "transform": [
        { "type": "sequence", "start": 1, "stop": 5001 },
        { "type": "formula", "as": "x", "expr": "random()" },
        { "type": "formula", "as": "y", "expr": "random()" },
        { "type": "filter", "expr": "datum.data <= num_points" }
      ]
    },
    {
      "name": "pi_estimates",
      "source": "random_data",
      "transform": [
        {
          "type": "formula", "as": "is_inside",
          "expr": "(datum.x * datum.x + datum.y * datum.y) < 1"
        },
        {
          "type": "window",
          "fields": ["is_inside"],
          "ops": ["sum"],
          "as": ["num_inside"]
        },
        {
          "type": "formula", "as": "estimate",
          "expr": "4 * datum.num_inside / datum.data"
        }
      ]
    },
    {
      "name": "pi_estimate",
      "source": "pi_estimates",
      "transform": [
        { "type": "filter", "expr": "datum.data == num_points" },
        { "type": "formula", "as": "value", "expr": "datum.estimate" }
      ]
    },
    {
      "name": "pi",
      "values": [{ "value": 3.141592653589793 }]
    }
  ],

  "signals": [
    {
      "name": "num_points",
      "value": 1000,
      "bind": {"input": "range", "min": 10, "max": 5000, "step": 1, "debounce": 10}
    }
  ],

  "layout": {
    "padding": 70,
    "bounds": "flush",
    "align": "none"
  },

  "marks": [
    {
      "type": "group",
      "style": "cell",
      "title": {
        "text": "In Points and Out Points",
        "frame": "group"
      },

      "encode": {
        "update": {
          "width": {"signal": "height"},
          "height": {"signal": "height"}
        }
      },

      "marks": [
        {
          "type": "arc",
          "encode": {
            "enter": {
              "stroke": {"value": "#888"},
              "strokeWidth": {"value": 1},
              "startAngle": {"signal": "1.570796"},
              "endAngle": {"value": 0},
              "x": {"value": 0.5},
              "y": {"signal": "height + 0.5"},
              "innerRadius": {"signal": "height"},
              "outerRadius": {"signal": "height"}
            }
          }
        },
        {
          "type": "symbol",
          "style": ["circle"],
          "from": {"data": "random_data"},
          "encode": {
            "update": {
              "opacity": {"value": 0.6},
              "fill": [
                {
                  "test": "hypot(datum.x, datum.y) <= 1",
                  "value": "#003f5c"
                },
                { "value": "#ffa600" }
              ],
              "x": {"scale": "x_scale", "field": "x"},
              "y": {"scale": "y_scale", "field": "y"},
              "shape": {"value": "circle"}
            }
          }
        }
      ],

      "axes": [
        {
          "scale": "x_scale",
          "orient": "bottom",
          "title": "x",
          "labelFlush": true,
          "labelOverlap": true,
          "zindex": 1
        },
        {
          "scale": "x_scale",
          "orient": "bottom",
          "grid": true,
          "gridScale": "y_scale",
          "domain": false,
          "labels": false,
          "maxExtent": 0,
          "minExtent": 0,
          "ticks": false,
          "zindex": 0
        },
        {
          "scale": "y_scale",
          "orient": "left",
          "title": "y",
          "labelOverlap": true,
          "zindex": 1
        },
        {
          "scale": "y_scale",
          "orient": "left",
          "grid": true,
          "gridScale": "x_scale",
          "domain": false,
          "labels": false,
          "maxExtent": 0,
          "minExtent": 0,
          "ticks": false,
          "zindex": 0
        }
      ]
    },
    {
      "type": "group",
      "name": "concat_1_group",
      "style": "cell",
      "title": {
        "text": "π Estimate",
        "frame": "group"
      },

      "encode": {
        "update": {
          "width": {"signal": "height"},
          "height": {"signal": "height"}
        }
      },

      "marks": [
        {
          "type": "symbol",
          "style": ["circle"],
          "from": {"data": "pi_estimates"},
          "encode": {
            "update": {
              "opacity": {"value": 0.7},
              "fill": {"value": "#4c78a8"},
              "x": {"scale": "data_point_scale", "field": "data"},
              "y": {"scale": "pi_scale", "field": "estimate"},
              "size": {"value": 8},
              "shape": {"value": "circle"}
            }
          }
        },
        {
          "type": "rule",
          "from": {"data": "pi"},
          "encode": {
            "update": {
              "stroke": {"value": "darkgrey"},
              "x": {"value": 0},
              "y": {"scale": "pi_scale", "field": "value"},
              "x2": {"field": {"group": "width"}}
            }
          }
        },
        {
          "type": "text",
          "from": {"data": "pi"},
          "encode": {
            "update": {
              "align": {"value": "left"},
              "x": {"value": 10},
              "fill": {"value": "black"},
              "y": {"scale": "pi_scale", "field": "value", "offset": -5},
              "text": {"value": "Real PI: 3.1415..."}
            }
          }
        },
        {
          "type": "text",
          "from": {"data": "pi_estimate"},
          "encode": {
            "update": {
              "align": {"value": "right"},
              "x": {"signal": "height", "offset": -5},
              "dy": {"value": -5},
              "fill": {"value": "black"},
              "y": {"scale": "pi_scale", "field": "value"},
              "text": {"signal": "'Estimate: ' + format(datum.estimate, ',.3f')"}
            }
          }
        }
      ],

      "axes": [
        {
          "scale": "data_point_scale",
          "orient": "bottom",
          "title": "Number of Points",
          "labelFlush": true,
          "labelOverlap": true,
          "zindex": 1
        },
        {
          "scale": "data_point_scale",
          "orient": "bottom",
          "grid": true,
          "gridScale": "pi_scale",
          "domain": false,
          "labels": false,
          "maxExtent": 0,
          "minExtent": 0,
          "ticks": false,
          "zindex": 0
        },
        {
          "scale": "pi_scale",
          "orient": "left",
          "title": "Estimated π Value",
          "labelOverlap": true,
          "zindex": 1
        },
        {
          "scale": "pi_scale",
          "orient": "left",
          "grid": true,
          "gridScale": "data_point_scale",
          "domain": false,
          "labels": false,
          "maxExtent": 0,
          "minExtent": 0,
          "ticks": false,
          "zindex": 0
        }
      ]
    }
  ],

  "scales": [
    {
      "name": "x_scale",
      "type": "linear",
      "domain": [0, 1],
      "range": "height",
      "reverse": true,
      "nice": true,
      "zero": true
    },
    {
      "name": "y_scale",
      "type": "linear",
      "domain": [0, 1],
      "range": "height",
      "nice": true,
      "zero": true
    },
    {
      "name": "data_point_scale",
      "type": "linear",
      "domain": {
        "data": "pi_estimates",
        "field": "data"
      },
      "range": "height",
      "reverse": true,
      "nice": false,
      "zero": true
    },
    {
      "name": "pi_scale",
      "type": "linear",
      "domain": {
        "fields": [
          [2, 4],
          {"data": "pi", "field": "value"},
          {"data": "pi_estimates", "field": "estimate"}
        ]
      },
      "range": "height",
      "nice": true,
      "zero": false
    }
  ],

  "config": {
    "axisY": {"minExtent": 30}
  }
}