Here is a demonstration of MRoots:
I know, it needs some work... You must have Silverlight 4 installed to see the MRoots Applet below. Silverlight is (in my opinion) a more secure/versatile alternative to Adobe Flash.
I need to upgrade this to SVG.js when I get the chance...

Get Microsoft Silverlight

Here's a "pretty" listing of the code. I'll probably add a raw file link later:

"And whatever you do, whether in word or deed,
do it all in the name of the Lord Jesus, giving thanks to
God the Father through him."
Collossians 3:17 NIV
!!! Warning !!! This document is currently in a draft status.
it might change a bit. If you actually do cite it,
be sure and let everyone know that you are citing
a draft document.
Title : M Roots Demo
Filename : MSRootsDemo.fs    
Author : Shawn Eary
Date : 01-FEB-2011
Revision : dft-0.01  (This is seriously alpha...
                      I'm a little cramped for time right now...)
Copyright : 2011
License : Free Christian Document License (FCDL)
Warranty : None (See FCDL Terms)
Purpose : To amuze the reader (Also see spec)
The program is covered under the FCDL (see above) as such it
is treated more as a paper than a program. Do not confuse
the FCDL License with other "Open Source" Licenses as this
license is very different. The FCDL is a "good faith"
licence that basically gives you the
right to:
a) Make as many copies of covered documents that you want as
   long as the entire covered documents including spelling
   errors, biblical references, citations and author credits
   are kept intact.
b) Use portions of this document to create your own
   religiously neutral or Christian products provided you
   properly cite this document.
   (Overall URL of document and Author at tail or beginning
    of work with (filename:functionname) citations inline)
c) Charge for the distribution of covered documents or
   for products that were created by using portions of covered
   documents with no obligation to reimburse the authors of
   the covered documents.
Other Notes: 
In order to compile this, you will need Mr. Danson's Silverlight 
Application Template [1] (See Below) 
You cram all of this file into the MainPage.fs file that his template
creates.  You should then be able to compile this applet
(which is still in a serious development stage and may have 
 significant bugs) 
