Проблема масштабирования оси Y с небольшими числами

У меня проблема с масштабированием по оси Y для чисел меньше 1e-10: все они отображаются на одной горизонтальной линии.

Вот воспроизводимый пример:

file <- structure(list(I = c(-7.254574e-11, -5.649333e-11, -5.015416e-11, 
-4.228137e-11, -3.287486e-11, -2.714915e-11, -2.203692e-11, -1.784489e-11, 
-1.150574e-11, -1.058553e-11, -6.189018e-12, -3.735149e-12, -2.303724e-12, 
6.610914e-13, 1.274374e-12, -3.610768e-13, 5.465134e-12, 6.691699e-12, 
8.020478e-12, 1.139353e-11, 1.537988e-11, 1.926399e-11, 2.130825e-11, 
2.45791e-11, 3.204071e-11, 3.582262e-11, 4.287535e-11, 4.624839e-11, 
5.16657e-11, 6.035387e-11), V = c(-2, -1.867, -1.733, -1.6, -1.467, 
-1.333, -1.2, -1.067, -0.933, -0.8, -0.667, -0.533, -0.4, -0.267, 
-0.133, 0, 0.133, 0.267, 0.4, 0.533, 0.667, 0.8, 0.933, 1.067, 
1.2, 1.333, 1.467, 1.6, 1.733, 1.867)), .Names = c("I", "V"), class = "data.frame", row.names = c(NA, 
-30L))

plot(file$V,file$I)

gg <- ggplot(file,aes(x = V,y=I))
print(gg + geom_point())

Как видите, при использовании функции базового графика точки отображаются правильно, а при использовании ggplot2 — на горизонтальной линии.

Я видел похожий пост в списке рассылки в мае 2011 года, на что Хэдли ответил, что он работает с разрабатываемой версией ggplot2. Однако, используя описанную ниже версию R, я все еще получаю сообщение об ошибке.

> sessionInfo()
R version 2.15.0 (2012-03-30)
Platform: i686-pc-linux-gnu (32-bit)

locale:
 [1] LC_CTYPE=fr_FR.UTF-8       LC_NUMERIC=C               LC_TIME=fr_FR.UTF-8       
 [4] LC_COLLATE=fr_FR.UTF-8     LC_MONETARY=fr_FR.UTF-8    LC_MESSAGES=fr_FR.UTF-8   
 [7] LC_PAPER=C                 LC_NAME=C                  LC_ADDRESS=C              
[10] LC_TELEPHONE=C             LC_MEASUREMENT=fr_FR.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] tikzDevice_0.6.2 filehash_2.2-1   scales_0.2.0     plyr_1.7.1       reshape2_1.2.1  
[6] ggplot2_0.9.0   

loaded via a namespace (and not attached):
 [1] colorspace_1.1-1   dichromat_1.2-4    digest_0.5.2       grid_2.15.0        MASS_7.3-18       
 [6] memoise_0.1        munsell_0.3        proto_0.3-9.2      RColorBrewer_1.0-5 stringr_0.6       
[11] tools_2.15.0 

Кто-нибудь знает?

Заранее спасибо ! Тибо Рюэль


person Thibaud Ruelle    schedule 05.06.2012    source источник
comment
+1 быстрый тест подтверждает такое поведение в моей системе (ggplot2 0.9.1). Может была реверсия или ?   -  person Ben Bolker    schedule 05.06.2012
comment
@BenBolker Я спросил об этом Брайана в чате, учитывая связь с этим предыдущим вопросом.   -  person joran    schedule 05.06.2012
comment
@joran Да, кажется, два поста можно объединить. Извините, что не нашел его в своих исследованиях.   -  person Thibaud Ruelle    schedule 05.06.2012
comment
Я, вероятно, не нашел бы его, если бы специально не вспомнил, что видел и комментировал предыдущий.   -  person joran    schedule 05.06.2012
comment
Однако вариант ручного масштабирования не может (или, по крайней мере, вряд ли) применяться в моем случае, так как у меня есть сотни этих файлов для построения и анализа.   -  person Thibaud Ruelle    schedule 05.06.2012


Ответы (1)


