Существующему ответу на этот вопрос пять лет, и он полезен и информативен. Недавнее дополнение к нему указывает на хорошее решение, и я думаю, что это лучший ответ.
Тем не менее, мой ответ здесь состоит в том, чтобы показать, что все это время существовало и базовое решение проблемы R. Мы можем видеть разрыв в графическом выводе, поэтому все, что нам нужно сделать, это придумать способ, чтобы R тоже его увидел.
Допустим, мы делаем график без полей и с черным фоном и помещаем на него красивую большую букву H в точке x = 5 белого цвета. Затем мы проводим тонкую вертикальную линию в точке x = 5.
Мы создадим его в формате png, указав ширину 10 дюймов и установив разрешение 100 пикселей на дюйм. После его создания мы можем получить все его пиксели в виде массива:
mar <- par("mar")
par(mar = c(0, 0, 0, 0))
ppi <- 100
tmpfile <- tempfile(fileext = ".png")
png(tmpfile, width = 10, height = 5, units = "in", res = ppi, bg = "black")
plot(1:10, asp = 1, cex = 1)
text(x = 5, y = 10, labels = "H", adj = c(0, 1), cex = 30, col = "white")
lines(c(5,5), c(-1,20), col = "white", cex = 1)
dev.off()
mat <- png::readPNG(tmpfile)
plot(raster::as.raster(mat))
Теперь массив у нас одноцветный, то есть фактически представляет собой три одинаковые сложенные матрицы по 500 строк на 1000 столбцов. Мы можем взять один его слой, который будет представлять белые (1) или черные (0) пиксели, каждый шириной 1/100 дюйма.
Поэтому, если мы используем apply
для получения максимального значения этих столбцов, мы получаем вектор из 1000 элементов из 0 и 1, который фактически является одномерной проекцией этого изображения. Первые 499 или 500 значений будут равны 0 для черной половины изображения, затем будет одно значение 1, представляющее белую линию, затем нули там, где левый пробел находится перед нашей буквой, а затем ряд 1 с для само письмо. Если мы посчитаем черные пиксели между линией и буквой, то получим размер зазора.
space_in_pixels <- diff(which(apply(mat, 2, max) > 0.9))[1]
space_in_pixels
#> [1] 40
Поскольку мы можем использовать strwidth
для получения общей ширины глифа, мы можем определить, какая часть глифа занимает пробел слева:
space_in_inches <- space_in_pixels / ppi
leading_proportion <- space_in_inches/strwidth("H", cex = 30, units = "inches")
leading_proportion
#> [1] 0.1106628
Если подумать, это именно то число, которое вам нужно передать adj
, чтобы сдвинуть букву так, чтобы ее крайний левый пиксель совпал с заданным значением x
в вызове text
.
Мы можем повторить это для всех прописных и строчных букв (это займет всего несколько секунд) и сохранить все значения в именованном списке.
sizes <- numeric(52)
l <- c(LETTERS, letters)
for(i in 1:52)
{
tmpfile <- tempfile(fileext = ".png")
png(tmpfile, width = 10, height = 5, units = "in", res = ppi, bg = "black")
plot(1:10, asp = 1, cex = 1)
text(x = 5, y = 10, labels = l[i], adj = c(0, 1), cex = 30, col = "white")
lines(c(5,5), c(-1,20), col = "white", cex = 1)
dev.off()
mat <- png::readPNG(tmpfile)
space_size <- diff(which(apply(mat, 2, max) > 0.9))[1]/ppi
sizes[i] <- space_size/strwidth(l[i], cex = 30, units = "inches")
}
leading <- setNames(as.list(sizes), c(LETTERS, letters))
Чтобы упростить использование, мы определяем функцию, которую мы можем передать adj
любой заданной строке, которая сдвинет строку влево на правильную величину:
Adj <- function(x, y = 0)
{
first_char <- substr(x, 1, 1)
c(leading[[first_char]] * strwidth(first_char)/strwidth(x), 1)
}
Итак, теперь давайте попробуем:
par(mar = mar)
string <- "H"
plot(1:10, asp = 1, cex = 1)
points(x = 5, y = 5, pch = 3, cex = 3, col = 'red')
text(5, 5, labels = string, cex = 8, adj = Adj(string), col = rgb(0.1, 0.9, 0.1, 0.5))
и с многосимвольной строкой:
string <- "Xerxes"
plot(1:10, asp = 1, cex = 1)
points(x = 5, y = 5, pch = 3, cex = 3, col = 'red')
text(5, 5, labels = string, cex = 8, adj = Adj(string), col = rgb(0.1, 0.9, 0.1, 0.5))
...и строка в нижнем регистре:
string <- "lol"
plot(1:10, asp = 1, cex = 1)
points(x = 5, y = 5, pch = 3, cex = 3, col = 'red')
text(5, 5, labels = string, cex = 8, adj = Adj(string), col = rgb(0.1, 0.9, 0.1, 0.5))
Обратите внимание, что этот результат не совсем эквивалентен типографскому левому азимуту. В своей текущей форме он применяется только к шрифту без шрифта по умолчанию, но может быть рассчитан для любого шрифта, который вы хотите использовать.
Вы также можете использовать эту технику, чтобы получить пространство справа от глифа. Теоретически вы можете использовать эти методы для управления расстоянием между символами в сюжете. Это может сделать полезный небольшой пакет.
Создано 08 мая 2020 г. с помощью пакета reprex (v0.3.0)
person
Allan Cameron
schedule
08.05.2020
cex = 1
. - person yalei du   schedule 11.05.2015cex=1
. С моего экрана это выглядит как два пикселя. Также похоже, что их примерно в 8 раз больше для больших (когдаcex = 8
). Вы хотели удалить это смещение только для символов H или вообще? - person Max Candocia   schedule 11.05.2015cex=1
. У вас есть идеи, как убрать эти пробелы? - person yalei du   schedule 11.05.2015