Generating a circle matrix image

#1
Hi all,
Code:
# Suppose I have a 200 by 200 matrix with zeros entry
a<- matrix(0,nrow=200,ncol=200)

#I want to draw a shaded circle on this matrix using binary 1 and 0.
 
# Defining a coordinate as my centre of the circle, e.g.(100,100)
y.cent <- 100
x.cent <- 100

#Suppose I want my radius be 10 unit.
r=10

#I do the following,
xx <- x.cent + r*cos( seq(0,2*pi, length.out=360) )
yy <- y.cent + r*sin( seq(0,2*pi, length.out=360) )
a[xx,yy]=1
image(a)
I can't seem to arrive at my desired result. I got a rectangle instead. :(

Anyone can share your thoughts ? :)
Any methods will do as long as the shaded circle appears on this simulated grid matrix a.
 
Last edited by a moderator:

bryangoodrich

Probably A Mammal
#2
Maybe it has something to do with image? I would test by creating an actual circle (simplified example) and see if it does what you want it to do. Then you can generalize your approach. I'd also create a function to perform the actions like,

Code:
drawImage <- function(mat, center, radius) {
  grid <- mat
  x.index <- center + radius * cos(seq(0, 2*pi, length = 360))
  y.index <- center + radius * sin(seq(0, 2*pi, length = 360))
  grid[x.index, y.index] <- 1
  image(grid)
}  # end drawImage

drawImage(matrix(0, 200, 200), 100, 10)  # call example
Though, if your matrix is 200 cells across (100 from radius), aren't your indexes meaningless when indicating 360 different values? Granted, the index has to be a whole number, so many of them will overlap, no doubt. I wonder if your algorithm is making enough "curving" to make a "smoother" transition around the edges of the "circle" you want to make.
 

bryangoodrich

Probably A Mammal
#3
Well, your algorithm produces a circle.

Code:
drawCircle <- function(center, radius) {
  j <- center + radius * cos(seq(0, 10*pi, length = 360))
  k <- center + radius * sin(seq(0, 10*pi, length = 360))
  plot(NULL, type = "n", xlab = "", ylab = "", xlim = range(j, k), ylim = range(j, k))
  matlines(j, k)
}
drawCircle(100, 10)
Therefore, my guess is that it has to do with either the way things are indexed in the grid or with the way image interprets your grid. My guess is the latter. Maybe image isn't the right function, or you need to play with its parameters. I've never even seen the function before today, so look into it.
 

Dason

Ambassador to the humans
#4
No. It has everything to do with this line:
Code:
a[xx, yy] <- 1
R takes the cartesian product of the elements in xx and yy and uses every index in there.

Just like how if you say something like:
Code:
a <- matrix(1:4, 2, 2)
a[1:2, 1:2]
You get all of "a" back (not just the elements a[1,1], a[2,2]).

Doing a simple loop fixes the problem:
Code:
for(i in 1:length(xx)){
   a[xx[i], yy[i]] <- 1
}
 

bryangoodrich

Probably A Mammal
#5
Oh snap, that does work:

Code:
drawImage <- function(mat, center, radius) {
  grid <- mat
  x.index <- center + radius * cos(seq(0, 2*pi, length = 360))
  y.index <- center + radius * sin(seq(0, 2*pi, length = 360))

  for (i in seq(x.index))
    grid[x.index[i], y.index[i]] <- 1

  image(grid)
}  # end drawImage

drawImage(matrix(0, 200, 200), 100, 10)  # call example
But what if we wanted to fill the circle?
 

Dason

Ambassador to the humans
#6
At that point I'd probably just write a loop to figure out the edge of the circle in terms of the x axis and then loop through and fill in the appropriate y values with a 1.

Yeah that was very non specific but essentially it's easy to figure out the edge of the circle (center - radius, center + radius). For a given x value it's easy to figure out which y values fall inside the circle. Fill all of those pairs in with a 1.
 

bryangoodrich

Probably A Mammal
#8
Well, Dason aptly described the logic to filling in the circle. What I wonder is if there's a vectorized way to do it--say, use the boundaries at a given x/y value and extract the appropriate vector. It might require a loop through one dimension with a condition for checking what vector subset to extract from the cross-dimension; repeat for each point along the segment of the dimension.
 

TheEcologist

Global Moderator
#9
if there's a vectorized way to do it--say
What do you mean?

Something like this?

Code:
# Circle outline only
DrawMeACircle= function(x, y, r, col) { 	
    lines( (cos(seq(0, 2*pi, pi/180)) * r) + x, (sin(seq(0, 2*pi, pi/180)) *
    r) + y , col=col )
}

# blank canvas
plot(0,0,col="white",xlim=c(-40,40),ylim=c(-40,40))
# Bob Ross with R: making a happy circle
DrawMeACircle(0,0,20,col='red')

# Filled circle
DrawMeAFilledCircle= function(x, y, r, col) { 
 polygon( (cos(seq(0, 2*pi, pi/180)) * r) + x, (sin(seq(0, 2*pi, pi/180)) *
    r) + y , col=col )
}

# blank canvas
plot(0,0,col="white",xlim=c(-40,40),ylim=c(-40,40))
# Bob Ross with R: making a happy circle
DrawMeAFilledCircle(0,0,20,col='red')
 

TheEcologist

Global Moderator
#10
I can't seem to arrive at my desired result. I got a rectangle instead. :(

Anyone can share your thoughts ? :)
Any methods will do as long as the shaded circle appears on this simulated grid matrix a.
Why dont you just do this?

Code:
x=1:200;y=x;x.cent=100;y.cent=100;r=10
A=outer(x,y,function(x,y) sqrt(((x-x.cent)^2)+((y-y.cent)^2)))
image(x,y,A<r)
Credit for the formula goes to our good friend Euclid of Alexandria (+- 300 BC)
 
#11
Code:
x=1:200;y=x;x.cent=100;y.cent=100;r=10
A=outer(x,y,function(x,y) sqrt(((x-x.cent)^2)+((y-y.cent)^2)))
image(x,y,A<r)
Hi thanks for your help.

My priority of doing this is to set a matrix of 1 and 0 with 1 falling in the circle.

I guess this will help me

Code:
circle<-ifelse((A<r),1,0)
 
Last edited:

TheEcologist

Global Moderator
#12
Sure the data is distances to the circle center and this is stored in object A. You can change this to 'ones and zeros' by doing this;

Code:
as.numeric(A<r)
#where r is an arbitrary circle radius
Then just store it as an object.