Мне нужно построить гистограмму с подсчетами и линейную диаграмму, показывающую скорость всего на одном графике, я могу сделать их обособленно, но когда я их складываю, я масштабирую первый уровень (т.е. geom_bar
) перекрывается вторым слоем (т.е. geom_line
).
Можно ли переместить ось geom_line
вправо?
Иногда клиенту нужны две шкалы. Предоставление им "ошибочной" речи часто бессмысленно. Но мне нравится ggplot2, настаивая на том, чтобы делать все правильно. Я уверен, что ggplot на самом деле обучает среднего пользователя правильной визуализации.
Может быть, вы можете использовать огранку и масштабировать, чтобы сравнить две серии данных? - например, посмотрите здесь: https://github.com/hadley/ggplot2/wiki/Align-two-plots-on-a-page
Это невозможно в ggplot2, потому что я считаю, что графики с отдельными y шкалами (а не y-масштабами, которые являются преобразованиями друг друга) в корне ошибочны. Некоторые проблемы:
Не обратимы: если задана точка на пространстве сюжета, вы не можете однозначно отобразить ее обратно в точку в пространстве данных.
Их относительно сложно правильно читать по сравнению с другими вариантами. Подробнее см. Исследование диаграмм данных с двумя масштабами Петрой Изенберг, Анастасией Безерианос, Пьером Драгиевичем и Жаном-Даниэлем Фекете.
Их легко манипулировать, чтобы ввести в заблуждение: нет единственного способа указать относительные масштабы осей, оставляя их открытыми для манипуляций. Два примера из блога Junkcharts: один, два
Они произвольны: почему есть только 2 шкалы, а не 3, 4 или десять?
Возможно, вам захочется прочитать Стивена. Несколько длительных обсуждений по теме Двойные масштабируемые оси в графах - это лучшее решение?.
Начиная с ggplot2 2.2.0 вы можете добавить такую вторичную ось (взятую из объявления ggplot2 2.2.0):
ggplot(mpg, aes(displ, hwy)) +
geom_point() +
scale_y_continuous(
"mpg (US)",
sec.axis = sec_axis(~ . * 1.20, name = "mpg (UK)")
)
Техническая основа для решения этой задачи была предложена Кохке около 3 лет назад [KOHSKE]. Тема и технические вопросы вокруг ее решения обсуждались в нескольких случаях здесь, в Stackoverflow [IDs: 18989001, 29235405, 21026598]. Поэтому я буду приводить только конкретную вариацию и некоторое пояснительное пошаговое руководство, используя вышеуказанные решения.
Предположим, что у нас есть некоторые данные y1 в группе G1, к которым некоторые данные y2 в группе G2 связаны каким-либо образом, например. диапазон/масштаб преобразован или с некоторым добавленным шумом. Таким образом, мы хотим построить данные вместе на одном графике со шкалой y1 слева и y2 справа.
df <- data.frame(item=LETTERS[1:n], y1=c(-0.8684, 4.2242, -0.3181, 0.5797, -0.4875), y2=c(-5.719, 205.184, 4.781, 41.952, 9.911 )) # made up!
> df
item y1 y2
1 A -0.8684 -19.154567
2 B 4.2242 219.092499
3 C -0.3181 18.849686
4 D 0.5797 46.945161
5 E -0.4875 -4.721973
Если мы теперь построим наши данные вместе с чем-то вроде
ggplot(data=df, aes(label=item)) +
theme_bw() +
geom_segment(aes(x='G1', xend='G2', y=y1, yend=y2), color='grey')+
geom_text(aes(x='G1', y=y1), color='blue') +
geom_text(aes(x='G2', y=y2), color='red') +
theme(legend.position='none', panel.grid=element_blank())
он не выравнивается хорошо, так как меньший масштаб y1 obviosuly становится рухнутым более крупным масштабом y2.
Трюк здесь для решения проблемы заключается в техническом построении обоих наборов данных по сравнению с первой шкалой y1, но сообщающих второй относительно вторичной оси с метками, показывающими исходный масштаб y2.
Итак, мы создаем первую вспомогательную функцию CalcFudgeAxis, которая вычисляет и собирает функции новой оси. Функция может быть изменена на айонскую симпатию (эта только отображает y2 на диапазон y1).
CalcFudgeAxis = function( y1, y2=y1) {
Cast2To1 = function(x) ((ylim1[2]-ylim1[1])/(ylim2[2]-ylim2[1])*x) # x gets mapped to range of ylim2
ylim1 <- c(min(y1),max(y1))
ylim2 <- c(min(y2),max(y2))
yf <- Cast2To1(y2)
labelsyf <- pretty(y2)
return(list(
yf=yf,
labels=labelsyf,
breaks=Cast2To1(labelsyf)
))
}
что дает:
> FudgeAxis <- CalcFudgeAxis( df$y1, df$y2 )
> FudgeAxis
$yf
[1] -0.4094344 4.6831656 0.4029175 1.0034664 -0.1009335
$labels
[1] -50 0 50 100 150 200 250
$breaks
[1] -1.068764 0.000000 1.068764 2.137529 3.206293 4.275058 5.343822
> cbind(df, FudgeAxis$yf)
item y1 y2 FudgeAxis$yf
1 A -0.8684 -19.154567 -0.4094344
2 B 4.2242 219.092499 4.6831656
3 C -0.3181 18.849686 0.4029175
4 D 0.5797 46.945161 1.0034664
5 E -0.4875 -4.721973 -0.1009335
Теперь я воспользовался решением Kohske во второй вспомогательной функции PlotWithFudgeAxis (в которую мы бросаем объект ggplot и вспомогательный объект новой оси):
library(gtable)
library(grid)
PlotWithFudgeAxis = function( plot1, FudgeAxis) {
# based on: https://rpubs.com/kohske/dual_axis_in_ggplot2
plot2 <- plot1 + with(FudgeAxis, scale_y_continuous( breaks=breaks, labels=labels))
#extract gtable
g1<-ggplot_gtable(ggplot_build(plot1))
g2<-ggplot_gtable(ggplot_build(plot2))
#overlap the panel of the 2nd plot on that of the 1st plot
pp<-c(subset(g1$layout, name=="panel", se=t:r))
g<-gtable_add_grob(g1, g2$grobs[[which(g2$layout$name=="panel")]], pp$t, pp$l, pp$b,pp$l)
ia <- which(g2$layout$name == "axis-l")
ga <- g2$grobs[[ia]]
ax <- ga$children[[2]]
ax$widths <- rev(ax$widths)
ax$grobs <- rev(ax$grobs)
ax$grobs[[1]]$x <- ax$grobs[[1]]$x - unit(1, "npc") + unit(0.15, "cm")
g <- gtable_add_cols(g, g2$widths[g2$layout[ia, ]$l], length(g$widths) - 1)
g <- gtable_add_grob(g, ax, pp$t, length(g$widths) - 1, pp$b)
grid.draw(g)
}
Теперь все можно собрать: Ниже приведен код, как предлагаемое решение может использоваться в повседневной среде. Звонок теперь не строит исходные данные y2, а клонированную версию yf (удерживается внутри предварительно вычисленного вспомогательного объекта FudgeAxis), который запускает масштаб y1. Затем исходный объект ggplot обрабатывается с помощью вспомогательной функции Kohske PlotWithFudgeAxis, чтобы добавить вторую ось, сохраняющую масштабы y2. Он также описывает манипулируемый сюжет.
FudgeAxis <- CalcFudgeAxis( df$y1, df$y2 )
tmpPlot <- ggplot(data=df, aes(label=item)) +
theme_bw() +
geom_segment(aes(x='G1', xend='G2', y=y1, yend=FudgeAxis$yf), color='grey')+
geom_text(aes(x='G1', y=y1), color='blue') +
geom_text(aes(x='G2', y=FudgeAxis$yf), color='red') +
theme(legend.position='none', panel.grid=element_blank())
PlotWithFudgeAxis(tmpPlot, FudgeAxis)
Теперь это выглядит по желанию с двумя осями, y1 слева и y2 справа
Выше решение, если честно сказать, ограниченный шаткий взломать. По мере того, как он играет с ядром ggplot, он бросает некоторые предупреждения, которые мы обмениваем шкалами после факта и т.д. Его нужно обрабатывать с осторожностью и может привести к некорректному поведению в другой настройке. Кроме того, может потребоваться задействовать вспомогательные функции для получения макета по желанию. Размещение легенды является такой проблемой (она будет размещена между панелью и новой осью, поэтому я ее бросил). Масштабирование/выравнивание оси 2 также немного сложно: приведенный выше код хорошо работает, когда в обеих шкалах содержится "0", иначе одна ось смещается. Так определенно с некоторыми возможностями улучшить...
В случае, если пользователю захочется сохранить pic, нужно обернуть вызов в устройство open/close:
png(...)
PlotWithFudgeAxis(tmpPlot, FudgeAxis)
dev.off()
Взяв приведенные выше ответы и некоторые настройки (и во что бы то ни стало), вот способ достижения двух шкал с помощью sec_axis
:
Предположим, что простой (и чисто вымышленный) набор данных dt
: в течение пяти дней он отслеживает количество прерываний VS производительности:
when numinter prod
1 2018-03-20 1 0.95
2 2018-03-21 5 0.50
3 2018-03-23 4 0.70
4 2018-03-24 3 0.75
5 2018-03-25 4 0.60
(диапазоны обоих столбцов отличаются примерно в 5 раз).
Следующий код нарисует обе серии, что они используют всю ось Y:
ggplot() +
geom_bar(mapping = aes(x = dt$when, y = dt$numinter), stat = "identity", fill = "grey") +
geom_line(mapping = aes(x = dt$when, y = dt$prod*5), size = 2, color = "blue") +
scale_x_date(name = "Day", labels = NULL) +
scale_y_continuous(name = "Interruptions/day",
sec.axis = sec_axis(~./5, name = "Productivity % of best",
labels = function(b) { paste0(round(b * 100, 0), "%")})) +
theme(
axis.title.y = element_text(color = "grey"),
axis.title.y.right = element_text(color = "blue"))
Вот результат (код выше + подстройка цвета):
sec_axis
(помимо использования sec_axis
при указании y_scale заключается в умножении каждого значения 2-го ряда данных на 5 при указании ряда. Чтобы получить метки прямо в определении sec_axis, необходимо затем разделить на 5 (и отформатировать). Таким образом, критическая часть в приведенном выше коде на самом деле *5
в geom_line и ~./5
в sec_axis (формула, разделяющая текущее значение .
5).
Для сравнения (я не хочу судить о подходах здесь), вот как выглядят две диаграммы друг над другом:
Вы сами можете судить, какой из них лучше переносить сообщение ("Не мешайте людям на работе!"). Угадай, что честный способ решить.
Полный код для обоих изображений (на самом деле он не более того, что указан выше, только завершен и готов к запуску) находится здесь: https://gist.github.com/sebastianrothbucher/de847063f32fdff02c83b75f59c36a7d, более подробное объяснение здесь: https://sebastianrothbucher. github.io/datascience/r/visualization/ggplot/2018/03/24/two-scales-ggplot-r.html
Следующая статья помогла мне объединить два графика, сгенерированные ggplot2 в одной строке:
Несколько графиков на одной странице (ggplot2) по Cookbook для R
И вот что может выглядеть в этом случае в коде:
p1 <-
ggplot() + aes(mns)+ geom_histogram(aes(y=..density..), binwidth=0.01, colour="black", fill="white") + geom_vline(aes(xintercept=mean(mns, na.rm=T)), color="red", linetype="dashed", size=1) + geom_density(alpha=.2)
p2 <-
ggplot() + aes(mns)+ geom_histogram( binwidth=0.01, colour="black", fill="white") + geom_vline(aes(xintercept=mean(mns, na.rm=T)), color="red", linetype="dashed", size=1)
multiplot(p1,p2,cols=2)
Для меня сложная часть заключалась в определении функции преобразования между двумя осями. Для этого я использовал myCurveFit.
> dput(combined_80_8192 %>% filter (time > 270, time < 280))
structure(list(run = c(268L, 268L, 268L, 268L, 268L, 268L, 268L,
268L, 268L, 268L, 263L, 263L, 263L, 263L, 263L, 263L, 263L, 263L,
263L, 263L, 269L, 269L, 269L, 269L, 269L, 269L, 269L, 269L, 269L,
269L, 261L, 261L, 261L, 261L, 261L, 261L, 261L, 261L, 261L, 261L,
267L, 267L, 267L, 267L, 267L, 267L, 267L, 267L, 267L, 267L, 265L,
265L, 265L, 265L, 265L, 265L, 265L, 265L, 265L, 265L, 266L, 266L,
266L, 266L, 266L, 266L, 266L, 266L, 266L, 266L, 262L, 262L, 262L,
262L, 262L, 262L, 262L, 262L, 262L, 262L, 264L, 264L, 264L, 264L,
264L, 264L, 264L, 264L, 264L, 264L, 260L, 260L, 260L, 260L, 260L,
260L, 260L, 260L, 260L, 260L), repetition = c(8L, 8L, 8L, 8L,
8L, 8L, 8L, 8L, 8L, 8L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L,
9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 5L, 5L,
5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L,
6L, 6L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 4L, 4L, 4L, 4L,
4L, 4L, 4L, 4L, 4L, 4L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L
), module = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), .Label = "scenario.node[0].nicVLCTail.phyVLC", class = "factor"),
configname = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L), .Label = "Road-Vlc", class = "factor"), packetByteLength = c(8192L,
8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L,
8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L,
8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L,
8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L,
8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L,
8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L,
8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L,
8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L,
8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L,
8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L,
8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L
), numVehicles = c(2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L
), dDistance = c(80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L,
80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L,
80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L,
80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L,
80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L,
80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L,
80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L,
80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L,
80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L), time = c(270.166006903445,
271.173853699836, 272.175873251122, 273.177524313334, 274.182946177105,
275.188959464989, 276.189675339937, 277.198250244799, 278.204619457189,
279.212562800009, 270.164199199177, 271.168527215152, 272.173072994958,
273.179210429715, 274.184351047337, 275.18980754378, 276.194816792995,
277.198598277809, 278.202398083519, 279.210634593917, 270.210674322891,
271.212395107473, 272.218871923292, 273.219060500457, 274.220486359614,
275.22401452372, 276.229646658839, 277.231060448138, 278.240407241942,
279.2437126347, 270.283554249858, 271.293168593832, 272.298574288769,
273.304413221348, 274.306272082517, 275.309023049011, 276.317805897347,
277.324403550028, 278.332855848701, 279.334046374594, 270.118608539613,
271.127947700074, 272.133887145863, 273.135726000491, 274.135994529981,
275.136563912708, 276.140120735361, 277.144298344151, 278.146885137621,
279.147552358659, 270.206015567272, 271.214618077209, 272.216566814903,
273.225435592582, 274.234014573683, 275.242949179958, 276.248417809711,
277.248800670023, 278.249750333404, 279.252926560188, 270.217182684494,
271.218357511397, 272.224698488895, 273.231112784327, 274.238740508457,
275.242715184122, 276.249053562718, 277.250325509798, 278.258488063493,
279.261141590137, 270.282904173953, 271.284689544638, 272.294220723234,
273.299749415592, 274.30628880553, 275.312075103126, 276.31579134717,
277.321905523606, 278.326305136748, 279.333056502253, 270.258991527456,
271.260224091407, 272.270076810133, 273.27052037648, 274.274119348094,
275.280808254502, 276.286353887245, 277.287064312339, 278.294444793276,
279.296772014594, 270.333066283904, 271.33877455992, 272.345842319903,
273.350858180493, 274.353972278505, 275.360454510107, 276.365088896161,
277.369166956941, 278.372571708911, 279.38017503079), distanceToTx = c(80.255266401689,
80.156059067023, 79.98823695539, 79.826647129071, 79.76678667135,
79.788239825292, 79.734539327997, 79.74766421514, 79.801243848241,
79.765920888341, 80.255266401689, 80.15850240049, 79.98823695539,
79.826647129071, 79.76678667135, 79.788239825292, 79.735078924078,
79.74766421514, 79.801243848241, 79.764622734914, 80.251248121732,
80.146436869316, 79.984682320466, 79.82292012342, 79.761908518748,
79.796988776281, 79.736920997657, 79.745038376718, 79.802638836686,
79.770029970452, 80.243475525691, 80.127918207499, 79.978303140866,
79.816259117883, 79.749322030693, 79.809916018889, 79.744456560867,
79.738655068783, 79.788697533211, 79.784288359619, 80.260412958482,
80.168426829066, 79.992034911214, 79.830845773284, 79.7756751763,
79.778156038931, 79.732399593756, 79.752769548846, 79.799967731078,
79.757585110481, 80.251248121732, 80.146436869316, 79.984682320466,
79.822062073459, 79.75884601899, 79.801590491435, 79.738335109094,
79.74347007248, 79.803215965043, 79.771471198955, 80.250257298678,
80.146436869316, 79.983831684476, 79.822062073459, 79.75884601899,
79.801590491435, 79.738335109094, 79.74347007248, 79.803849157574,
79.771471198955, 80.243475525691, 80.130180105198, 79.978303140866,
79.816881283718, 79.749322030693, 79.80984572883, 79.744456560867,
79.738655068783, 79.790548644175, 79.784288359619, 80.246349000313,
80.137056554491, 79.980581246037, 79.818924707937, 79.753176142361,
79.808777040341, 79.741609845588, 79.740770913572, 79.796316397253,
79.777593733292, 80.238796415443, 80.119021911134, 79.974810568944,
79.814065350562, 79.743657315504, 79.810146783217, 79.749945098869,
79.737122584544, 79.781650522348, 79.791554933936), headerNoError = c(0.99999999989702,
0.9999999999981, 0.99999999999946, 0.9999999928026, 0.99999873265475,
0.77080141574964, 0.99007491438593, 0.99994396605059, 0.45588747062284,
0.93484381262491, 0.99999999989702, 0.99999999999816, 0.99999999999946,
0.9999999928026, 0.99999873265475, 0.77080141574964, 0.99008458785106,
0.99994396605059, 0.45588747062284, 0.93480223051707, 0.99999999989735,
0.99999999999789, 0.99999999999946, 0.99999999287551, 0.99999876302649,
0.46903147501117, 0.98835168988253, 0.99994427085086, 0.45235035271542,
0.93496741877335, 0.99999999989803, 0.99999999999781, 0.99999999999948,
0.99999999318224, 0.99994254156311, 0.46891362282273, 0.93382613917348,
0.99994594904099, 0.93002915596843, 0.93569767251247, 0.99999999989658,
0.99999999998074, 0.99999999999946, 0.99999999272802, 0.99999871586781,
0.76935240919896, 0.99002587758346, 0.99999881589732, 0.46179415706093,
0.93417422376389, 0.99999999989735, 0.99999999999789, 0.99999999999946,
0.99999999289347, 0.99999876940486, 0.46930769326427, 0.98837353639905,
0.99994447154714, 0.16313586712094, 0.93500824170148, 0.99999999989744,
0.99999999999789, 0.99999999999946, 0.99999999289347, 0.99999876940486,
0.46930769326427, 0.98837353639905, 0.99994447154714, 0.16330039178981,
0.93500824170148, 0.99999999989803, 0.99999999999781, 0.99999999999948,
0.99999999316541, 0.99994254156311, 0.46794586553266, 0.93382613917348,
0.99994594904099, 0.9303627789484, 0.93569767251247, 0.99999999989778,
0.9999999999978, 0.99999999999948, 0.99999999311433, 0.99999878195152,
0.47101897739483, 0.93368891853679, 0.99994556595217, 0.7571113417265,
0.93553999975802, 0.99999999998191, 0.99999999999784, 0.99999999999971,
0.99999891129658, 0.99994309267792, 0.46510628979591, 0.93442584181035,
0.99894450514543, 0.99890078483692, 0.76933812306423), receivedPower_dbm = c(-93.023492290586,
-92.388378035287, -92.205716340607, -93.816400586752, -95.023489422885,
-100.86308557253, -98.464763536915, -96.175707680373, -102.06189538385,
-99.716653422746, -93.023492290586, -92.384760627397, -92.205716340607,
-93.816400586752, -95.023489422885, -100.86308557253, -98.464201120719,
-96.175707680373, -102.06189538385, -99.717150021506, -93.022927803442,
-92.404017215549, -92.204561341714, -93.814319484729, -95.016990717792,
-102.01669022332, -98.558088145955, -96.173817001483, -102.07406915124,
-99.71517574876, -93.021813165972, -92.409586309743, -92.20229160243,
-93.805335867418, -96.184419849593, -102.01709540787, -99.728735187547,
-96.163233028048, -99.772547164798, -99.706399753853, -93.024204617071,
-92.745813384859, -92.206884754512, -93.818508150122, -95.027018807793,
-100.87000577258, -98.467607232407, -95.005311380324, -102.04157607608,
-99.724619517, -93.022927803442, -92.404017215549, -92.204561341714,
-93.813803344588, -95.015606885523, -102.0157405687, -98.556982278361,
-96.172566862738, -103.21871579865, -99.714687230796, -93.022787428238,
-92.404017215549, -92.204274688493, -93.813803344588, -95.015606885523,
-102.0157405687, -98.556982278361, -96.172566862738, -103.21784988098,
-99.714687230796, -93.021813165972, -92.409950613665, -92.20229160243,
-93.805838770576, -96.184419849593, -102.02042267497, -99.728735187547,
-96.163233028048, -99.768774335378, -99.706399753853, -93.022228914406,
-92.411048503835, -92.203136463155, -93.807357409082, -95.012865008237,
-102.00985717796, -99.730352912911, -96.165675535906, -100.92744056572,
-99.708301333236, -92.735781110993, -92.408137395049, -92.119533319039,
-94.982938427575, -96.181073124017, -102.03018610927, -99.721633629806,
-97.32940323644, -97.347613268692, -100.87007386786), snr = c(49.848348091678,
57.698190927109, 60.17669971462, 41.529809724535, 31.452202106925,
8.1976890851341, 14.240447804094, 24.122884195464, 6.2202875499406,
10.674183333671, 49.848348091678, 57.746270018264, 60.17669971462,
41.529809724535, 31.452202106925, 8.1976890851341, 14.242292077376,
24.122884195464, 6.2202875499406, 10.672962852322, 49.854827699773,
57.49079026127, 60.192705735317, 41.549715223147, 31.499301851462,
6.2853718719014, 13.937702343688, 24.133388256416, 6.2028757927148,
10.677815810561, 49.867624820879, 57.417115267867, 60.224172277442,
41.635752021705, 24.074540962859, 6.2847854917092, 10.644529778044,
24.19227425387, 10.537686730745, 10.699414795917, 49.84017267426,
53.139646558768, 60.160512118809, 41.509660845114, 31.42665220053,
8.1846370024428, 14.231126423354, 31.584125885363, 6.2494585568733,
10.654622041348, 49.854827699773, 57.49079026127, 60.192705735317,
41.55465351989, 31.509340361646, 6.2867464196657, 13.941251828322,
24.140336174865, 4.765718874642, 10.679016976694, 49.856439162736,
57.49079026127, 60.196678846453, 41.55465351989, 31.509340361646,
6.2867464196657, 13.941251828322, 24.140336174865, 4.7666691818074,
10.679016976694, 49.867624820879, 57.412299088098, 60.224172277442,
41.630930975211, 24.074540962859, 6.279972363168, 10.644529778044,
24.19227425387, 10.546845071479, 10.699414795917, 49.862851240855,
57.397787176282, 60.212457625018, 41.61637603957, 31.529239767749,
6.2952688513108, 10.640565481982, 24.178672145334, 8.0771089950663,
10.694731030907, 53.262541905639, 57.43627424514, 61.382796189332,
31.747253311549, 24.093100244121, 6.2658701281075, 10.661949889074,
18.495227442305, 18.417839037171, 8.1845086722809), frameId = c(15051,
15106, 15165, 15220, 15279, 15330, 15385, 15452, 15511, 15566,
15019, 15074, 15129, 15184, 15239, 15298, 15353, 15412, 15471,
15526, 14947, 14994, 15057, 15112, 15171, 15226, 15281, 15332,
15391, 15442, 14971, 15030, 15085, 15144, 15203, 15262, 15321,
15380, 15435, 15490, 14915, 14978, 15033, 15092, 15147, 15198,
15257, 15312, 15371, 15430, 14975, 15034, 15089, 15140, 15195,
15254, 15313, 15368, 15427, 15478, 14987, 15046, 15105, 15160,
15215, 15274, 15329, 15384, 15447, 15506, 14943, 15002, 15061,
15116, 15171, 15230, 15285, 15344, 15399, 15454, 14971, 15026,
15081, 15136, 15195, 15258, 15313, 15368, 15423, 15478, 15039,
15094, 15149, 15204, 15263, 15314, 15369, 15428, 15487, 15546
), packetOkSinr = c(0.99999999314881, 0.9999999998736, 0.99999999996428,
0.99999952114066, 0.99991568416005, 3.00628034688444e-08,
0.51497487795954, 0.99627877136019, 0, 0.011303253101957,
0.99999999314881, 0.99999999987726, 0.99999999996428, 0.99999952114066,
0.99991568416005, 3.00628034688444e-08, 0.51530974419663,
0.99627877136019, 0, 0.011269851265775, 0.9999999931708,
0.99999999985986, 0.99999999996428, 0.99999952599145, 0.99991770469509,
0, 0.45861812482641, 0.99629897628155, 0, 0.011403119534097,
0.99999999321568, 0.99999999985437, 0.99999999996519, 0.99999954639936,
0.99618434878558, 0, 0.010513119213425, 0.99641022914441,
0.00801687746446111, 0.012011103529927, 0.9999999931195,
0.99999999871861, 0.99999999996428, 0.99999951617905, 0.99991456738049,
2.6525298291169e-08, 0.51328066587104, 0.9999212220316, 0,
0.010777054258914, 0.9999999931708, 0.99999999985986, 0.99999999996428,
0.99999952718674, 0.99991812902805, 0, 0.45929307038653,
0.99631228046814, 0, 0.011436292559188, 0.99999999317629,
0.99999999985986, 0.99999999996428, 0.99999952718674, 0.99991812902805,
0, 0.45929307038653, 0.99631228046814, 0, 0.011436292559188,
0.99999999321568, 0.99999999985437, 0.99999999996519, 0.99999954527918,
0.99618434878558, 0, 0.010513119213425, 0.99641022914441,
0.00821047996950475, 0.012011103529927, 0.99999999319919,
0.99999999985345, 0.99999999996519, 0.99999954188106, 0.99991896371849,
0, 0.010410830482692, 0.996384831822, 9.12484388049251e-09,
0.011877185067536, 0.99999999879646, 0.9999999998562, 0.99999999998077,
0.99992756868677, 0.9962208785486, 0, 0.010971897073662,
0.93214999078663, 0.92943956665979, 2.64925478221656e-08),
snir = c(49.848348091678, 57.698190927109, 60.17669971462,
41.529809724535, 31.452202106925, 8.1976890851341, 14.240447804094,
24.122884195464, 6.2202875499406, 10.674183333671, 49.848348091678,
57.746270018264, 60.17669971462, 41.529809724535, 31.452202106925,
8.1976890851341, 14.242292077376, 24.122884195464, 6.2202875499406,
10.672962852322, 49.854827699773, 57.49079026127, 60.192705735317,
41.549715223147, 31.499301851462, 6.2853718719014, 13.937702343688,
24.133388256416, 6.2028757927148, 10.677815810561, 49.867624820879,
57.417115267867, 60.224172277442, 41.635752021705, 24.074540962859,
6.2847854917092, 10.644529778044, 24.19227425387, 10.537686730745,
10.699414795917, 49.84017267426, 53.139646558768, 60.160512118809,
41.509660845114, 31.42665220053, 8.1846370024428, 14.231126423354,
31.584125885363, 6.2494585568733, 10.654622041348, 49.854827699773,
57.49079026127, 60.192705735317, 41.55465351989, 31.509340361646,
6.2867464196657, 13.941251828322, 24.140336174865, 4.765718874642,
10.679016976694, 49.856439162736, 57.49079026127, 60.196678846453,
41.55465351989, 31.509340361646, 6.2867464196657, 13.941251828322,
24.140336174865, 4.7666691818074, 10.679016976694, 49.867624820879,
57.412299088098, 60.224172277442, 41.630930975211, 24.074540962859,
6.279972363168, 10.644529778044, 24.19227425387, 10.546845071479,
10.699414795917, 49.862851240855, 57.397787176282, 60.212457625018,
41.61637603957, 31.529239767749, 6.2952688513108, 10.640565481982,
24.178672145334, 8.0771089950663, 10.694731030907, 53.262541905639,
57.43627424514, 61.382796189332, 31.747253311549, 24.093100244121,
6.2658701281075, 10.661949889074, 18.495227442305, 18.417839037171,
8.1845086722809), ookSnirBer = c(8.8808636558081e-24, 3.2219795637026e-27,
2.6468895519653e-28, 3.9807779074715e-20, 1.0849324265615e-15,
2.5705217057696e-05, 4.7313805615763e-08, 1.8800438086075e-12,
0.00021005320203921, 1.9147343768384e-06, 8.8808636558081e-24,
3.0694773489537e-27, 2.6468895519653e-28, 3.9807779074715e-20,
1.0849324265615e-15, 2.5705217057696e-05, 4.7223753038869e-08,
1.8800438086075e-12, 0.00021005320203921, 1.9171738578051e-06,
8.8229427230445e-24, 3.9715925056443e-27, 2.6045198111088e-28,
3.9014083702734e-20, 1.0342658440386e-15, 0.00019591630514278,
6.4692014108683e-08, 1.8600094209271e-12, 0.0002140067535655,
1.9074922485477e-06, 8.7096574467175e-24, 4.2779443633862e-27,
2.5231916788231e-28, 3.5761615214425e-20, 1.9750692814982e-12,
0.0001960392878411, 1.9748966344895e-06, 1.7515881895994e-12,
2.2078334799411e-06, 1.8649940680806e-06, 8.954486301678e-24,
3.2021085732779e-25, 2.690441113724e-28, 4.0627628846548e-20,
1.1134484878561e-15, 2.6061691733331e-05, 4.777159157954e-08,
9.4891388749738e-16, 0.00020359398491544, 1.9542110660398e-06,
8.8229427230445e-24, 3.9715925056443e-27, 2.6045198111088e-28,
3.8819641115984e-20, 1.0237769828158e-15, 0.00019562832342849,
6.4455095380046e-08, 1.8468752030971e-12, 0.0010099091367628,
1.9051035165106e-06, 8.8085966897635e-24, 3.9715925056443e-27,
2.594108048185e-28, 3.8819641115984e-20, 1.0237769828158e-15,
0.00019562832342849, 6.4455095380046e-08, 1.8468752030971e-12,
0.0010088638355194, 1.9051035165106e-06, 8.7096574467175e-24,
4.2987746909572e-27, 2.5231916788231e-28, 3.593647329558e-20,
1.9750692814982e-12, 0.00019705170257492, 1.9748966344895e-06,
1.7515881895994e-12, 2.1868296425817e-06, 1.8649940680806e-06,
8.7517439682173e-24, 4.3621551072316e-27, 2.553168170837e-28,
3.6469582463164e-20, 1.0032983660212e-15, 0.00019385229409318,
1.9830820164805e-06, 1.7760568361323e-12, 2.919419915209e-05,
1.8741284335866e-06, 2.8285944348148e-25, 4.1960751547207e-27,
7.8468215407139e-29, 8.0407329049747e-16, 1.9380328071065e-12,
0.00020004849911333, 1.9393279417733e-06, 5.9354475879597e-10,
6.4258355913627e-10, 2.6065221215415e-05), ookSnrBer = c(8.8808636558081e-24,
3.2219795637026e-27, 2.6468895519653e-28, 3.9807779074715e-20,
1.0849324265615e-15, 2.5705217057696e-05, 4.7313805615763e-08,
1.8800438086075e-12, 0.00021005320203921, 1.9147343768384e-06,
8.8808636558081e-24, 3.0694773489537e-27, 2.6468895519653e-28,
3.9807779074715e-20, 1.0849324265615e-15, 2.5705217057696e-05,
4.7223753038869e-08, 1.8800438086075e-12, 0.00021005320203921,
1.9171738578051e-06, 8.8229427230445e-24, 3.9715925056443e-27,
2.6045198111088e-28, 3.9014083702734e-20, 1.0342658440386e-15,
0.00019591630514278, 6.4692014108683e-08, 1.8600094209271e-12,
0.0002140067535655, 1.9074922485477e-06, 8.7096574467175e-24,
4.2779443633862e-27, 2.5231916788231e-28, 3.5761615214425e-20,
1.9750692814982e-12, 0.0001960392878411, 1.9748966344895e-06,
1.7515881895994e-12, 2.2078334799411e-06, 1.8649940680806e-06,
8.954486301678e-24, 3.2021085732779e-25, 2.690441113724e-28,
4.0627628846548e-20, 1.1134484878561e-15, 2.6061691733331e-05,
4.777159157954e-08, 9.4891388749738e-16, 0.00020359398491544,
1.9542110660398e-06, 8.8229427230445e-24, 3.9715925056443e-27,
2.6045198111088e-28, 3.8819641115984e-20, 1.0237769828158e-15,
0.00019562832342849, 6.4455095380046e-08, 1.8468752030971e-12,
0.0010099091367628, 1.9051035165106e-06, 8.8085966897635e-24,
3.9715925056443e-27, 2.594108048185e-28, 3.8819641115984e-20,
1.0237769828158e-15, 0.00019562832342849, 6.4455095380046e-08,
1.8468752030971e-12, 0.0010088638355194, 1.9051035165106e-06,
8.7096574467175e-24, 4.2987746909572e-27, 2.5231916788231e-28,
3.593647329558e-20, 1.9750692814982e-12, 0.00019705170257492,
1.9748966344895e-06, 1.7515881895994e-12, 2.1868296425817e-06,
1.8649940680806e-06, 8.7517439682173e-24, 4.3621551072316e-27,
2.553168170837e-28, 3.6469582463164e-20, 1.0032983660212e-15,
0.00019385229409318, 1.9830820164805e-06, 1.7760568361323e-12,
2.919419915209e-05, 1.8741284335866e-06, 2.8285944348148e-25,
4.1960751547207e-27, 7.8468215407139e-29, 8.0407329049747e-16,
1.9380328071065e-12, 0.00020004849911333, 1.9393279417733e-06,
5.9354475879597e-10, 6.4258355913627e-10, 2.6065221215415e-05
)), class = "data.frame", row.names = c(NA, -100L), .Names = c("run",
"repetition", "module", "configname", "packetByteLength", "numVehicles",
"dDistance", "time", "distanceToTx", "headerNoError", "receivedPower_dbm",
"snr", "frameId", "packetOkSinr", "snir", "ookSnirBer", "ookSnrBer"
))
Поиск функции преобразования
функция преобразования: f(y1) = 0.025*x + 2.75
функция преобразования: f(y1) = 40*x - 110
Заговор
Обратите внимание, как функции преобразования используются в вызове ggplot
для преобразования данных "на лету",
ggplot(data=combined_80_8192 %>% filter (time > 270, time < 280), aes(x=time) ) +
stat_summary(aes(y=receivedPower_dbm ), fun.y=mean, geom="line", colour="black") +
stat_summary(aes(y=packetOkSinr*40 - 110 ), fun.y=mean, geom="line", colour="black", position = position_dodge(width=10)) +
scale_x_continuous() +
scale_y_continuous(breaks = seq(-0,-110,-10), "y_first", sec.axis=sec_axis(~.*0.025+2.75, name="y_second") )
Первый вызов stat_summary
- это тот, который устанавливает базу для первой оси y. Второй вызов stat_summary
вызывается для преобразования данных. Помните, что все данные берут за основу первую ось y. Чтобы данные были нормализованы для первой оси y. Для этого я использую функцию преобразования по данным: y=packetOkSinr*40 - 110
Теперь, чтобы преобразовать вторую ось, я использую противоположную функцию в пределах scale_y_continuous
call: sec.axis=sec_axis(~.*0.025+2.75, name="y_second")
.
coef(lm(c(-70, -110) ~ c(1,0)))
и coef(lm(c(1,0) ~ c(-70, -110)))
Вы можете определить вспомогательную функцию, такую как equationise <- function(range = c(-70, -110), target = c(1,0)){ c = coef(lm(target ~ range)) as.formula(substitute(~ a*. + b, list(a=c[[2]], b=c[[1]]))) }
Существуют общие случаи использования дуэльных осей, например, климатограф, показывающий месячную температуру и количество осадков. Вот простое решение, обобщенное на основе решения Megatron, позволяющее установить нижний предел переменных на значение, отличное от нуля:
Пример данных:
climate <- tibble(
Month = 1:12,
Temp = c(-4,-4,0,5,11,15,16,15,11,6,1,-3),
Precip = c(49,36,47,41,53,65,81,89,90,84,73,55)
)
Установите пределы каждой оси вручную:
ylim.prim <- c(0, 180) # in this example, precipitation
ylim.sec <- c(-4, 18) # in this example, temperature
Следующее делает необходимые вычисления, основанные на этих пределах, и делает сам график:
b <- diff(ylim.prim)/diff(ylim.sec)
a <- b*(ylim.prim[1] - ylim.sec[1])
ggplot(climate, aes(Month, Precip)) +
geom_col() +
geom_line(aes(y = a + Temp*b), color = "red") +
scale_y_continuous("Precipitation", sec.axis = sec_axis(~ (. - a)/b, name = "Temperature")) +
scale_x_continuous("Month", breaks = 1:12) +
ggtitle("Climatogram for Oslo (1961-1990)")
Если вы хотите убедиться, что красная линия соответствует правой оси Y, вы можете добавить предложение theme
в код:
ggplot(climate, aes(Month, Precip)) +
geom_col() +
geom_line(aes(y = a + Temp*b), color = "red") +
scale_y_continuous("Precipitation", sec.axis = sec_axis(~ (. - a)/b, name = "Temperature")) +
scale_x_continuous("Month", breaks = 1:12) +
theme(axis.line.y.right = element_line(color = "red"),
axis.ticks.y.right = element_line(color = "red"),
axis.text.y.right = element_text(color = "red"),
axis.title.y.right = element_text(color = "red")
) +
ggtitle("Climatogram for Oslo (1961-1990)")
который окрашивает правую ось:
Мы определенно могли построить график с двойными Y-осями, используя базовое R funtion plot
.
# pseudo dataset
df <- data.frame(x = seq(1, 1000, 1), y1 = sample.int(100, 1000, replace=T), y2 = sample(50, 1000, replace = T))
# plot first plot
with(df, plot(y1 ~ x, col = "red"))
# set new plot
par(new = T)
# plot second plot, but without axis
with(df, plot(y2 ~ x, type = "l", xaxt = "n", yaxt = "n", xlab = "", ylab = ""))
# define y-axis and put y-labs
axis(4)
with(df, mtext("y2", side = 4))
Вы можете создать коэффициент масштабирования, который применяется ко второй геометрии и правой оси y. Это происходит из решения Себастьяна.
library(ggplot2)
scaleFactor <- max(mtcars$cyl) / max(mtcars$hp)
ggplot(mtcars, aes(x=disp)) +
geom_smooth(aes(y=cyl), method="loess", col="blue") +
geom_smooth(aes(y=hp * scaleFactor), method="loess", col="red") +
scale_y_continuous(name="cyl", sec.axis=sec_axis(~./scaleFactor, name="hp")) +
theme(
axis.title.y.left=element_text(color="blue"),
axis.text.y.left=element_text(color="blue"),
axis.title.y.right=element_text(color="red"),
axis.text.y.right=element_text(color="red")
)
Примечание: использование ggplot2
v3.0.0
Я признаю и соглашаюсь с hadley (и другими), что отдельные y-шкалы "в корне ошибочны". Сказав это, я часто желаю, чтобы у ggplot2
была функция - особенно, когда данные находятся в широкоформатном, и я быстро хочу визуализировать или проверить данные (то есть только для личного использования).
В то время как библиотека tidyverse
позволяет легко преобразовать данные в формат long (например, facet_grid()
будет работать), процесс все еще не является тривиальным, как показано ниже:
library(tidyverse)
df.wide %>%
# Select only the columns you need for the plot.
select(date, column1, column2, column3) %>%
# Create an id column – needed in the `gather()` function.
mutate(id = n()) %>%
# The `gather()` function converts to long-format.
# In which the `type` column will contain three factors (column1, column2, column3),
# and the `value` column will contain the respective values.
# All the while we retain the `id` and `date` columns.
gather(type, value, -id, -date) %>%
# Create the plot according to your specifications
ggplot(aes(x = date, y = value)) +
geom_line() +
# Create a panel for each `type` (ie. column1, column2, column3).
# If the types have different scales, you can use the `scales="free"` option.
facet_grid(type~., scales = "free")
sec_axis
.
Вы можете использовать facet_wrap(~ variable, ncol= )
для переменной, чтобы создать новое сравнение. Это не на той же оси, но похоже.
Казалось бы, это простой вопрос, но он сталкивается с двумя фундаментальными вопросами. A) Как работать с мультискалярными данными при представлении в сравнительной диаграмме, и, во-вторых, B) можно ли это сделать без некоторых практических правил программирования R, таких как i) плавление данных, ii) огранка, iii) добавление другой слой к существующему. Приведенное ниже решение удовлетворяет обоим вышеперечисленным условиям, поскольку оно обрабатывает данные без необходимости их масштабирования, и, во-вторых, упомянутые методы не используются.
Вот результат,
Для тех, кто хочет узнать больше об этом методе, перейдите по ссылке ниже. Как построить график оси 2- y с столбцами рядом без повторного масштабирования данных
Ответ Хэдли дает интересную ссылку на доклад Стивена Мало Двойные масштабируемые оси в Графы - это лучшее решение?.
Я не знаю, что означает OP с "counts" и "rate", но быстрый поиск дает мне Counts and Rates, поэтому Я получаю некоторые данные о авариях в североамериканском альпинизме 1:
Years<-c("1998","1999","2000","2001","2002","2003","2004")
Persons.Involved<-c(281,248,301,276,295,231,311)
Fatalities<-c(20,17,24,16,34,18,35)
rate=100*Fatalities/Persons.Involved
df<-data.frame(Years=Years,Persons.Involved=Persons.Involved,Fatalities=Fatalities,rate=rate)
print(df,row.names = FALSE)
Years Persons.Involved Fatalities rate
1998 281 20 7.117438
1999 248 17 6.854839
2000 301 24 7.973422
2001 276 16 5.797101
2002 295 34 11.525424
2003 231 18 7.792208
2004 311 35 11.254019
И затем я попытался сделать график, как было предложено на стр. 7 вышеупомянутого отчета (и, следуя просьбе OP, для графа подсчета в виде гистограммы и ставок в виде линейной диаграммы):
Другим менее очевидным решением, которое работает только для временных рядов, является для преобразования всех наборов значений в общий количественный масштаб посредством отображение процентных различий между каждым значением и ссылкой (или индекс). Например, выберите конкретный момент времени, такой как первый интервал, который появляется на графике, и выразить каждое последующее значение в виде процентной разницы между ним и Начальное значение. Это делается путем деления значения в каждой точке в время на значение для начальной точки во времени, а затем умножение на 100, чтобы преобразовать скорость в процент, как показано ниже.
df2<-df
df2$Persons.Involved <- 100*df$Persons.Involved/df$Persons.Involved[1]
df2$rate <- 100*df$rate/df$rate[1]
plot(ggplot(df2)+
geom_bar(aes(x=Years,weight=Persons.Involved))+
geom_line(aes(x=Years,y=rate,group=1))+
theme(text = element_text(size=30))
)
И это результат:
Но мне это не очень нравится, и я не могу легко поместить в него легенду...
1 <Суб > WILLIAMSON, Jed, et al. Аварии в североамериканском альпинизме 2005 года. The Mountaineers Books, 2005. Суб >