Как прокомментировал Брайан Диггс в ответ на связанный пост, который @ Джоран указал выше, проблема вызвана функцией scales::zero_range(). Он использует all.equal() для проверки того, находятся ли наименьшее и наибольшее значения y в пределах tolerance = .Machine$double.eps ^ 0.5 = 1.490116e-08 друг от друга; если это так, данные отображаются с «нулевой шкалой», используемой в вашем примере.

В качестве временного исправления вы можете использовать fixInNamespace() для удаления ошибочного бита zero_range().

library(scales)  ## (The scales package needs to be on your search path)
fixInNamespace("zero_range", pos="package:scales")

В редакторе, запущенном fixInNamespace(), замените это определение zero_range():

function (x) 
{
    length(x) == 1 || isTRUE(all.equal(x[1] - x[2], 0))
}

с этим (не забудьте сохранить отредактированную версию):

function (x) 
{
    length(x) == 1 
}

Код, который вы указали, работает нормально:

введите здесь описание изображения

person Josh O'Brien    schedule 05.06.2012
comment
Я полагаю, вы также можете настроить аргумент tolerance в all.equal. - person joran; 05.06.2012
comment
@joran - Есть идеи, что было бы лучше? Я не знаю, от какой патологии Хэдли пытается защититься с помощью этого фрагмента кода, поэтому не знаю, насколько безопасно опускаться... (Поэтому, конечно, я пошел и удалил защиту целиком;) - person Josh O'Brien; 05.06.2012
comment
Что ж, zero_range обычно передается вектор с минимальным/максимальным значением, поэтому вы хотите, чтобы некоторые проверяли, совпадают ли они. Может быть, просто проверить, если x[1] == x[2]? Я чувствую, что здесь есть пограничные случаи с плавающей запятой, которых я не понимаю. - person joran; 05.06.2012
comment
Большое спасибо за ваш ответ. Это имеет смысл для меня, но не работает с кодом, который я использую. Я очистил свое рабочее пространство, сделал исправление после загрузки весов, затем загрузил ggplot2, а затем запустил предоставленный мной код. Может весов нет в моем пути поиска, как я могу убедиться? - person Thibaud Ruelle; 05.06.2012
comment
@ThibaudRuelle -- Введите search(), и если вы увидите package:scales в результатах, это значит, что он указан в вашем пути поиска. Кроме того, вы должны убедиться, что вы сохранили отредактированную версию zero_range. (Интересно, что даже если вы соответствующим образом отредактировали код, при вводе zero_range будет напечатана неотредактированная версия.) - person Josh O'Brien; 05.06.2012
comment
@joran - Да, я тоже не понимаю этих крайних случаев. Предположительно была причина не использовать ==, но столь же очевидно, что all.equal() с допуском по умолчанию слишком консервативен. - person Josh O'Brien; 05.06.2012
comment
@ ДжошО'Брайен Еще раз спасибо. Кажется, я не нашел, как правильно сохранить zero_range() : когда я делаю ваше исправление, функция отображается так, как должна, но zero_range(c(1e-11,2e-11,3e-11)) дает TRUE, поэтому изменения не были внесены. (весы находятся в моем пути поиска). - person Thibaud Ruelle; 05.06.2012
comment
@ThibaudRuelle -- Вместо этого взгляните на версию (?), которая находится в пространстве имен: scales:::zero_range(range(c(1e-11,2e-11,3e-11))). Это должно вернуть FALSE, если вам удалось сохранить изменения. - person Josh O'Brien; 05.06.2012
comment
@ ДжошО'Брайен Да, это работает. Теперь мне нужно заставить ggplot2 использовать эту версию вместо текущей :) - person Thibaud Ruelle; 05.06.2012
comment
comment
Я получаю разные результаты, вводя zero_range (исходная функция) и scales:::zero_range (исправленная функция), но обе с <environment: namespace:scales> в конце. Пожалуй, сделаю новый пост. Я также думаю, что мы больше не получим результатов по этой проблеме, пока не будет сделано чистое исправление, поэтому я подтвержу ваш ответ, еще раз спасибо, ДжошО'Брайен. Редактировать: после перезапуска R я получаю правильную кривую, но без y-тиков, что достаточно для меня. - person Thibaud Ruelle; 05.06.2012