Как добавить точку на точке пересечения y (ось y), используя ggplot2 - PullRequest
4 голосов
/ 21 апреля 2020

У меня есть точечная диаграмма, где масштабирование по оси Y изменяется в определенной точке, чтобы построить данные с некоторыми экстремальными значениями. Я пытаюсь добавить какую-то визуальную подсказку по оси Y, которая указывает, что масштабирование изменяется в точке.

Вот пример графика

library(scales)
library(ggplot2)

set.seed(104)

ggdata <- data.frame('x' = rep('a',100),
                     'y' = c(runif(90, 0, 20), runif(10, 90, 100)))

transformation <- trans_new(
  "my_transformation", 
  transform = function(x) ifelse(x <= 30, x / 5, (x - 30) / 20 + 30 / 5),
  inverse = function(x) ifelse(x <= 30 / 5, x * 5, (x - 30 / 5) * 20 + 30)
)

ggplot(data = ggdata) + 
  geom_jitter(aes(x = x, y = y)) +
  scale_y_continuous(trans = transformation, breaks = c(0, 10, 20, 30, 50, 70, 90, 110))  

scatter plot

Я хочу добавить маркер к отметке 30 на оси Y для изменения масштаба.

Я думал о добавлении двойной отметки на оси, но нет linetype, который выглядит как двойная линия. Продукт должен выглядеть примерно так: this . Мне известны такие преобразования, как scale_y_log10, но я бы предпочел работать с пользовательским масштабированием, которое динамически изменяется с данными.

РЕДАКТИРОВАТЬ: согласно предложению @ Tjebo, я использовал annotate для добавления "= "до точки останова оси Y:

library(scales)
library(ggplot2)

set.seed(104)

ggdata <- data.frame('x' = rep('a',100),
                     'y' = c(runif(90, 0, 20), runif(10, 90, 100)))

transformation <- trans_new(
  "my_transformation", 
  transform = function(x) ifelse(x <= 30, x / 5, (x - 30) / 20 + 30 / 5),
  inverse = function(x) ifelse(x <= 30 / 5, x * 5, (x - 30 / 5) * 20 + 30)
)

mybreaks <- c(0, 10, 20, 30, 50, 70, 90, 110)
tick_linetype <- rep("solid", length(mybreaks))
tick_linetype[4] <- "blank"

ggplot(data = ggdata) + 
  geom_jitter(aes(x = x, y = y)) +
  annotate(geom = "point", shape = "=", x = -Inf, y = 30, size = 3) +
  scale_y_continuous(trans = transformation, breaks = mybreaks) +
  theme(axis.ticks.y = element_line(linetype = tick_linetype)) + 
  coord_cartesian(clip = 'off')

solution

Ответы [ 3 ]

2 голосов
/ 21 апреля 2020

Я думал о добавлении двойного тика на оси, но нет типа линии, который выглядит как двойная линия.

Вы можете использовать любой символ в качестве точечной формы. Также знак равенства, или обратно sla sh, et c.

Например:

library(scales)
library(ggplot2)

set.seed(104)

ggdata <- data.frame('x' = rep('a',100),
                     'y' = c(runif(90, 0, 20), runif(10, 90, 100)))

transformation <- trans_new(
  "my_transformation", 
  transform = function(x) ifelse(x <= 30, x / 5, (x - 30) / 20 + 30 / 5),
  inverse = function(x) ifelse(x <= 30 / 5, x * 5, (x - 30 / 5) * 20 + 30)
)

ggplot(data = ggdata) + 
  geom_jitter(aes(x = x, y = y)) +
  annotate(geom = "point", shape = "=", x = -Inf, y = 30, size = 8, color = 'red') +
  scale_y_continuous(trans = transformation, breaks = c(0, 10, 20, 30, 50, 70, 90, 110))+
  coord_cartesian(clip = 'off')

Я удалил вырезку, но вы также можете оставить ее. Цвет был просто выбран для выделения.

Или, что еще лучше, используйте текстовую аннотацию. Затем вы можете также изменить угол - вроде приятно.

