Подтвердить что ты не робот

Настройте расстояние между текстом в горизонтальной легенде

У меня есть сюжет с горизонтальной легендой:

 legend("bottomleft", inset = c(0, -0.3), bty = "n",
        x.intersp=0, xjust=0,yjust=0,
        legend=c("AAPL", "Information Technology",
                 "Technology Hardware and Equipment", "S&P 500"),
        col=c("black", "red", "blue3", "olivedrab3"),
        lwd=2, cex = 0.5, xpd = TRUE, ncol = 4)

Проблема заключается в том, что между первым элементом легенды, "AAPL" и огромным расстоянием между вторым элементом "Информационные технологии" существует огромный пробег.

Я попытался настроить интервал с помощью txt.width(), но он вообще не работал. Или, может быть, я не использую этот вариант по назначению. Вот как я ввел параметр txt.width внутри legend():

txt.width = c(2,1,1)

Я не уверен, что это имеет значение, но моя ось x является осью дат!

Есть ли простой способ настройки пробелов между текстом в легенде?

Спасибо!

4b9b3361

Ответ 1

text.width может дать вам контроль над шириной каждого столбца в вашей легенде, но это не так просто. В принципе, text.width - это вектор, который будет умножен на другой вектор, который до тех пор, пока ваш вектор строк легенды. Элементами этого второго вектора являются целые числа от 0 до length(legend)-1. См. code to legend() для деталей gory. Важно то, что вы можете придумать этот продукт text.width, а второй вектор - приблизительно, координаты x для ваших элементов легенды. Затем, если вы знаете, какие координаты x вы хотите, вы можете рассчитать, что нужно передать в аргументе text.width.

legtext <- c("AAPL", "Information Technology", 
             "Technology Hardware and Equipment", "S&P 500")
xcoords <- c(0, 10, 30, 60)
secondvector <- (1:length(legtext))-1
textwidths <- xcoords/secondvector # this works for all but the first element
textwidths[1] <- 0 # so replace element 1 with a finite number (any will do)

И тогда ваш последний код мог бы выглядеть примерно так (за исключением того, что мы не знаем ваших исходных данных или параметров печати):

plot(x=as.Date(c("1/1/13","3/1/13","5/1/13"), "%m/%d/%y"), y=1:3, ylim=c(0,3))

legend(x="bottomleft", bty = "n", x.intersp=0, xjust=0, yjust=0,
   legend=legtext, 
   col=c("black", "red", "blue3", "olivedrab3"), 
   lwd=2, cex = 0.5, xpd = TRUE, ncol = 4,
   text.width=textwidths)

Как отметил Андре Сильва, значения, которые вы хотите использовать в xcoords и textwidths, будут зависеть от текущего размера вашего графика, диапазона значений, заданных для вашей оси x и т.д.

Кроме того, secondvector выше выглядел бы иначе, если бы у вас было более одного элемента на столбец. Например, для двух столбцов с двумя элементами легенды, secondvector == c(0,0,1,1).

Ответ 2

plot(1,1,xlab="",ylab="",xlim=c(0,2),ylim=c(0,2))

legend("bottomleft", text.width=c(0,0.085,0.235,0.35),
       inset = c(0, -0.2), bty = "n", x.intersp=0.5,
       xjust=0, yjust=0,
       legend=c("AAPL", "Information Technology",
                "Technology Hardware and Equipment", "S&P 500"),
       col=c("black", "red", "blue3", "olivedrab3"),
       lwd=3, cex = 0.75, xpd = TRUE, horiz=TRUE)

horizontal_legend

Я использовал text.width с четырьмя аргументами, чтобы установить пространство между строками в легенде. Второй аргумент внутри text.width удалось установить расстояние между "AAPL" и "Информационные технологии" и т.д. Для третьего и четвертого аргументов.

К сожалению, мне приходилось reset значения внутри text.width каждый раз, когда я менял размер графика.

Ответ 3

В моей системе (платформа: x86_64-w64-mingw32, версия R: 3.4.1 (2017-06-30)) решения, предоставленные до сих пор Андре Сильвой и Пангой, неудовлетворительны. Оба решения требуют ввода пользователя и зависят от размера устройства. Поскольку я никогда не использовал команду text.width и мне всегда приходилось корректировать значения с помощью try-and-error, я написал функцию (f.horlegend). Функция имеет аналогичные аргументы как функция legend и основана на идее, размещенной здесь.

Функция создает горизонтальную (одну строку) легенду, которую можно расположить командами, известными из функции legend, например. "bottomleft"