// Sources
// Warning: I haven't double checked these references.
//          This is not a serious acedemic adventure yet...
// [1] - Danson, Neil 
//       F# Silverlight Application 
//       December 22, 2010 
//       Last visited on: January 29, 2011
// [2] - McNamara, Brian
//       Game programming in F# (with Silverlight and WPF)
//       April 24, 2010
//       Last Visited on: January 29, 2011
// [3] - McNamara, Brian
//       Source code for F# Depth Colorizer extension
//       November 21, 2010
//       Last Visited on: January 29, 2011
// [4] - Smith, J.O. 
//       Mathematics of the Discrete Fourier Transform (DFT)
//       with Audio Applications, Second Edition,
//       2007, online book, accessed January 30, 2011.
// [5] - Butler, Tetyana
//       Roots of complex numbers 
//       2006
//       Last Visited on: February 01, 2011
namespace FSharpSilverlightApp
open System
open System.Windows
open System.Windows.Controls
open System.Windows.Media
open System.Windows.Shapes
open System.Windows.Media.Imaging
type MainPage() as this = 
   inherit UserControl()
      (* BEGIN: Configuration Constants                          *) 
      let canvasHeight = 400.0
      let canvasWidth = 400.0
      let circleFractionToCanvasSize = 0.70   (* 70 Percent *) 
      let minRootLevel = 1
      let maxRootLevel = 7
      let defaultRootLevel = 3
      (* Limited to prevent excessive clutter *)
      let rec allowedRoots = 
         [minRootLevel .. maxRootLevel] 
      (* END: Configuration Constants                            *) 
      let canvasCenterX = canvasHeight / 2.0
      let canvasCenterY = canvasWidth / 2.0
      let minDimValue = min canvasHeight canvasWidth
      let circleRadius = (minDimValue * circleFractionToCanvasSize) / 2.0
      let phaseCirclesRadius = circleRadius * 0.05
      (* Helper function to load a combo box with values *)
      let rec loadCB (cb : ComboBox) list = 
         match list with 
         | head :: tail -> 
            loadCB cb tail 
         | [] -> ()
      (* Helper function to return the Magnatude of a complex number *)
      let magnitude r i = 
         Math.Sqrt(r*r + i*i)
      (* Helper function to return the Phase of a complex number *) 
      let phase r i =          
      (* I "believe" this computes the Mth roots of identity of 
         the complex number defined by r (real) and i (imaginary).
         This is of course assuming that I understood Dr. Smith. [4]
         If I understood Dr. Smith correctly, then the M roots are
         simply given by his formula:
         r^(1/M) * e ^ (j*(initialPhase+2*pi*k)/M) 
         since r^(1/M) appears to just be a scaling factor then the 
         Mth roots of unity should just be the same function above 
         without the scaling factor which would be 
         e ^ (j*(initialPhase+2*pi*k)/M) 
         this is confusing to me since Dr. Smith formula for the Mth
         roots of unity appears to be 
         e ^ (j*2*pi*k/M)
         which totally ignores the initial phase of the complex 
         number.  Maybe I'm just going a little dense here.  Maybe
         we want for Dr. Smith's application the initial phase isn't
         important.  Anyway, I will by using 
         e ^ (j*(initialPhase+2*pi*k)/M)
         and applying it to Euler's identity as proposed by 
         Dr. Smith [4] which should give me (assuming I'm not really
           cos ((initialPhase + 2*pi*k) / M) + 
         j sin ((initialPhase + 2*pi*k) / M)
         to get the unit circle roots of the original complex 
         number defined by r (real) and i (imaginary)  *)  
      let rootPhases r i M = 
         let rec p_rootsOfUnity r i M (k : int) = 
            if (k > (M-1)) then
               let complexPhase = phase r i 
               let (doubleK : double) = Convert.ToDouble(k)
               let (doubleM : double) = Convert.ToDouble(M)
               let theta = (complexPhase + 2.0 * Math.PI * doubleK) / doubleM
               (Math.Cos(theta), Math.Sin(theta)) :: (p_rootsOfUnity r i M (k+1))
         p_rootsOfUnity r i M 0
      (* Helper function to output a Phase List in a format that 
         is a little easier to read in the VS2010 debugger *)  
      let rec getPhaseDebugString pl = 
         match pl with 
         | head :: tail -> 
            "(" + fst(head).ToString() + "," + snd(head).ToString() + ")" 
            + (getPhaseDebugString tail)
         | [] -> ""
      (* Given the assumption that the origin is in the center of the
         canvas, this trivial function converts the origin relative
         Cord into the absolute cord that is needed by a Silverlight
         Canvas *)
      let relToAbs (rx,ry) = (canvasCenterX + rx, canvasCenterY - ry)
      (* Trivial function to compute the center of the well behaved
         shape.  This will only work on Ellipses, Rectangles 
         and Lines *) 
      let simpleShapeCenter (s : Shape) = 
         (s.Width / 2.0, s.Height / 2.0)
      (* Takes a simple shape and its current position and returns 
         the absolute coordinated needed to position it on a canvas.
         This makes it easy to plot the center of elipses from the 
         center of the cavas which is considered the origin 
         Note: This will only work on Ellipses and Rectangles *)
      let simpleShapeRelToAbs (s : Shape) (rx,ry) = 
         let cTup = simpleShapeCenter s
         let absTup = relToAbs (rx,ry)
         (fst(absTup) - fst(cTup), snd(absTup) - snd(cTup))
      (* Helper function to packs the specified control into the 
         specified grid *) 
      let pack ctrl row column colSpan (grid : Grid) = 
         Grid.SetRow(ctrl, row)
         Grid.SetColumn(ctrl, column)
         Grid.SetColumnSpan(ctrl, colSpan)
      (* Helper function to create/locate simple TextBlock controls *)
      let newTB text row column colSpan (grid : Grid) = 
         let someTB = TextBlock(Text=text)
         pack someTB row column colSpan grid         
      let grid = Grid()            
         RowDefinition(Height=GridLength(0.0, GridUnitType.Auto))
         RowDefinition(Height=GridLength(0.0, GridUnitType.Auto))
         RowDefinition(Height=GridLength(0.0, GridUnitType.Auto))
         RowDefinition(Height=GridLength(0.0, GridUnitType.Auto))
      let canvas = Canvas()      
      canvas.Height <- canvasHeight
      canvas.Width <- canvasWidth
      canvas.Background <- SolidColorBrush(Color(A=255uy,R=0uy,B=0uy,G=255uy))
      this.Content <- grid      
      let a = 
      let newCord = simpleShapeRelToAbs a (0.0, 0.0)      
      Canvas.SetLeft(a, fst(newCord)) 
      Canvas.SetTop(a, snd(newCord)) 
      pack canvas 0 0 3 grid
      (* Create the labels for the input controls *) 
      newTB "Real:" 1 0 1 grid
      newTB "Imaginary:" 1 1 1 grid
      newTB "Num Roots:" 1 2 1 grid      
      let realInput = TextBox()
      pack realInput 2 0 1 grid
      let imaginaryInput = TextBox()
      pack imaginaryInput 2 1 1 grid
      let cbNumRoots = ComboBox()
      loadCB cbNumRoots allowedRoots     
      cbNumRoots.SelectedValue <- defaultRootLevel 
      pack cbNumRoots 2 2 1 grid
      (* Helper function to plot the circle dots associated with the 
         the phases in pl *) 
      let plotPhases pl (iCanvas : Canvas) baseCircle = 
         let rec plotPhasesR pl (iCanvas : Canvas) = 
            match pl with 
            | head :: tail ->
               let e = 
               let fstHead = fst(head)      
               let sndHead = snd(head)
               let relX = fstHead*circleRadius
               let relY = sndHead*circleRadius
               let newCord = simpleShapeRelToAbs e (relX, relY)      
               Canvas.SetLeft(e, fst(newCord)) 
               Canvas.SetTop(e, snd(newCord))             
               plotPhasesR tail iCanvas      
            | [] -> ()
         (* Toast everything in the Canvas - Lazy fix *)
         (* Add the base circle back after the above toast 
            operation *) 
         plotPhasesR pl iCanvas
      (* Mr. McNamara shows how to map a handler in [3] *)
      let submitHandler() =         
         let realString = realInput.Text         
         let realIsValid = fst(Double.TryParse(realString))         
         if not realIsValid then
            MessageBox.Show("Real Component is not a valid Double") |> ignore              
         let imaginaryString = imaginaryInput.Text
         let imaginaryIsValid = fst(Double.TryParse(imaginaryString))
         if not imaginaryIsValid then
            MessageBox.Show("Imaginary Component is not a valid Double") |> ignore
         if realIsValid && imaginaryIsValid then
            let (rootDegree : int) = cbNumRoots.SelectedValue :?> int
            let realValue = Double.Parse(realString)
            let imaginaryValue = Double.Parse(imaginaryString)  
            let complexRadius = magnitude realValue imaginaryValue  
            let thePhases = rootPhases realValue imaginaryValue rootDegree                    
            plotPhases thePhases canvas a
      let bnSubmit = Button(Content="Submit")            
      pack bnSubmit 3 0 3 grid
      (* Mr. McNamara shows how to map a handler in [3] *)
      bnSubmit.Click.Add(fun _ -> submitHandler())