I want to create a new Geom type: geom_ohlc(), which is something like Candlestick Charts, to plot the stock open-high-low-close data.
After learning this Hadley's article: I tried this:
GeomOHLC <- ggproto(`_class` = "GeomOHLC", `_inherit` = Geom,
required_aes = c("x", "op", "hi", "lo", "cl"),
draw_panel = function(data, panel_scales, coord){
coords <- coord$transform(data, panel_scales)
browser() # <<-- here is where I found the problem
grid::gList(
grid::rectGrob(
x = coords$x,
y = pmin(coords$op, coords$cl),
vjust = 0,
width = 0.01,
height = abs(coords$op - coords$cl),
gp = grid::gpar(col = coords$color, fill = "yellow")
),
grid::segmentsGrob(
x0 = coords$x,
y0 = coords$lo,
x1 = coords$x,
y1 = coords$hi
)
)
})
geom_ohlc <- function(data = NULL, mapping = NULL, stat = "identity", position = "identity", na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, ...)
{
layer(
geom = GeomOHLC, mapping = mapping, data = data,
stat = stat, position = position, show.legend = show.legend,
inherit.aes = inherit.aes, params = list(na.rm = na.rm, ...)
)
}
dt <- data.table(x = 1:10, open = 1:10, high = 3:12, low = 0:9, close = 2:11)
p <- ggplot(dt, aes(x = x, op = open, hi = high, lo = low, cl = close)) +
geom_ohlc()
p
for simplicity, i just do not consider the color of bar.
The result plot is like this:
I add a browser()
inside the ggproto
function, and I found that the coord$transform
did not transform the op
, hi
, lo
, cl
aesthetics into interverl [0,1]. How to fix this problem ?
Moreover, is there any other documents about how to create your own Geom type except that Hadley's article ?
As mentioned in the comments under the OP's question the problem is aes_to_scale()
function inside transform_position()
, which in turn is called by coord$transform
. Transformations are limited to variables named x, xmin, xmax, xend, xintercept
and the equivalents for y axis. This is mentioned in the help for transform_position:
Description
Convenience function to transform all position variables.
Usage
transform_position(df, trans_x = NULL, trans_y = NULL, ...) Arguments
trans_x, trans_y Transformation functions for x and y aesthetics. (will transform x, xmin, xmax, xend etc) ... Additional arguments passed to trans_x and trans_y.
A workaround would be to use those variable names instead of the variable names used by the OP. The following code works in transforming the variables but it fails at somewhere else (see at the end). I do not know the details of the intended plot, so didn't try to fix this error.
GeomOHLC <- ggproto(
`_class` = "GeomOHLC",
`_inherit` = Geom,
required_aes = c("x", "yintercept", "ymin", "ymax", "yend"),
draw_panel = function(data, panel_scales, coord) {
coords <- coord$transform(data, panel_scales)
#browser() # <<-- here is where I found the problem
grid::gList(
grid::rectGrob(
x = coords$x,
y = pmin(coords$yintercept, coords$yend),
vjust = 0,
width = 0.01,
height = abs(coords$op - coords$cl),
gp = grid::gpar(col = coords$color, fill = "yellow")
),
grid::segmentsGrob(
x0 = coords$x,
y0 = coords$ymin,
x1 = coords$x,
y1 = coords$ymax
)
)
}
)
geom_ohlc <-
function(data = NULL,
mapping = NULL,
stat = "identity",
position = "identity",
na.rm = FALSE,
show.legend = NA,
inherit.aes = TRUE,
...)
{
layer(
geom = GeomOHLC,
mapping = mapping,
data = data,
stat = stat,
position = position,
show.legend = show.legend,
inherit.aes = inherit.aes,
params = list(na.rm = na.rm, ...)
)
}
dt <-
data.table(
x = 1:10,
open = 1:10,
high = 3:12,
low = 0:9,
close = 2:11
)
p <-
ggplot(dt, aes(
x = x,
yintercept = open,
ymin = high,
ymax = low,
yend = close
)) +
geom_ohlc()
p
This transforms the variables but produces the following error:
Error in unit(height, default.units) :
'x' and 'units' must have length > 0
But hopefully from here it can be made to work.
NOTE: I chose the mapping between the original variable names (op, hi, lo, cl) rather arbitrarily. Specially yintercept
does not seem to fit well. Maybe there is need to support arbitrary scale variable names in ggplot2?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With