Bayes Visualization
This app is based on the visualization of Bayes' Theorem described in this post: http://lesswrong.com/lw/2b0/bayes_theorem_illustrated_my_way/
This app was designed for a window size of 800x600. You will need to click the "Preview Fullscreen" button in order to see the right half of the app.
or view the version at http://peerinfinity.com/BayesVisualization/
/**
* Copyright PeerInfinity ( http://wonderfl.net/user/PeerInfinity )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/32WF
*/
// This app is based on the visualization of Bayes' Theorem described in this post:
// http://lesswrong.com/lw/2b0/bayes_theorem_illustrated_my_way/
// This app was designed for a window size of 800x600.
// You will need to click the "Preview Fullscreen" button
// in order to see the right half of the app.
// or view the version at http://peerinfinity.com/BayesVisualization/
// this app has known bugs.
// Any help fixing these bugs or adding features is appreciated.
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.display.*;
import flash.text.*;
import flash.events.*;
import flash.geom.*;
import flash.ui.*;
public class Main extends Sprite
{
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
var newFormat:TextFormat;
m_Label_HypothesisCount = new TextField();
m_Label_HypothesisCount.text = "Number of Hypotheses:";
m_Label_HypothesisCount.width = 130;
newFormat = m_Label_HypothesisCount.getTextFormat();
newFormat.size = 12;
newFormat.align = TextFormatAlign.RIGHT;
m_Label_HypothesisCount.setTextFormat(newFormat);
m_Label_HypothesisCount.x = 0;
m_Label_HypothesisCount.y = 10;
addChild(m_Label_HypothesisCount);
m_Edit_HypothesisCount = new TextField();
m_Edit_HypothesisCount.text = "2";
m_Edit_HypothesisCount.type = TextFieldType.INPUT;
m_Edit_HypothesisCount.selectable = true;
mouseChildren = true;
m_Edit_HypothesisCount.border = true;
m_Edit_HypothesisCount.background = true;
m_Edit_HypothesisCount.textColor = 0x000000;
m_Edit_HypothesisCount.multiline = false;
newFormat = m_Edit_HypothesisCount.getTextFormat();
newFormat.size = 12;
newFormat.align = TextFormatAlign.RIGHT;
m_Edit_HypothesisCount.setTextFormat(newFormat);
//m_Edit_HypothesisCount.autoSize = TextFieldAutoSize.CENTER;
m_Edit_HypothesisCount.width = 40;
m_Edit_HypothesisCount.height = 20;
m_Edit_HypothesisCount.x = m_Label_HypothesisCount.x + m_Label_HypothesisCount.width + 2;
m_Edit_HypothesisCount.y = 10;
//trace(m_Label_HypothesisCount.x);
//trace(m_Label_HypothesisCount.width);
//trace(m_Edit_HypothesisCount.x);
//trace(m_Edit_HypothesisCount.width);
addChild(m_Edit_HypothesisCount);
m_Edit_HypothesisCount.addEventListener(Event.CHANGE, HypothesisCountChanged);
ResetEverything();
}
private function HypothesisCountChanged(e:Event):void
{
//trace("event");
if ( Number(m_Edit_HypothesisCount.text) > 10 || Number(m_Edit_HypothesisCount.text) < 2 )
{
m_Label_HypothesisCount.textColor = 0xFF0000;
}
else
{
m_Label_HypothesisCount.textColor = 0x000000;
ResetEverything();
}
}
private function ResetEverything():void
{
var hypothesisCount:int = Number(m_Edit_HypothesisCount.text);
//trace(hypothesisCount);
var i:uint = 0;
var j:uint = 0;
var newFormat:TextFormat;
for each( var CurrentRow:DisplayRow in m_Array_DisplayRows )
{
CurrentRow.ClearDisplayRow();
}
m_Array_DisplayRows = [];
graphics.clear();
for( i = 0; i < hypothesisCount; i++ )
{
m_Array_DisplayRows[i] = new DisplayRow();
m_Array_DisplayRows[i].m_Index = i;
m_Array_DisplayRows[i].ResetDisplayRow();
addChild(m_Array_DisplayRows[i]);
}
}
}
}
import flash.display.*;
import flash.text.*;
import flash.events.*;
import flash.geom.*;
import flash.ui.*;
var m_Label_HypothesisCount:TextField;
var m_Edit_HypothesisCount:TextField;
var m_Array_DisplayRows:Array = [];
var g_ColorArray:Array = [0x0000FF, 0x00FF00, 0x00FFFF, 0xFF0000, 0xFF00FF, 0xFFFF00, 0x000080, 0x008000, 0x800000, 0x808080];
class DisplayRow extends Sprite
{
public var m_Index:int;
public var m_Label_PriorProbability:TextField;
public var m_Edit_PriorProbability:TextField;
public var m_PriorProbabilityAfterLastUpdate:Number;
public var m_HypothesisShape:HypothesisShape;
public var m_Array_ResultRows:Array;
public var m_AlreadyUpdatingPriorProbability:Boolean = false;
public function ClearDisplayRow():void
{
removeChild(m_Label_PriorProbability);
removeChild(m_Edit_PriorProbability);
removeChild(m_HypothesisShape);
for each( var CurrentRow:ResultRow in m_Array_ResultRows )
{
CurrentRow.ClearResultRow();
}
}
public function ResetDisplayRow():void
{
var i:uint = m_Index;
var j:uint = 0;
var hypothesisCount:int = Number(m_Edit_HypothesisCount.text);
var newFormat:TextFormat;
var priorProbability:Number = 1 / hypothesisCount;
m_PriorProbabilityAfterLastUpdate = priorProbability * 100;
m_Label_PriorProbability = new TextField();
m_Label_PriorProbability.text = "Prior Probability of H" + (i+1) + ":";
m_Label_PriorProbability.width = 130;
newFormat = m_Label_PriorProbability.getTextFormat();
newFormat.size = 12;
newFormat.align = TextFormatAlign.RIGHT;
m_Label_PriorProbability.setTextFormat(newFormat);
m_Label_PriorProbability.x = 0;
m_Label_PriorProbability.y = 40 + (i * 110);
addChild(m_Label_PriorProbability);
m_Edit_PriorProbability = new TextField();
m_Edit_PriorProbability.text = String(100/hypothesisCount);
m_Edit_PriorProbability.type = TextFieldType.INPUT;
m_Edit_PriorProbability.selectable = true;
mouseChildren = true;
m_Edit_PriorProbability.border = true;
m_Edit_PriorProbability.background = true;
m_Edit_PriorProbability.textColor = 0x000000;
m_Edit_PriorProbability.multiline = false;
newFormat = m_Edit_PriorProbability.getTextFormat();
newFormat.size = 12;
newFormat.align = TextFormatAlign.RIGHT;
m_Edit_PriorProbability.setTextFormat(newFormat);
//m_Edit_PriorProbability.autoSize = TextFieldAutoSize.CENTER;
m_Edit_PriorProbability.width = 40;
m_Edit_PriorProbability.height = 20;
m_Edit_PriorProbability.x = m_Label_HypothesisCount.x + m_Label_HypothesisCount.width + 2;
m_Edit_PriorProbability.y = m_Label_PriorProbability.y;
//trace(m_Label_HypothesisCount.x);
//trace(m_Label_HypothesisCount.width);
//trace(m_Edit_PriorProbability.x);
//trace(m_Edit_PriorProbability.width);
addChild(m_Edit_PriorProbability);
m_HypothesisShape = new HypothesisShape();
m_HypothesisShape.m_size = priorProbability;
m_HypothesisShape.m_color = g_ColorArray[i];
m_HypothesisShape.DrawHypothesisShape();
m_HypothesisShape.x = m_Edit_PriorProbability.x + m_Edit_PriorProbability.width + 10;
m_HypothesisShape.y = m_Edit_PriorProbability.y;
addChild(m_HypothesisShape);
m_Array_ResultRows = [];
for( j = 0; j < hypothesisCount; j++ )
{
m_Array_ResultRows[j] = new ResultRow();
m_Array_ResultRows[j].m_ParentIndex = i;
m_Array_ResultRows[j].m_Index = j;
m_Array_ResultRows[j].m_Parent = this;
m_Array_ResultRows[j].ResetResultRow();
addChild(m_Array_ResultRows[j]);
}
m_Edit_PriorProbability.addEventListener(Event.CHANGE, PriorProbabilityChanged);
}
// this only gets called when the user changes the value, not when the code changes the edit box's text value?
private function PriorProbabilityChanged(e:Event):void
{
var newPriorProbability:Number = Number(m_Edit_PriorProbability.text);
if ( newPriorProbability > 100 || newPriorProbability < 0 )
{
m_Label_PriorProbability.textColor = 0xFF0000;
}
else
{
m_Label_PriorProbability.textColor = 0x000000;
DoPriorProbabilityChanged();
}
}
public function DoPriorProbabilityChanged():void
{
if ( !m_AlreadyUpdatingPriorProbability )
{
m_AlreadyUpdatingPriorProbability = true;
var newPriorProbability:Number = Number(m_Edit_PriorProbability.text);
var totalPriorProbability:Number = newPriorProbability;
for each( var CurrentRow:DisplayRow in m_Array_DisplayRows )
{
if ( !CurrentRow.m_AlreadyUpdatingPriorProbability )
{
if ( totalPriorProbability + Number(CurrentRow.m_Edit_PriorProbability.text) > 100 )
{
CurrentRow.m_Edit_PriorProbability.text = String( 100 - totalPriorProbability );
// because this doesn't happen automatically
CurrentRow.DoPriorProbabilityChanged();
}
totalPriorProbability += Number(CurrentRow.m_Edit_PriorProbability.text);
}
}
ResizeDisplayRowShapes(newPriorProbability);
for each( var CurrentRow2:ResultRow in m_Array_ResultRows )
{
//CurrentRow2.ResizeResultRowShapes();
//CurrentRow2.DoResultProbabilityChanged();
var prevVal:Number = Number(CurrentRow2.m_Edit_ResultProbability.text);
var newVal:Number = prevVal / m_PriorProbabilityAfterLastUpdate * newPriorProbability;
CurrentRow2.m_Edit_ResultProbability.text = String(newVal);
CurrentRow2.ResizeResultRowShapes(newVal);
}
m_PriorProbabilityAfterLastUpdate = newPriorProbability;
m_AlreadyUpdatingPriorProbability = false;
}
}
public function ResizeDisplayRowShapes(newPriorProbability:int):void
{
m_HypothesisShape.m_size = newPriorProbability / 100;
m_HypothesisShape.DrawHypothesisShape();
}
}
class ResultRow extends Sprite
{
public var m_ParentIndex:int;
public var m_Index:int;
public var m_Parent:DisplayRow;
public var m_Edit_ResultProbability:TextField;
public var m_ResultProbabilityAfterLastUpdate:Number;
public var m_ResultShape:ResultShape;
public var m_Label_UnscaledProbability:TextField;
public var m_Label_RescaledProbability:TextField;
public var m_AlreadyUpdatingResultProbability:Boolean = false;
public function ClearResultRow():void
{
removeChild(m_Edit_ResultProbability);
removeChild(m_ResultShape);
removeChild(m_Label_UnscaledProbability);
removeChild(m_Label_RescaledProbability);
}
public function ResetResultRow():void
{
var i:uint = m_ParentIndex;
var j:uint = m_Index;
var hypothesisCount:int = Number(m_Edit_HypothesisCount.text);
var newFormat:TextFormat;
var priorProbability:Number = 1 / hypothesisCount;
//var resultProbability:Number = priorProbability / hypothesisCount;
var resultProbability:Number = priorProbability;
m_ResultProbabilityAfterLastUpdate = resultProbability * 100;
m_Edit_ResultProbability = new TextField();
m_Edit_ResultProbability.text = String(resultProbability * 100);
m_Edit_ResultProbability.type = TextFieldType.INPUT;
m_Edit_ResultProbability.selectable = true;
mouseChildren = true;
m_Edit_ResultProbability.border = true;
m_Edit_ResultProbability.background = true;
m_Edit_ResultProbability.textColor = 0x000000;
m_Edit_ResultProbability.multiline = false;
newFormat = m_Edit_ResultProbability.getTextFormat();
newFormat.size = 12;
newFormat.align = TextFormatAlign.RIGHT;
m_Edit_ResultProbability.setTextFormat(newFormat);
//m_Edit_ResultProbability.autoSize = TextFieldAutoSize.CENTER;
m_Edit_ResultProbability.width = 40;
m_Edit_ResultProbability.height = 20;
m_Edit_ResultProbability.x = m_Parent.m_HypothesisShape.x + 100 + 2;
m_Edit_ResultProbability.y = m_Parent.m_HypothesisShape.y + ( j * ( 100 / hypothesisCount ) );
//trace(m_Label_HypothesisCount.x);
//trace(m_Label_HypothesisCount.width);
//trace(m_Edit_ResultProbability.x);
//trace(m_Edit_ResultProbability.width);
addChild(m_Edit_ResultProbability);
m_ResultShape = new ResultShape();
m_ResultShape.m_size = resultProbability;
m_ResultShape.m_color = g_ColorArray[i];
m_ResultShape.m_sides = 3 + j;
m_ResultShape.DrawResultShape();
m_ResultShape.x = m_Edit_ResultProbability.x + m_Edit_ResultProbability.width + 10;
m_ResultShape.y = m_Edit_ResultProbability.y;
addChild(m_ResultShape);
m_Label_UnscaledProbability = new TextField();
m_Label_UnscaledProbability.text = "Unscaled Result R" + (j+1) + ":";
m_Label_UnscaledProbability.width = 130;
newFormat = m_Label_UnscaledProbability.getTextFormat();
newFormat.size = 12;
newFormat.align = TextFormatAlign.RIGHT;
m_Label_UnscaledProbability.setTextFormat(newFormat);
m_Label_UnscaledProbability.x = m_ResultShape.x + 100;
m_Label_UnscaledProbability.y = m_ResultShape.y;
addChild(m_Label_UnscaledProbability);
m_Label_RescaledProbability = new TextField();
m_Label_RescaledProbability.text = "Rescaled Result R" + (j+1) + ":";
m_Label_RescaledProbability.width = 130;
newFormat = m_Label_RescaledProbability.getTextFormat();
newFormat.size = 12;
newFormat.align = TextFormatAlign.RIGHT;
m_Label_RescaledProbability.setTextFormat(newFormat);
m_Label_RescaledProbability.x = m_Label_UnscaledProbability.x + m_Label_UnscaledProbability.width;
m_Label_RescaledProbability.y = m_Label_UnscaledProbability.y;
addChild(m_Label_RescaledProbability);
m_Edit_ResultProbability.addEventListener(Event.CHANGE, ResultProbabilityChanged);
}
// this only gets called when the user changes the value, not when the code changes the edit box's text value?
private function ResultProbabilityChanged(e:Event):void
{
//var maxProbability:Number = Number(m_Parent.m_Edit_PriorProbability.text);
var maxProbability:Number = 100;
var newResultProbability:Number = Number(m_Edit_ResultProbability.text);
if ( newResultProbability > maxProbability || newResultProbability < 0 )
{
m_Label_UnscaledProbability.textColor = 0xFF0000;
m_Label_RescaledProbability.textColor = 0xFF0000;
}
else
{
m_Label_UnscaledProbability.textColor = 0x000000;
m_Label_RescaledProbability.textColor = 0x000000;
DoResultProbabilityChanged();
}
}
public function DoResultProbabilityChanged():void
{
if ( !m_AlreadyUpdatingResultProbability )
{
m_AlreadyUpdatingResultProbability = true;
//var maxProbability:Number = Number(m_Parent.m_Edit_PriorProbability.text);
var maxProbability:Number = 100;
var newResultProbability:Number = Number(m_Edit_ResultProbability.text);
var totalResultProbability:Number = newResultProbability;
for each( var CurrentRow:ResultRow in m_Parent.m_Array_ResultRows )
{
if ( !CurrentRow.m_AlreadyUpdatingResultProbability )
{
if ( totalResultProbability + Number(CurrentRow.m_Edit_ResultProbability.text) > maxProbability )
{
CurrentRow.m_Edit_ResultProbability.text = String( maxProbability - totalResultProbability );
// because this doesn't happen automatically
CurrentRow.DoResultProbabilityChanged();
}
totalResultProbability += Number(CurrentRow.m_Edit_ResultProbability.text);
}
}
ResizeResultRowShapes(newResultProbability);
m_ResultProbabilityAfterLastUpdate = newResultProbability;
m_AlreadyUpdatingResultProbability = false;
}
}
public function ResizeResultRowShapes(newResultProbability:int):void
{
m_ResultShape.m_size = newResultProbability / 100;
m_ResultShape.DrawResultShape();
var totalUnscaled:Number = 0;
var i:int = 0;
var count:int = Number(m_Edit_HypothesisCount.text);
for ( i = 0; i < count; i++ )
{
//var tempUnscaled:Number = 1;
var tempUnscaled:Number = ( Number(m_Array_DisplayRows[i].m_Array_ResultRows[m_Index].m_Edit_ResultProbability.text) * Number(m_Array_DisplayRows[i].m_Edit_PriorProbability.text) / 100 );
//trace(m_Array_DisplayRows[i].m_Edit_PriorProbability.text);
//trace(m_Array_DisplayRows[i].m_Array_ResultRows[m_Index].m_Edit_ResultProbability.text);
totalUnscaled += tempUnscaled;
}
for ( i = 0; i < count; i++ )
{
var currentUnscaled:Number = ( Number(m_Array_DisplayRows[i].m_Array_ResultRows[m_Index].m_Edit_ResultProbability.text) * Number(m_Array_DisplayRows[i].m_Edit_PriorProbability.text) / 100 );
var currentRescaled:Number = currentUnscaled / totalUnscaled * 100;
//CurrentRow2.m_Label_UnscaledProbability.text = "Unscaled Result R" + (CurrentRow2.m_Index+1) + ": " + currentUnscaled;
//CurrentRow2.m_Label_RescaledProbability.text = "Rescaled Result R" + (CurrentRow2.m_Index+1) + ": " + currentRescaled;
m_Array_DisplayRows[i].m_Array_ResultRows[m_Index].m_Label_UnscaledProbability.text = "Unscaled Result: " + currentUnscaled;
m_Array_DisplayRows[i].m_Array_ResultRows[m_Index].m_Label_RescaledProbability.text = "Rescaled Result: " + currentRescaled;
}
}
}
class HypothesisShape extends Sprite
{
public var m_size:Number;
public var m_color:int;
public function DrawHypothesisShape():void
{
graphics.clear();
graphics.beginFill(m_color);
graphics.lineStyle(2, 0x000000);
//graphics.drawRect(0, 0, 100*m_size, 100*m_size);
graphics.drawCircle(50*m_size, 50*m_size, 50*m_size);
graphics.endFill();
}
}
// done quick and dirty. a quick google search didn't find a standard class for regular polygons
class ResultShape extends Sprite
{
public var m_size:Number;
public var m_color:int;
public var m_sides:int;
public function DrawResultShape():void
{
graphics.clear();
// graphics.beginFill(m_color);
// graphics.lineStyle(2, 0x000000);
// graphics.drawRect(0, 0, 100*m_size, 100*m_size);
//graphics.drawCircle(50*m_size, 50*m_size, 50*m_size);
// graphics.endFill();
const REVOLUTION:int = 360;
var _radius:int = 100/Number(m_Edit_HypothesisCount.text)*m_size;
var _sides:int = m_sides;
var _strokeThickness:int = 2;
var _strokeColor:int = 0x000000;
var _fillColor:int;
var _strokeAlpha:Number;
var _fillAlpha:Number;
var _angle:int = 0;
_fillColor = m_color;
_fillAlpha = 1;
_strokeColor = 0x000000;
_strokeAlpha = 1;
_strokeThickness = 2;
_angle = REVOLUTION;
var angle:Number = 0;
var angleInc:Number = (REVOLUTION / _sides);
var xpos:Number = 0;
var ypos:Number = 0;
xpos = getAngleX(_radius, angle);
ypos = getAngleY(_radius, angle);
//graphics.clear();
if(_strokeColor > -1) graphics.lineStyle(_strokeThickness, _strokeColor, _strokeAlpha);
graphics.moveTo(xpos+_radius, ypos+_radius);
graphics.beginFill(_fillColor, _fillAlpha);
while(angle <= _angle)
{
xpos = getAngleX(_radius, angle);
ypos = getAngleY(_radius, angle);
angle += angleInc;
graphics.lineTo(xpos+_radius,ypos+_radius);
}
graphics.endFill();
}
public function getAngleX(r:Number, Angle:Number):Number { return ( r * Math.cos((90 - Angle) * Math.PI / 180)); }
public function getAngleY(r:Number, Angle:Number):Number { return ( -r * Math.sin((90 - Angle) * Math.PI / 180)); }
}
//todo - add a message to report when the probabilities add up to less than 100?
// and a button to automatically update one probability to make the total 100?
// or just make the math support probability totals of less than 100?