1

I need to plot multiple explicit functions definitions to compare them visually.

Consider the family of functions:

fun.1 <- function(x) { 1 / ( 0.01 + x) }
fun.2 <- function(x) { 1 / ( 0.1 + x) }
fun.3 <- function(x) { 1 / ( 0.3 + x) }

The idea is to plot the result of evaluating these functions on the following inputs:

xs = c(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048)

Currently, my code is:

library(ggplot2)
library(dplyr)

xs = c(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048)

fun.1 <- function(x) { 1 / ( 0.01 + x) }
fun.2 <- function(x) { 1 / ( 0.1 + x) }
fun.3 <- function(x) { 1 / ( 0.3 + x) }

base <- ggplot(data.frame(x = xs), aes(x=as.factor(x)))

base + theme_classic() +
       theme(
          legend.position = c(.95, .95),
          legend.justification = c("right", "top"),
          legend.box.just = "right",
          legend.margin = margin(6, 6, 6, 6)
          ) +
       geom_function(fun = fun.1, colour = "red") + 
       geom_function(fun = fun.2, colour = "blue") +
       geom_function(fun = fun.3, colour = "yellow") +
       scale_x_discrete(name = "Input",
                        breaks = xs) +
       scale_y_discrete(name = "Growth")

The resulting plot is this

Now this looks ugly among other things, i can't make the legend to appear and there are warnings:

Multiple drawing groups in `geom_function()`. Did you use the correct `group`, `colour`, or `fill` aesthetics?
Multiple drawing groups in `geom_function()`. Did you use the correct `group`, `colour`, or `fill` aesthetics?
Multiple drawing groups in `geom_function()`. Did you use the correct `group`, `colour`, or `fill` aesthetics?

The style i'm trying to get is like this. Ideally, the points should be visible and connected by a continuous curve.

The question is, what is the best way to create a plot with multiple functions with a style like this ?

1

2 Answers 2

4

You can just lapply() over something and if it automatically gets added to the ggplot because it is a list. This is only useful though if the output of the lapply loop are things ggplot understands, such as geoms.

The example below assumes that the relevant function can be found using the naming structure you provided.

library(ggplot2)
library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union

xs = c(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048)

fun.1 <- function(x) { 1 / ( 0.01 + x) }
fun.2 <- function(x) { 1 / ( 0.1 + x) }
fun.3 <- function(x) { 1 / ( 0.3 + x) }

ggplot(data.frame(x = xs), aes(x=x)) + 
  lapply(1:3, function(i) {
    fun_name <- paste0("fun.", i)
    fun <- get(fun_name)
    line <- geom_function(fun = fun,
                          aes(colour = fun_name))
    points <- geom_point(aes(y = fun(xs), colour = fun_name))
    list(line, points)
  }) +
  scale_x_log10(breaks = xs, name = "Input") +
  scale_y_continuous(name = "Growth") +
  theme_classic() +
  theme(
    legend.position = c(.95, .95),
    legend.justification = c("right", "top"),
    legend.box.just = "right",
    legend.margin = margin(6, 6, 6, 6)
  )

Created on 2020-12-07 by the reprex package (v0.3.0)

Point of note, whereas your plot seems continuous in almost every way, you add the _discrete() variant of position scales which I don't understand. I converted everything to numeric instead.

Sign up to request clarification or add additional context in comments.

7 Comments

Thanks. I didn't know something like lapply() could be possible. Is it possible for the round points to be different not just by color, but also on "form"?, i mean like: round, star, square, triangle, etc. In this way the plot can also be printed in black and white.
BTW, the _discrete() thing is because i couldn't make the ticks appear at the same distance, so i started to experiment. It seems you solved that by using _log10.
However, i think the shape of the curve can be badly affected with _log10.
Sure you can add shape = fun_name inside the aes() of the geom_point(). I don't know what exactly you mean with 'badly affected'. In what way? Note that if you use as.factor(xs), the x-position under the hood is converted to 1:length(xs) since factors are integers with a levels attribute. Which seems more harmful than log-transforming the axis.
Maybe it is not that apparent in the function of my code. To see what i mean, consider this similar variation: function(x) { 1 / ( 0.01 + (0.99/x)), function(x) { 1 / ( 0.1 + (0.9/x)) }, function(x) { 1 / ( 0.3 + (0.7/x)) }. Comparing x_continuous vs x_log10 looks extremely different, when i expect something similar to what is produced by x_continuous. Is it possible to adjust this but keep ticks at same distance?.
|
0

You can also try:

library(ggplot2)
#Plot
base <- ggplot(data.frame(x = xs), aes(x=as.factor(x)))
#Plot 2
base + theme_classic() +
  theme(
    legend.position = c(.95, .95),
    legend.justification = c("right", "top"),
    legend.box.just = "right",
    legend.margin = margin(6, 6, 6, 6)
  ) +
  stat_function(fun = fun.1, aes(colour = "fun.1"),geom = 'point',size=1) + 
  stat_function(fun = fun.1, aes(colour = "fun.1"),geom = 'line') + 
  stat_function(fun = fun.2, aes(colour = "fun.2"),geom='point',size=1) +
  stat_function(fun = fun.2, aes(colour = "fun.2"),geom = 'line') +
  stat_function(fun = fun.3, aes(colour = "fun.3"),geom = 'point',size=1) +
  stat_function(fun = fun.3, aes(colour = "fun.3"),geom = 'line') +
  scale_x_discrete(name = "Input",
                   breaks = xs) +
  scale_y_discrete(name = "Growth")+
  scale_color_manual(values = c('red','blue','yellow'))

Output:

enter image description here

2 Comments

Thanks. I looked into stat_function, although didn't try to use it twice for each function. The problem is there are more points than x ticks.
@fulem You could play around the size of points or using the approach from teunbrand, in any sense I hope the code give you any useful insight!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.