Random Dots on a Circle

Viewed 125

Is there a way to randomly scatter a pre-defined number of dots on a circle? The example below randomly scatters dots on a square but I need the area to be a circle.

clear
set seed 101010
set obs 225           // There should be 225 dots on the circle. 
gen x1 = runiform()
gen y1 = runiform()

twoway  (scatter x1 y1 ///
        , graphregion(color(white)) xtitle("") ytitle("") ///
        yscale(lstyle(none)) xscale(lstyle(none)) ///
        ylabel(none, nolabels noticks nogrid) xlabel(none, nolabels noticks nogrid))

Edit The code below outlines a possible solution but the dots are not distributed evenly across the area. Since this is most visible when there is a large number of dots, the code below generates 10000 observations.

Any idea how to make the dots evenly distributed across the area?

clear 
set obs 10000
gen obs = _n
gen N = _N
gen y = runiform()
gen angle = obs * 2 * _pi / N

gen obsx = y * cos(angle)
gen obsy = y * sin(angle)

twoway scatter obsx obsy, msize(tiny) graphregion(color(white)) xtitle("") ytitle("") ///
            yscale(lstyle(none)) xscale(lstyle(none)) ysize(1) xsize(1) ///
            ylabel(none, nolabels noticks nogrid) xlabel(none, nolabels noticks nogrid)  

3 Answers
clear
set seed 101010
set obs 225
gen x1 = 2 * (runiform() - 0.5) 
gen y1 = 2 * (runiform() - 0.5)

twoway  (scatter x1 y1 if (x1^2 + y1^2 < 1) ///
        , graphregion(color(white)) xtitle("") ytitle("") ///
        yscale(lstyle(none)) xscale(lstyle(none)) aspect(1)  ///
        ylabel(none, nolabels noticks nogrid) xlabel(none, nolabels noticks nogrid))

Following a suggestion in a comment by Nick Cox, here is a code that generates a given number of dots randomly on a circle.

clear 
set seed 1010101
set obs 10000
gen obs = _n
gen N = _N
gen y = sqrt(runiform())
gen angle = obs * 2 * _pi / N

gen obsx = (y * cos(angle))
gen obsy = (y * sin(angle))

* Keep required number of dots
generate random = runiform()
sort random
keep if _n <= 250

twoway scatter obsx obsy, graphregion(color(white)) xtitle("") ytitle("") ///
            yscale(lstyle(none)) xscale(lstyle(none)) ysize(1) xsize(1) ///
            ylabel(none, nolabels noticks nogrid) xlabel(none, nolabels noticks nogrid)  

enter image description here

Here is an answer that 1) generalizes for any bounding radius (which may not be useful for you); and 2) abstracts away from explicitly using N.


clear 
set seed 101010
set obs 250
gen obs = _n
scalar R = 1 // set the  bounding radius
gen y = R * sqrt(runiform()) // random "sub" radius
gen angle = runiform() * 2 * _pi

gen obsx = y * cos(angle)
gen obsy = y * sin(angle)

twoway scatter obsx obsy, msize(tiny) graphregion(color(white)) xtitle("") ytitle("") ///
            yscale(lstyle(none)) xscale(lstyle(none)) ysize(1) xsize(1) ///
            ylabel(none, nolabels noticks nogrid) xlabel(none, nolabels noticks nogrid)  
            
Related