Skip to content

Commit c719333

Browse files
committed
categorical variables on scatter plot axes
1 parent c5e1594 commit c719333

File tree

2 files changed

+47
-5
lines changed

2 files changed

+47
-5
lines changed

R/ggplotly.R

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,9 @@ gg2list <- function(p){
199199
layout <- list()
200200
trace.list <- list()
201201
## Before building the ggplot, we would like to add aes(name) to
202-
## figure out what the object group is later.
202+
## figure out what the object group is later. This also copies any
203+
## needed global aes/data values to each layer, so we do not have to
204+
## worry about combining global and layer-specific aes/data later.
203205
for(layer.i in seq_along(p$layers)){
204206
layer.aes <- p$layers[[layer.i]]$mapping
205207
to.copy <- names(p$mapping)[!names(p$mapping) %in% names(layer.aes)]
@@ -208,6 +210,9 @@ gg2list <- function(p){
208210
name.names <- sprintf("%s.name", mark.names)
209211
layer.aes[name.names] <- layer.aes[mark.names]
210212
p$layers[[layer.i]]$mapping <- layer.aes
213+
if(!is.data.frame(p$layers[[layer.i]]$data)){
214+
p$layers[[layer.i]]$data <- p$data
215+
}
211216
}
212217
## Extract data from built ggplots
213218
built <- ggplot2::ggplot_build(p)
@@ -221,10 +226,14 @@ gg2list <- function(p){
221226
df <- built$data[[i]]
222227

223228
## Test fill and color to see if they encode a quantitative
224-
## variable. In that case, we do not make traces for separate
225-
## colors, since there are too many!
229+
## variable. This may be useful for several reasons: (1) it is
230+
## sometimes possible to plot several different colors in the same
231+
## trace (e.g. points), and that is faster for large numbers of
232+
## data points and colors; (2) factors on x or y axes should be
233+
## sent to plotly as characters, not as numeric data (which is
234+
## what ggplot_build gives us).
226235
misc <- list()
227-
for(a in c("fill", "colour")){
236+
for(a in c("fill", "colour", "x", "y")){
228237
fun.name <- sprintf("scale_%s_continuous", a)
229238
fun <- get(fun.name)
230239
misc$is.continuous[[a]] <- tryCatch({
@@ -318,7 +327,11 @@ gg2list <- function(p){
318327
ax.list$tickfont <- theme2font(tick.text)
319328
title.text <- e(s("axis.title.%s"))
320329
ax.list$titlefont <- theme2font(title.text)
321-
ax.list$type <- "linear" ## TODO: log scales?
330+
ax.list$type <- if(misc$is.continuous[[xy]]){
331+
"linear"
332+
}else{## TODO: time scales?
333+
"category"
334+
}
322335
## Lines drawn around the plot border:
323336
ax.list$showline <- ifelse(is.blank("panel.border"), FALSE, TRUE)
324337
ax.list$linecolor <- toRGB(theme.pars$panel.border$colour)
@@ -360,6 +373,18 @@ layer2traces <- function(l, d, misc){
360373
## needed for when group, etc. is an expression.
361374
g$aes <- sapply(l$mapping, function(k) as.character(as.expression(k)))
362375

376+
## For factors on the axes, we should take the values from the
377+
## original data.
378+
for(axis.name in c("x", "y")){
379+
if(!misc$is.continuous[[axis.name]]){
380+
aes.names <- paste0(axis.name, c("", "end", "min", "max"))
381+
aes.used <- aes.names[aes.names %in% names(g$aes)]
382+
if(length(aes.used)){
383+
col.used <- g$aes[aes.used]
384+
g$data[aes.used] <- l$data[col.used]
385+
}
386+
}
387+
}
363388
## use un-named parameters so that they will not be exported
364389
## to JSON as a named object, since that causes problems with
365390
## e.g. colour.
@@ -446,6 +471,12 @@ layer2traces <- function(l, d, misc){
446471
for(data.i in seq_along(data.list)){
447472
data.params <- data.list[[data.i]]
448473
tr <- do.call(getTrace, data.params)
474+
for(v.name in c("x", "y")){
475+
vals <- tr[[v.name]]
476+
if(is.na(vals[length(vals)])){
477+
tr[[v.name]] <- vals[-length(vals)]
478+
}
479+
}
449480
name.names <- grep("[.]name$", names(data.params$params), value=TRUE)
450481
if(length(name.names)){
451482
for(a.name in name.names){

inst/tests/test-ggplot-categorical.R

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
context("categorical data on the axes")
2+
3+
d <- head(diamonds, 50)
4+
5+
test_that("axis type=category when we plot factors", {
6+
gg <- qplot(cut, price, data=d)
7+
info <- gg2list(gg)
8+
l <- info$kwargs$layout
9+
expect_identical(l$xaxis$type, "category")
10+
expect_identical(l$yaxis$type, "linear")
11+
})

0 commit comments

Comments
 (0)