f.horlegend <- function(pos, legend, xoff = 0, yoff = 0, 
  lty = 0, lwd = 1, ln.col = 1, seg.len = 0.04, 
  pch = NA, pt.col = 1, pt.bg = NA, pt.cex = par("cex"), pt.lwd = lwd, 
  text.cex = par("cex"), text.col = par("col"), text.font = NULL, text.vfont = NULL, 
  bty = "o", bbord = "black", bbg = par("bg"), blty = par("lty"), blwd = par("lwd"), bdens = NULL, bbx.adj = 0, bby.adj = 0.75 
) {

  ### get original par values and re-set them at end of function
  op <- par(no.readonly = TRUE)
  on.exit(par(op))

  ### new par with dimension [0,1]
  par(new=TRUE, xaxs="i", yaxs="i", xpd=TRUE)
  plot.new()

  ### spacing between legend elements
  d0 <- 0.01 * (1 + bbx.adj)
  d1 <- 0.01
  d2 <- 0.02
  pch.len <- 0.008
  ln.len <- seg.len/2

  n.lgd <- length(legend)

  txt.h <- strheight(legend[1], cex = text.cex, font = text.font, vfont = text.vfont) *(1 + bby.adj)
  i.pch <- seq(1, 2*n.lgd, 2)
  i.txt <- seq(2, 2*n.lgd, 2)

  ### determine x positions of legend elements
  X <- c(d0 + pch.len, pch.len + d1, rep(strwidth(legend[-n.lgd])+d2+pch.len, each=2))
  X[i.txt[-1]] <- pch.len+d1

  ### adjust symbol space if line is drawn
  if (any(lty != 0)) {
    lty <- rep(lty, n.lgd)[1:n.lgd]
    ln.sep <- rep(ln.len - pch.len, n.lgd)[lty]
    ln.sep[is.na(ln.sep)] <- 0
    X <- X + rep(ln.sep, each=2)
    lty[is.na(lty)] <- 0
  } 

  X <- cumsum(X)

  ### legend box coordinates
  bstart <- 0
  bend <- X[2*n.lgd]+strwidth(legend[n.lgd])+d0

  ### legend position
  if (pos == "top" | pos == "bottom" | pos == "center") x_corr <- 0.5 - bend/2 +xoff
  if (pos == "bottomright" | pos == "right" | pos == "topright") x_corr <- 1. - bend + xoff
  if (pos == "bottomleft" | pos == "left" | pos == "topleft") x_corr <- 0 + xoff

  if (pos == "bottomleft" | pos == "bottom" | pos == "bottomright") Y <- txt.h/2 + yoff
  if (pos == "left" | pos == "center" | pos =="right") Y <- 0.5 + yoff
  if (pos == "topleft" | pos == "top" | pos == "topright") Y <- 1  - txt.h/2 + yoff

  Y <- rep(Y, n.lgd)
  ### draw legend box
  if (bty != "n") rect(bstart+x_corr, Y-txt.h/2, x_corr+bend, Y+txt.h/2, border=bbord, col=bbg, lty=blty, lwd=blwd, density=bdens)

  ### draw legend symbols and text
  segments(X[i.pch]+x_corr-ln.len, Y, X[i.pch]+x_corr+ln.len, Y, col = ln.col, lty = lty, lwd = lwd)
  points(X[i.pch]+x_corr, Y, pch = pch, col = pt.col, bg = pt.bg, cex = pt.cex, lwd = pt.lwd)
  text(X[i.txt]+x_corr, Y, legend, pos=4, offset=0, cex = text.cex, col = text.col, font = text.font, vfont = text.vfont)

}

Аргументы

pos позиция легенды (c ( "нижняя", "нижняя", "прямая", "левая", "центральная", "правая", "верхняя", "верхняя", "прямая" ))

legend текст легенды

xoff регулировка положения по оси x. NB: легенда изображена на графике с пределами = c (0,1)

`yoff`` то же, что и xoff, но в y-directin

lty Тип линии. Типы строк могут быть указаны только как целое число (0 = пустое, 1 = твердое (по умолчанию), 2 = пунктирное, 3 = пунктирное, 4 = точка, 5 = длинная, 6 = twodash)

lwd Ширина линии, положительное число, по умолчанию 1

ln.col Цвет линии

seg.len Длина линии, глубина до 0,04

pch Целое число, определяющее символ.

pt.col Цвет символа.

pt.bg Цвет фона символа.

pt.cex коэффициент расширения для символа

`pt.lwd`` ширина строки символа

text.cex коэффициент расширения для текста

text.col цвет текста

text.font текстовый шрифт

text.vfont см. vfont в текстовой справке

bty тип окна, который будет нарисован вокруг легенды. Допустимые значения: "o" (по умолчанию) и "n"

bbord цвет рамки рамки легенды

bbg цвет фона

blty стиль рамки

blwd ширина линии границы

bdens плотность строк, см. раздел-help

bbx.adj относительное значение для увеличения расстояния между текстом и горизонтальной рамкой

bby.adj то же, что и bbx.adj, но для вертикальной боковой линии

К сожалению, у меня нет времени на создание пакета на данный момент. Но не стесняйтесь использовать эту функцию. Любые комментарии и идеи для улучшения функций приветствуются.

Некоторые примеры

plot(1:100, rnorm(100))
lgd.text <- c("12", "12")
sapply(c("bottomleft", "bottom", "bottomright", "left", "center", "right", "topleft", "top", "topright"), function(x) f.horlegend(x, lgd.text, pch=16, lty=c(NA, 1), bbg="orange"))


plot(1:100, rnorm(100))
lgd.text <- c("12", "132", "12345")
f.horlegend("topleft", lgd.text, pch=NA)
f.horlegend("top", lgd.text, pch=NA, bby.adj=1.5, bbord="red")
f.horlegend("left", lgd.text, xoff=0.2, pch=1, bby.adj=0, bbord="red", bbg="lightgreen")
f.horlegend("left", lgd.text, xoff=0.2, yoff=-0.05, pch=c(NA, 1, 6), lty=1, bbx.adj=2, bby.adj=0, bbord="red", bbg="lightgreen")

f.horlegend("topright", lgd.text, yoff=0.1, pch=c(1,2,NA), lty=c(NA, NA, 2), bbord="red", blty=2, blwd=2)

lgd.text <- c("12", "123456", "12345", "123")
f.horlegend("bottom", lgd.text, yoff=0.1, pch=c(1,2,NA), lty=c(NA, 1, 2), text.font=2)
f.horlegend("bottom", lgd.text, pch=c(1,2,NA), lty=c(NA, 1, 2), text.font=c(1,2,3))

plot(seq(as.POSIXct("2017-08-30"), as.POSIXct("2017-09-30"), by="weeks"), rnorm(5), type="l")
f.horlegend("topleft", "random values", lty=1)