Точные размеры интервалов и размеров линий

В основном это дополнительный вопрос к предыдущему.

Учитывая, что в ggplot2 и сетке есть разные типы линий, а интервалы различаются между размерами линий, какова их связь?

Есть две вещи, которые я не совсем понимаю.

  1. Как определяется размер строки? Если бы мне нужно было нарисовать прямую вертикальную линию и заменить ее прямоугольником, какой должна быть ширина прямоугольника, чтобы получить эквивалент размера линии? В частности, как lwd = 1 или lwd = 10, которые я передаю в par()/gpar(), относятся к абсолютным размерам (пиксели, мм, дюймы, точки)?

Документация gpar() ссылается на документацию par(), в которой говорится следующее:

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

Что достаточно справедливо, но я не смог найти необходимую документацию по конкретным устройствам для обычных устройств.

  1. Я думаю, что могу предположить, что интервалы между различными типами линий пропорциональны их размеру, но как именно определяются пропорции «пунктирная», «пунктирная», «пунктирная» и т. д. длины штриха к длине интервала?

На приведенном ниже графике, как я могу заранее предсказать или рассчитать длину штриха/интервала?

library(ggplot2)

df <- data.frame(
  x = rep(c(0, 1), 4),
  y = rep(1:4, each = 2),
  size = rep(c(2, 10), each = 4),
  linetype = rep(c(2,2,3,3), 2)
)

# The `I()` function automatically assigns identity scales
ggplot(df, aes(x, y, size = I(size), linetype = I(linetype))) +
  geom_line(aes(group = y))

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

РЕДАКТИРОВАТЬ: ggplot имеет переменную с именем .pt, которую они часто используют для умножения размера строки. Вероятно, это означает, что в сетке размер линии равен something / .pt, но в каких единицах?


person teunbrand    schedule 25.07.2020    source источник
comment
Я думаю, что это то, что вам нужно, включая длину включения/выключения участки линии. Это делается с помощью строки, содержащей 2, 4, 6 или 8 шестнадцатеричных цифр, которые задают длины последовательных длин. Например, строка 33 указывает три включенных единицы, затем три выключенных, а 3313 указывает три включенных единицы, затем три выключенных, затем одну включенную и, наконец, три выключенных. Размер линии — это ее ширина в миллиметрах.   -  person Limey    schedule 25.07.2020
comment
Спасибо за это, я знал об этой альтернативной записи, но я пропустил этот важный момент в документации: «Пять стандартных типов штрихпунктирных линий, описанных выше, соответствуют 44, 13, 1343, 73 и 2262». Теперь мне просто нужно выяснить, что именно означают «единицы».   -  person teunbrand    schedule 25.07.2020


Ответы (1)


Еще один отличный вопрос, Теунбранд. У меня есть частичный ответ, который, кажется, дает правильные результаты, но кажется немного неточным.

Очевидный способ получить преобразование между lwd и единицами длины — измерить их программно. Например, чтобы проверить lwd устройства X11, вы можете сделать это:

library(grid)

x11()
grid.newpage()

# draw a thick black line that goes right across the page
grid.draw(linesGrob(x = unit(c(-0.1, 1.1), "npc"), 
                    y = unit(c(0.5, 0.5), "npc"),
                    gp = gpar(lwd = 10)))

# Capture as a bitmap
bmp_line    <- dev.capture()

# Work out the thickness of the line in pixels as proportion of page height
lwd_10_prop <- sum(bmp_line != "white")/length(bmp_line)

# Now draw a black rectGrob of known height with lwd of 0 and transparent for completeness
grid.newpage()
grid.draw(rectGrob(width  = unit(1.1, "npc"),
                   height = unit(10, "mm"),
                   gp     = gpar(lwd = 0, col = "#00000000", fill = "black")))

# Capture as a bitmap and measure the width as proportion of device pixels
bmp_rect    <- dev.capture()
mm_10_prop  <- sum(bmp_rect != "white")/length(bmp_rect)

# Get the ratio of lwd to mm
lwd_as_mm <- lwd_10_prop / mm_10_prop
dev.off()

lwd_as_mm
#> [1] 0.2702296

Что говорит нам о том, что lwd от 1 на этом устройстве составляет 0,2702296 мм.

Мы можем проверить это, нанеся красный прямоугольник расчетной ширины на зеленую линию в верхней части страницы, а затем нанеся ту же зеленую линию на тот же красный прямоугольник в нижней части страницы. Тогда и только тогда, когда они будут одинаковой ширины, у нас будет полностью зеленая и полностью красная линии на нашей странице:

grid.newpage()

grid.draw(linesGrob(x = unit(c(-0.1, 1.1), "npc"), 
                    y = unit(c(0.75, 0.75), "npc"),
                    gp = gpar(lwd = 5, col = "green")))

grid.draw(rectGrob(y = unit(0.75, "npc"),
                   width  = unit(1.1, "npc"),
                   height = unit(5 * lwd_as_mm, "mm"),
                   gp     = gpar(lwd = 0,  col = "#00000000", fill = "red")))

grid.draw(rectGrob(y = unit(0.25, "npc"),
                   width  = unit(1.1, "npc"),
                   height = unit(5 * lwd_as_mm, "mm"),
                   gp     = gpar(lwd = 0,  col = "#00000000", fill = "red")))

grid.draw(linesGrob(x = unit(c(-0.1, 1.1), "npc"), 
                    y = unit(c(0.25, 0.25), "npc"),
                    gp = gpar(lwd = 5, col = "green")))

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

Конечно, мы можем повысить точность, увеличив толщину наших линий при измерении их ширины в пикселях.

Хотя предполагается, что результат не зависит от устройства, стоит отметить, что в приведенном выше примере я взял результаты с устройства X11, но нанес их на график в устройстве rstudio, так что эквивалентность сохраняется для обоих устройств.

person Allan Cameron    schedule 25.07.2020
comment
Привет, Аллан, отличный ответ, как обычно. Я получаю очень похожие цифры на своей машине, так что это отличный эмпирический подход. Я пробовал все виды convertUnit(unit(0.2702296, "mm"), "pt") и варьировал последний блок, чтобы угадать, каким должен быть исходный ввод, но пока это не имеет для меня особого смысла. Это работает для меня, несмотря на то, что я не знаю точных деталей :) - person teunbrand; 25.07.2020