[R] ggplot2 with an arbitrary number of curves from geom_function + legend?

Jeff Newmiller jdnewm|| @end|ng |rom dcn@d@v|@@c@@u@
Mon Feb 28 08:53:51 CET 2022


Well, the ggplot2 CRAN page [1] points people to [2], which in turn points out that support can be found on the RStudio community forums and StackOverflow, so there is a path from here (where contributed packages are off-topic per the Posting Guide) to getting help.

I will point out that the canonical solution is definitely to put all of your data into one long-form data frame and use a factor column to distinguish aesthetics (one google result is [3]) ... loops really don't work well to add layers to ggplots.

But yes, if you have further questions on a contributed package, do follow the breadcrumbs from CRAN for sources of help, and come back when your question is about the R language.

[1] https://cran.r-project.org/web/packages/ggplot2/index.html
[2] https://ggplot2.tidyverse.org/
[3] https://stackoverflow.com/questions/64523271/how-to-insert-a-legend-in-a-ggplot-with-multiple-time-series

On February 27, 2022 10:00:31 PM PST, Avi Gross via R-help <r-help using r-project.org> wrote:
>I would reply but since ggplot was mentioned, I must abstain. ;-)
>
>I will say that you can use ggplot in a loop in some cases if you do this:
>
>p <- ggplot(...) + ...
>
>Then you can in your loop keep adding to p as in:
>
>p <- p + geom_whatever() + ...
>
>You do at some point need to make p print itself and generate a graph. Until then, it can be amended, albeit some changes undo or overwrite earlier ones if not done carefully.
>
>Having said all that, there is often a way to do a kind of looping within ggplot by say grouping your data and having it draw things grouped, or say making multiple vertical (or horizontal) lines by supplying a vector of positions.
>
>But as noted, this is not considered a good place by some to discuss this, so forget I said anything.
>
>
>
>
>-----Original Message-----
>From: Michael Bonert <michael.bonert using alumni.utoronto.ca>
>To: r-help using r-project.org <r-help using r-project.org>
>Sent: Sun, Feb 27, 2022 8:02 pm
>Subject: [R] ggplot2 with an arbitrary number of curves from geom_function + legend?
>
>Dear R-help,
>
>I am trying to create a ggplot with an arbitrary number of curves + legend.
>
>The plot should contain:
>1. data points + a line that is either user defined *or* represents the median of the data points
>2. an arbitrary number of confidence intervals (CIs) around the line, where the CIs are defined by a function
>
>#1: this is easy enough
>#2: I don't know how to combine this with #1
>
>I can write #2 as a loop (see below) but it is then seems to be impossible to get ggplot to do a proper legend.
>
>The challenge I have seems similar to this problem:
>https://stackoverflow.com/questions/12169289/ggplot2-fail-to-apply-color-with-scale-fill-manual-inside-a-loop
>
>I read that one should not use a loop with ggplot ( https://stackoverflow.com/questions/62603533/adding-ggplot2-legend-with-many-lines-using-for-loop ).
>(Interesting: there are probably a half dozen posts on ggplot + loops floating around on the web.  I do not feel alone in my problem... but I also do not think I am close to solving it.)
>(As a user of GNU/Octave ( octave.org ) using a loop seems the intuitive solution. In GNU/Octave one does a "hold on" and then plots however many lines/objects one wants within a figure.)
>
>Is there a way to freeze the 'scale_colour_manual' attribute?
>(The way the code is written: the colour scale seems to be overwritten with the 'fp=fp ...' statement)
>(I have gotten the message: "Scale for 'colour' is already present. Adding another scale for 'colour',
>which will replace the existing scale.")
>
>Loop aside:
>Is there a way to elegantly pipe an arbitrary number of 'geom_function' calls to the 'ggplot'?
>(I wondered whether the '%>%' operator in 'dplyr' is a possible solution -- as suggested here:
>https://stackoverflow.com/questions/30655364/ggplot2-getting-a-color-legend-to-appear-using-stat-function-in-a-for-loop )
>
>
>I could write code to generate a data frame that has the data points and points for arbitrary curves; however,
>this would necessitate writing a function that replicates 'geom_function'.
>
>Is there a way to generate the text string and then execute it?
>( https://stackoverflow.com/questions/1743698/evaluate-expression-given-as-a-string )
>(In my humble opinion: this would be a hack.)
>
>Is there a way to generate a legend with 'override.aes'?
>( https://www.r-bloggers.com/2020/07/controlling-legend-appearance-in-ggplot2-with-override-aes/ )
>
>
>Below is the attempt at creating a legend:
>~~
>  # plot the data points
>  fp = ggplot(df,aes(x=x_var, y=y_var), colour4labels[num_of_funnels+2]) + geom_point(size=4, na.rm = TRUE, alpha = 0.75) + theme(legend.position="bottom") + scale_color_manual(labels = legend_labels, values = colour4labels) + guides(color=guide_legend("Control Limits")) + geom_hline(aes(yintercept = funnel_centre_line, colour = colour4labels[num_of_funnels+1]), linetype = 2) + xlab(x_label) + ylab(y_label) + ggtitle(plot_title) + theme(axis.title=element_text(face="bold"), plot.title = element_text(size = 14, face = "bold", hjust = 0.5))
>
>  # add funnel plot curves (limits)
>  for (ci_ctr in 1:length(limits)) {
>    if (ci_ctr==1) {
>      fp = fp + geom_function(fun = calc_fpc, args = list(ci_or_alpha = limits[ci_ctr], probability = funnel_centre_line, upper_or_lower = 1, trunc_val = 0), aes(colour = colour4labels[ci_ctr]), size = 1.1, na.rm = TRUE, linetype = 5) + geom_function(fun = calc_fpc, args = list(ci_or_alpha = limits[ci_ctr], probability = funnel_centre_line, upper_or_lower = 2, trunc_val = 0), aes(colour = colour4labels[ci_ctr]), size = 1.1, na.rm = TRUE, linetype = 5) + theme(legend.position="bottom") + scale_color_manual(labels = legend_labels, values = colour4labels) + guides(color=guide_legend("Control Limits"))
>
>    } else if (ci_ctr==2) {
>      fp = fp + geom_function(fun = calc_fpc, args = list(ci_or_alpha = limits[ci_ctr], probability = funnel_centre_line, upper_or_lower = 1, trunc_val = 0), aes(colour = colour4labels[ci_ctr]), size = 1.3, na.rm = TRUE) + geom_function(fun = calc_fpc, args = list(ci_or_alpha = limits[ci_ctr], probability = funnel_centre_line, upper_or_lower = 2, trunc_val = 0), aes(colour = colour4labels[ci_ctr]), size = 1.3, na.rm = TRUE) + theme(legend.position="bottom") + scale_color_manual(labels = legend_labels, values = colour4labels) + guides(color=guide_legend("Control Limits"))
>
>    } else {
>      fp = fp + geom_function(fun = calc_fpc, args = list(ci_or_alpha = limits[ci_ctr], probability = funnel_centre_line, upper_or_lower = 1, trunc_val = 0), aes(colour = colour4labels[ci_ctr]), na.rm = TRUE, linetype = 5) + geom_function(fun = calc_fpc, args = list(ci_or_alpha = limits[ci_ctr], probability = funnel_centre_line, upper_or_lower = 2, trunc_val = 0), aes(colour = colour4labels[ci_ctr]), na.rm = TRUE, linetype = 5) + theme(legend.position="bottom") + scale_color_manual(labels = legend_labels, values = colour4labels) + guides(color=guide_legend("Control Limits"))
>    }
>  }
>~~
>
>Code without elements to generate a legend (that otherwise does what I want it to):
>~~
>  # plot the data points
>  fp = ggplot(df,aes(x=x_var, y=y_var)) + geom_point(size=4, na.rm = TRUE, colour = "blue", alpha = 0.75) + theme_bw()
>
>  # add centre line, axis labels and plot title
>  fp = fp + geom_hline(aes(yintercept = funnel_centre_line), linetype = 2, colour = "black") + xlab(x_label) + ylab(y_label) + ggtitle(plot_title) + theme(axis.title=element_text(face="bold"), plot.title = element_text(size = 14, face = "bold", hjust = 0.5))
>
>  # add funnel plot curves (limits)
>  for (ci_ctr in 1:length(limits)) {
>    if (ci_ctr==1) {
>      fp = fp + geom_function(fun = calc_fpc, args = list(ci_or_alpha = limits[ci_ctr], probability = funnel_centre_line, upper_or_lower = 1, trunc_val = 0), colour = colour4labels[ci_ctr], size = 1.1, na.rm = TRUE, linetype = 5) + geom_function(fun = calc_fpc, args = list(ci_or_alpha = limits[ci_ctr], probability = funnel_centre_line, upper_or_lower = 2, trunc_val = 0), colour = colour4labels[ci_ctr], size = 1.1, na.rm = TRUE, linetype = 5)
>
>    } else if (ci_ctr==2) {
>      fp = fp + geom_function(fun = calc_fpc, args = list(ci_or_alpha = limits[ci_ctr], probability = funnel_centre_line, upper_or_lower = 1, trunc_val = 0), colour = colour4labels[ci_ctr], size = 1.3, na.rm = TRUE) + geom_function(fun = calc_fpc, args = list(ci_or_alpha = limits[ci_ctr], probability = funnel_centre_line, upper_or_lower = 2, trunc_val = 0), colour = colour4labels[ci_ctr], size = 1.3, na.rm = TRUE)
>
>    } else {
>      fp = fp + geom_function(fun = calc_fpc, args = list(ci_or_alpha = limits[ci_ctr], probability = funnel_centre_line, upper_or_lower = 1, trunc_val = 0), colour = colour4labels[ci_ctr], na.rm = TRUE, linetype = 5) + geom_function(fun = calc_fpc, args = list(ci_or_alpha = limits[ci_ctr], probability = funnel_centre_line, upper_or_lower = 2, trunc_val = 0), colour = colour4labels[ci_ctr], na.rm = TRUE, linetype = 5)
>    }
>  }
>~~
>
>Happy to post the complete code. I was thinking it might be a contribution--if deemed non-trivial.
>(I also have a test function that runs the code with a data set already in r-cran.)
>
>Take Care,
>Michael Bonert, BASc, MASc, MD, FRCPC
>
>PS -
>Environment details:
> R version: 4.0.4 (2021-02-15)
> Platform: Debian GNU/Linux 11 (stable)
>
>I am trying to generate R code similar to that in this paper: https://www.ncbi.nlm.nih.gov/pmc/articles/PMC8219089/
>(If you want to know where I am coming from: it is in that paper.)
>
>The code I wrote is somewhat similar to the package 'FunnelPlotR' ( https://cran.rstudio.com/web/packages/FunnelPlotR/index.html ). I did look at the code in that package.
>
>    [[alternative HTML version deleted]]
>
>______________________________________________
>R-help using r-project.org mailing list -- To UNSUBSCRIBE and more, see
>https://stat.ethz.ch/mailman/listinfo/r-help
>PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
>and provide commented, minimal, self-contained, reproducible code.
>
>______________________________________________
>R-help using r-project.org mailing list -- To UNSUBSCRIBE and more, see
>https://stat.ethz.ch/mailman/listinfo/r-help
>PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
>and provide commented, minimal, self-contained, reproducible code.

-- 
Sent from my phone. Please excuse my brevity.



More information about the R-help mailing list