-1

Is it possible to draw real solid circle with a radius in "user" coordinates?

I tried the following:

Polygons: I don't want to use them because I need real circles in the resulting svg.

Segments

segments(x, y, x, y, lwd=px, lend=0)

With segments there is the problem that I don't find a way to specify the segment in "user" coordinates.

The resulting graph is at the end exported to PDF.

Update I draw a graph with a lot of elements and the elements has a distinct width. The width of the elements depends on the width at the x-axis. If I don't use user coordinates the result in the PDF is not correct in dependence to the x-axis.

A Polygon is an approximation to a circle and if I use them the result e.g. PDF is very large and the performance is not good and memory usage is very high. I draw 10,000 circles and more on one graph.

I use the following code with the described performance problems:

circle <- function(x, y, r, col) {
  edgeCount <- 50
  intervals <- (1:edgeCount) / edgeCount * 2 * pi
  for(i in 1:length(x)) {
    polygon(r[i]*sin(intervals) + x[i], r[i]*cos(intervals) + y[i], col=col[i],border=NA)
  }
}
makurisan
  • 467
  • 3
  • 13
  • 3
    What is a "flooded circle" and what are "user units"? – John Coleman Jun 24 '19 at 16:11
  • Is this in base or grid/ggplot? Or something else? And you bring up `svg`, how are you saving it, with `grDevices::svg()` or some other way? Do you need the circle to show up on the plot window in R and the svg, or would adding it to the svg file be enough? This would be a much better question if you'd add a little bit of sample code setting up a plot an saving it so there is a starting point for anyone who wants to answer... – Gregor Thomas Jun 24 '19 at 16:12
  • @JohnColeman "User units" or "user coordinates" is a common term to distinguish from "data units" or "data coordinates". A circle in user units will look like a circle to the user regardless of the data aspect ratio of the plot, whereas a circle in data units may look like an ellipse if the aspect ratio is not 1. – Gregor Thomas Jun 24 '19 at 16:14
  • I use base but if it works, I can use grid or ggplot. – makurisan Jun 24 '19 at 16:19
  • 1
    And also, have you tried the solutions at these possible duplicates? [plot - drawing circle in R](https://stackoverflow.com/q/22265704/903061), which recommends `plotrix::draw.circle`, and [draw a circle in ggplot2](https://stackoverflow.com/q/6862742/903061) – Gregor Thomas Jun 24 '19 at 16:21
  • I need the circle in svg but svg is only an example. – makurisan Jun 24 '19 at 16:21
  • @Gregor: I the example plotrix::draw.circle is not used "user" coordinates and in the "plot-drawing circle in R" there is no used a real circle. There are circles which builds a circle. – makurisan Jun 24 '19 at 16:25
  • What about just using `points()` with `pch` 16 or 19 and using `cex` to make it as big as you want? – Gregor Thomas Jun 24 '19 at 16:35
  • In regard to " draw a circle in ggplot2": The accepted Answer shows a solution which uses an approximation to describe a circle and therefore it is not a real circle when exported to svg or pdf – makurisan Jun 24 '19 at 16:36
  • Or, perhaps, `gridExtra::grid.ellipse`. User coordinates, fillable, if you had `svg`-saving code in your question I'd test it, but you don't so I'll just assume it works as a circle when exported. – Gregor Thomas Jun 24 '19 at 16:39
  • I tried gridExtra::grid.ellipse but this are polygons if you look at them. Points has the problems that the points are not specified in user coordinates. – makurisan Jun 24 '19 at 17:33

2 Answers2

1

If you're comfortable with using a wrapper for sp's SpatialLine object you can try the oceanmap package which has a quite useful function called SpatialCircle(). It essentially builds a circle via seq() and adjusts it for your center point coordinates x and y, and for your radius r. It's still a set of line segments (so not one curved line), but quite simple to use.

Result:

1

Code:

Pretty straightforward:

# Load libraries.
library(oceanmap)

# Generate plot window and data.
set.seed(1702)
plot.new()
plot.window(xlim = c(0, 20), ylim = c(0, 10), 
            asp = 1, xaxs = "i",  yaxs = "i")
axis(1)
axis(2)
box()


n <- 1000
x <- runif(n, 0, 20)
y <- runif(n, 0, 10)

for (i in 1:n) { 

    circle <- SpatialCircle(x = x[i], y = y[i], r = 0.1, n = 1000)
    lines(circle)

}

This also works with ggplot2 with some data wrangling.


Addendum: Precision of SpatialCircles

If you want to check out what n (precision) in the SpatialCircle() function really means, try the following:

nrow(circle@lines[[1]]@Lines[[1]]@coords)
Result:
[1] 1000

This means that the object has 1,000 coordinate pairs (x and y) through which a line can be drawn. Furthermore, this line will have 999 distinct line segments, as the first and the last coordinate pairs are always identical. Proof:

all.equal(circle@lines[[1]]@Lines[[1]]@coords[1, ],
          circle@lines[[1]]@Lines[[1]]@coords[1000, ])
Result:
[1] TRUE
Roman
  • 4,744
  • 2
  • 16
  • 58
0

If found a solution myself with the help of Gregor2 which did lead me to the library "grid".

library(grid)
#draw frame using normal plot
plot(0, 0, cex=0)

margins <- par("mar")

#1: bottom 2:left 3:top 4:right
mb <- unit(margins[1], "lines")
ml <- unit(margins[2], "lines")

mt <- unit(margins[3], "lines")
mr <- unit(margins[4], "lines")

#create viewport equivalent to margins in par
pushViewport(viewport(x = ml, y = mb, width = unit(1, "npc") - ml - mr, height = unit(1, "npc") - mb - mt, just=c("left", "bottom"), clip=TRUE))

#draw circle in npc units (easily convertable to user units using grconvertX)
grid.draw(circleGrob(x=0.5, y=0.5, r=0.5, default.units="npc", gp=gpar(col="blue", fill="blue")))

popViewport()
makurisan
  • 467
  • 3
  • 13