ggplot(data = ggdata) +
  geom_jitter(aes(x = x, y = y)) +
  annotate(geom = "text", label = "=", x = -Inf, y = 30, size = 8, color = "red", angle = 45) +
  scale_y_continuous(trans = transformation, breaks = c(0, 10, 20, 30, 50, 70, 90, 110)) +
  coord_cartesian(clip = "off")

Создано в 2020-04-21 пакетом Представить (v0.3.0)

2 голосов
/ 21 апреля 2020

Я не могу получить точный вид, на который вы ссылались, но, возможно, некоторые из этих идей вам пригодятся.

Вы можете сделать указанное значение незначительным, а добавить строку только к незначительным ( здесь я не смог выбрать точное значение 20, поскольку это был уже серьезный перерыв, но, возможно, вы можете поиграть с числами, чтобы получить что-то, что вам нравится):

ggplot(data = ggdata) + 
  geom_jitter(aes(x = x, y = y)) +
  scale_y_continuous(trans = transformation, minor_breaks=20.05,breaks = c(0, 10,20, 30, 50, 70, 90, 110))+
  theme(
    panel.grid.minor.y = element_line(1)
  )

enter image description here

Другой вариант - изменить сами метки. Здесь я выделил () значение 20, но вы можете добавить и другие символы:

ggplot(data = ggdata) + 
  geom_jitter(aes(x = x, y = y)) +
  scale_y_continuous(trans = transformation, minor_breaks = c(0, 10, 20, 30, 50, 70, 90, 110),
                       breaks  = c(0, 10, 20, 30, 50, 70, 90, 110), labels=c(0, 10, expression(bold(("20"))), 30, 50, 70, 90, 110))

enter image description here

Вы можете добавить отрезок графика, который здесь не самый красивый вариант, поскольку ось x не является непрерывной, но, возможно, это будет стимулировать идеи:

ggplot(data = ggdata) + 
  geom_jitter(aes(x = x, y = y)) +
  scale_y_continuous(trans = transformation, breaks = c(0, 10, 20, 30, 50, 70, 90, 110))+
  geom_segment(aes(x=-.01,y=19.5,xend=.01,yend=20.5),size=1.5)

enter image description here

Возможно, вы также можете просто затенить нижнюю (или верхнюю) часть вашего графика:

ggplot(data = ggdata,aes(x = x, y = y)) + 
  geom_jitter() +
  scale_y_continuous(trans = transformation,breaks = c(0, 10,20, 30, 50, 70, 90, 110))+
  annotate("rect", xmin = .4, xmax = 1.6, ymin = 0, ymax = 21,
           alpha = .2)

enter image description here

0 голосов
/ 21 апреля 2020

Это решение должно помочь вам понять, как должна выглядеть ваша ось. Я хотел бы предостеречь от ломания топоров, если вы явно не расскажете о них своей аудитории. В приведенном ниже коде я создал два графика, один для данных ниже 30, а другой для экстремальных точек (и удалите его ось x и метки). Затем я использую plot.margin, чтобы установить поля графиков так, чтобы они немного перекрывались, когда я помещал их в grid.arrange. Возможно, вам придется возиться с полями, чтобы выровнять этикетки.

library(scales)
library(ggplot2)
library(gridExtra)
set.seed(104)

ggdata <- data.frame('x' = rep('a',100),
                     'y' = c(runif(90, 0, 20), runif(10, 90, 100)))

p1 <- ggplot(data = ggdata) + 
  geom_jitter(aes(x = x, y = y)) +
  scale_y_continuous(breaks = seq(0,30,5), limits = c(0,30))+
  theme(plot.margin=unit(c(0,.83,0,1), "cm")) 




p2 <- ggplot(data = ggdata) + 
  geom_jitter(aes(x = x, y = y)) +
  scale_y_continuous( breaks = seq(60,100,10), limits = c(60,100)) +
  scale_x_discrete()+
  theme(axis.title.x=element_blank(),
        axis.text.x=element_blank(),
        axis.ticks.x=element_blank(),
        plot.margin=unit(c(0,1,-0.1,1), "cm"))


grid.arrange(p2,p1)
...