[R] ggplot with arrows

Paul Murrell
Sun, 03 Aug 2025 21:00:44 -0000

Hi

At the risk of being labelled a "purist", you do not have to leave R
to
gain access to the underlying components and modify them.

The following code combines Rui's tidy up of the ggplot() call with an
example of directly modifying the underlying 'grid' grob to add arrows
to the ends.  There are more arguments in arrow() that you can explore
if you want to.


library(ggplot2)
library(grid)

ggplot() +
   stat_function(
     fun = function(x) x^2,
     color = "blue", linewidth = 1.25,
     xlim = c(-5, 5)
   ) +
   theme_linedraw()

grid.force()
## Check the name of the line grob
## grid.ls()
grid.edit("GRID.polyline", grep=TRUE,
           arrow=arrow(ends="both"))


Hope that helps.

Paul


On 2/08/2025 3:24 am, Rui Barradas wrote:
> On 8/1/2025 4:15 PM, Rui Barradas wrote:
>> On 8/1/2025 3:43 PM, Ebert,Timothy Aaron wrote:
>>> I would save the graph as a PowerPoint object and then edit it in
>>> PowerPoint.
>>> library(ggplot2)
>>> library(grid)
>>> library(officer)
>>> library(rvg)
>>> x <- seq(-5, 5, length.out = 100)
>>> y <- x^2
>>> data <- data.frame(x, y)
>>> plot <- ggplot(data, aes(x, y)) +
>>> ?? geom_path(color = "blue", linewidth = 1.25) +
>>> ?? geom_segment(
>>> ???? aes(x = x[1], y = y[1], xend = x[100], yend = y[100]),
>>> ???? arrow = arrow(angle = 20, type = "closed", ends =
"both", length
>>> = unit(0.2, "inches")),
>>> ???? color = "red"
>>> ?? ) +
>>> ?? theme_linedraw()
>>> doc <- read_pptx()
>>> doc <- add_slide(doc, layout = "Title and Content",
master = "Office
>>> Theme")
>>> doc <- ph_with(doc, dml(ggobj = plot), location =
>>> ph_location_fullsize())
>>> print(doc, target = "quadratic_with_arrows.pptx")
>>>
>>> If I remember I think you have to ungroup it in PowerPoint and then
>>> all elements become editable. The general approach can be done with
>>> other file formats/programs, not just PowerPoint.
>>> Tim
>>>
>>> -----Original Message-----
>>> From: R-help <r-help-bounces at r-project.org> On Behalf Of
Thomas Subia
>>> via R-help
>>> Sent: Friday, August 1, 2025 10:31 AM
>>> To: r-help at r-project.org
>>> Subject: [R] ggplot with arrows
>>>
>>> [External Email]
>>>
>>> Consider:
>>>
>>> x <- seq(-5,5,length.out = 100)
>>> y <- x^2
>>> data <- data.frame(x,y)
>>> library(ggplot2)
>>> ggplot(data,aes(x,y))+
>>> ?? stat_function(
>>> ???? fun = function(x) x^2,
>>> ???? color = "blue", linewidth = 1.25
>>> ?? ) +
>>> ?? theme_linedraw()
>>> I'd like to add an arrow to the ends of curve to illustrate the
curve
>>> continues indefinitely in that direction, ChatGPT suggests using
>>> geom_segment or geom_link but there has an easier way to do this.
>>>
>>> Any suggestions would be appreciated.
>>>
>>>
>>> ???????? [[alternative HTML version deleted]]
>>>
>>> ______________________________________________
>>> R-help at r-project.org mailing list -- To UNSUBSCRIBE and more,
see
>>> https://stat.ethz.ch/mailman/listinfo/r-help
>>> PLEASE do read the posting guide https://www.r-project.org/posting-
>>> guide.html
>>> and provide commented, minimal, self-contained, reproducible code.
>>>
>>> ______________________________________________
>>> R-help at r-project.org mailing list -- To UNSUBSCRIBE and more,
see
>>> https://stat.ethz.ch/mailman/listinfo/r-help
>>> PLEASE do read the posting guide https://www.R-project.org/posting-
>>> guide.html
>>> and provide commented, minimal, self-contained, reproducible code.
>> Hello,
>>
>> First of all, according to the documentation ?stat_function, section
>> Arguments,
>>
>>
>> data
>> Ignored by stat_function(), do not use.
>>
>>
>> As for the arrows, first get the equations of the lines tangent to the
>> end points of the parabola,
>>
>> y = -10*x - 25
>> y = 10*x - 25
>>
>> then compute segments' end points and plot.
>>
>>
>> f <- function(x, b = -25, m) m*x + b
>> arrow_data <- data.frame(
>> ?? id = c("n", "p"),
>> ?? x = c(-5, 5),
>> ?? y = f(c(-5, 5), m = c(-10, 10)),
>> ?? xend = c(-6, 6),
>> ?? yend = f(c(-6, 6), m = c(-10, 10))
>> )
>>
>> ggplot() +
>> ?? stat_function(
>> ???? fun = function(x) x^2,
>> ???? color = "blue", linewidth = 1.25,
>> ???? xlim = c(-5, 5)
>> ?? ) +
>> ?? geom_segment(
>> ???? data = arrow_data,
>> ???? mapping = aes(x = x, y = y, xend = xend, yend = yend, group = id),
>> ???? arrow = arrow(length = unit(0.5, "cm")),
>> ???? linewidth = 1.25,
>> ???? linetype = "dashed",
>> ???? inherit.aes = FALSE
>> ?? ) +
>> ?? theme_linedraw()
>>
>>
>>
>> Remove linetype and add color if you want.
>>
>> Hope this helps,
>>
>> Rui Barradas
>>
>> ______________________________________________
>> R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see
>> https://stat.ethz.ch/mailman/listinfo/r-help
>> PLEASE do read the posting guide https://www.R-project.org/posting-
>> guide.html
>> and provide commented, minimal, self-contained, reproducible code.
> Hello,
>
> Sorry, my previous code is a bit messy.
>
> You don't need to group, so I removed 'id' from the arrow_data.
> It's better to define the arrows' end points x coordinates as
variables,
> it makes it easier to change the plot at will.
>
> And the function is now defined with the intercept as last argument.
>
> f <- function(x, m, b = -25) m*x + b
>
> # here plot with linetype = "dashed"
> x0 <- c(-5, 5)
> x1 <- c(-6, 6)
> arrow_data <- data.frame(
>  ? x = x0,
>  ? y = f(x = x0, m = c(-10, 10)),
>  ? xend = x1,
>  ? yend = f(x = x1, m = c(-10, 10))
> )
>
> ggplot() +
>  ? stat_function(
>  ??? fun = function(x) x^2,
>  ??? color = "blue", linewidth = 1.25,
>  ??? xlim = c(-5, 5)
>  ? ) +
>  ? geom_segment(
>  ??? data = arrow_data,
>  ??? mapping = aes(x = x, y = y, xend = xend, yend = yend),
>  ??? arrow = arrow(length = unit(0.5, "cm")),
>  ??? linewidth = 1.25,
>  ??? linetype = "dashed",
>  ??? inherit.aes = FALSE
>  ? ) +
>  ? theme_linedraw()
>
>
> #---
>
> # here the line type is the default solid, so
> # start the arrows a bit away from the parabola, 0.1 away.
> x0 <- c(-5.1, 5.1)
> x1 <- c(-6, 6)
> arrow_data <- data.frame(
>  ? x = x0,
>  ? y = f(x = x0, m = c(-10, 10)),
>  ? xend = x1,
>  ? yend = f(x = x1, m = c(-10, 10))
> )
>
> ggplot() +
>  ? stat_function(
>  ??? fun = function(x) x^2,
>  ??? color = "blue", linewidth = 1.25,
>  ??? xlim = c(-5, 5)
>  ? ) +
>  ? geom_segment(
>  ??? data = arrow_data,
>  ??? mapping = aes(x = x, y = y, xend = xend, yend = yend),
>  ??? arrow = arrow(length = unit(0.5, "cm")),
>  ??? linewidth = 1.25,
>  ??? inherit.aes = FALSE
>  ? ) +
>  ? theme_linedraw()
>
>
> Hope this helps,
>
> Rui Barradas
>
> ______________________________________________
> R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see
> https://stat.ethz.ch/mailman/listinfo/r-help
> PLEASE do read the posting guide https://www.R-project.org/posting-
> guide.html
> and provide commented, minimal, self-contained, reproducible code.

--
Dr Paul Murrell (he/him)
Te Kura Tatauranga | Department of Statistics
Waipapa Taumata Rau | The University of Auckland
Private Bag 92019, Auckland 1142, New Zealand
64 9 3737599 x85392
paul at stat.auckland.ac.nz