I am trying to create a custom function that extends ggplot2. The goal of the function is to superimpose a mean with horizontal and vertical standard errors. The code below does the entire thing.
library(plyr)
library(tidyverse)
summ <- ddply(mtcars,.(),summarise,
dratSE = sqrt(var(drat))/length(drat),
mpgSE = sqrt(var(mpg))/length(mpg),
drat = mean(drat),
mpg = mean(mpg))
ggplot(data = mtcars, mapping = aes(x = drat, y = mpg)) +
geom_point(shape = 21, fill = 'black', color = 'white', size = 3) +
geom_errorbarh(data = summ, aes(xmin = drat - dratSE, xmax = drat + dratSE)) +
geom_errorbar(data = summ, aes(ymin = mpg - mpgSE, ymax = mpg+mpgSE), width = .1) +
geom_point(data = summ, color='red',size=4)
Ideally, it would only take a function such as geom_scattermeans()
to do this whole thing. But I am not sure how the aesthetics get transferred into subsequent geom
functions from ggplot()
.
Also I've had difficulties in making a function that receives column names as argument and making it work with ddply()
.
Since my first answer is still the easier solution, I decieded to keep it. This answer should get OP closer to their goal.
Building a ggproto object can be cumbersome depending on what you are trying to do. In your case you are combining 3
ggproto
Geoms
classes together with the possibility of a newStat
.The three Geoms are:
GeomErrorbar
GeomErrorbarh
GeomPoint
To get started, sometimes you just need to inherit from one of the classes and overwrite the method, but to pool the three together you will need to do more work.
Lets first consider how each of these
Geoms
draw theirgrid
objects. Depending on theGeom
it is in one of these functionsdraw_layer()
,draw_panel()
, anddraw_group()
. Fortunately, each of the geoms we want to use only usedraw_panel()
which mean a bit less work for us - we will just call these methods directly and build a newgrobTree
object. We will just need to be careful that all the correct parameters are making it to our newGeom
'sdraw_panel()
method.Before we get to writing our own
draw_panel
, we have to first considersetup_params()
andsetup_data()
functions. Occasionally, these will modify the data right out the gate. These steps are usually helpful to have automatic processing here and are often used to standardize/transform the data. A good example isGeomTile
andGeomRect
, they are essentially the sameGeom
s but theirsetup_data()
functions differ because they are parameterized differently.Lets assume you only want to assign an
x
and ay
aesthetic, and leave the calculations ofxmin
,ymin
,xmax
, andymax
to the geoms/stats.Fortunately,
GeomPoint
just returns the data with no modifications, so we will need to incorporateGeomErrorbar
andGeomErrorbarh
'ssetup_data()
first. To skip some steps, I am just going to make a newStat
that will take care of transforming those values for us within acompute_group()
method.A note here,
GeomErrorbar
andGeomErrorbarh
allow for another parameter to be included -width
andheight
respectively, which controls how wide the flat portions of the error bars are.also, within these functions, each will make their own
xmin
,xmax
,ymin
,ymax
- so we will need to distinguish these parameters.First load required information into the namespace
Start with new
Stat
, I've decided to call it aPointError
Now for the fun part, the
Geom
, again I'm going forPointError
as a consistent name.Last, we need a function for the user to call that will make a
Layer
object.Now we can test if this is working properly
Created on 2021-05-18 by the reprex package (v1.0.0)
There is obviously so much more you could do with this, from including additional default aesthetics such that you could control the color and size of the lines/points separately (may want to override
GeomPointError$setup_data()
to insure everything maps correctly).Finially, this geom is pretty naive in that it assumes the
x
andy
data mappings are continuous. It still works with mixing continuous and discrete, but looks a bit funky