20

これは、実際には 2 つの質問を 1 つにまとめたものです (SO 規則に違反するかどうかはわかりませんが、とにかく)。

最初の質問は、 を に強制的geom_textに収めるにはどうすればよいgeom_barですか? (プロットされた値に応じて動的に)

周りを見回すと、私が見つけた解決策はラベルのサイズを変更していました. それは確かに機能しますが、すべての場合に当てはまるわけではありません。特定のプロットのサイズを変更して、テキストがバー内に収まるようにすることができますが、データが変更された場合は、テキストのサイズを手動で再度変更する必要がある場合があります。私の実際の問題は、絶えず変化するデータ (毎日) に対して同じプロットを生成する必要があることです。そのため、各プロットのサイズを実際に手動で調整することはできません。

データの関数としてラベルのサイズを設定してみました。完全ではありませんが、多くの場合に機能します。

しかし、ラベルがバー内に収まる場合でも、プロットのサイズを変更するとすべてが台無しになるという別の問題があります。調べてみると、ggplotのドキュメントにもありました

ラベルには高さと幅がありますが、データ単位ではなく物理単位です。そのプロットで占有するスペースの量は、データ単位で一定ではありません。プロットのサイズを変更すると、ラベルは同じサイズのままですが、軸のサイズが変わります。

2 番目の質問: このデフォルトの動作を変更して、プロットに合わせてラベルのサイズを変更することはできますか?

また、最初の質問を改善させてください。物理単位とデータ単位の間の巧妙な関係を使用してテキストのサイズを動的に設定し、geom_textを 内に収まるように強制することは可能ですか?geom_bar

したがって、良い習慣に従うために、再現可能な例を次に示します。

set.seed(1234567)
data_gd <- data.frame(x = letters[1:5], 
                      y = runif(5, 100, 99999))

ggplot(data = data_gd,
       mapping = aes(x = x, y = y, fill = x)) +
    geom_bar(stat = "identity") +
    geom_text(mapping = aes(label = y, y = y/2))

このコードは、次のプロットを生成します。

ここに画像の説明を入力

単純にプロットのサイズを変更すると、「ラベルは同じサイズのままですが、軸のサイズが変更されます」ため、ラベルがバーに収まるようになります (ラベルが小さすぎる可能性があります)。

ここに画像の説明を入力

それで、これは私の2番目の質問です。ラベルのサイズも変更され、バーに対する縦横比が保たれるとよいでしょう。これを達成する方法、またはそれが可能かどうかについてのアイデアはありますか?

わかりましたが、バー内にラベルを合わせる方法に戻ると、最も簡単な解決策はラベルのサイズを設定することです。

ggplot(data = data_gd,
       mapping = aes(x = x, y = y, fill = x)) +
    geom_bar(stat = "identity") +
    geom_text(mapping = aes(label = y, y = y/2), size = 3)

繰り返しますが、これは以下に示すように機能しますが、データの変更に対して保守可能ではなく、堅牢でもありません。

ここに画像の説明を入力

たとえば、異なるデータを使用してプロットを生成するまったく同じコードが壊滅的な結果をもたらします。

data_gd <- data.frame(x = letters[1:30], 
                      y = runif(30, 100, 99999))
ggplot(data = data_gd,
       mapping = aes(x = x, y = y, fill = x)) +
    geom_bar(stat = "identity") +
    geom_text(mapping = aes(label = y, y = y/2), size = 3)

ここに画像の説明を入力

例を続けて、ラベルのサイズを x 軸のカテゴリ数の関数として設定します。しかし、あなたは要点を理解しています。おそらく、あなたのggplot2専門家の 1 人が私にアイデアを提供してくれるでしょう。

4

2 に答える 2

15

1 つのオプションは、バーの幅によって設定された割り当てられたスペース内に収まるように、カスタム drawDetails メソッドで textGrob を使用する geom を作成することです。

library(grid)
library(ggplot2)

fitGrob <- function(label, x=0.5, y=0.5, width=1){
  grob(x=x, y=y, width=width, label=label, cl = "fit")
}
drawDetails.fit <- function(x, recording=FALSE){
  tw <- sapply(x$label, function(l) convertWidth(grobWidth(textGrob(l)), "native", valueOnly = TRUE))
  cex <- x$width / tw
  grid.text(x$label, x$x, x$y, gp=gpar(cex=cex), default.units = "native")
}


`%||%` <- ggplot2:::`%||%`

GeomFit <- ggproto("GeomFit", GeomRect,
                   required_aes = c("x", "label"),

                   setup_data = function(data, params) {
                     data$width <- data$width %||%
                       params$width %||% (resolution(data$x, FALSE) * 0.9)
                     transform(data,
                               ymin = pmin(y, 0), ymax = pmax(y, 0),
                               xmin = x - width / 2, xmax = x + width / 2, width = NULL
                     )
                   },
                   draw_panel = function(self, data, panel_scales, coord, width = NULL) {
                     bars <- ggproto_parent(GeomRect, self)$draw_panel(data, panel_scales, coord)
                     coords <- coord$transform(data, panel_scales)    
                     width <- abs(coords$xmax - coords$xmin)
                     tg <- fitGrob(label=coords$label, y = coords$y/2, x = coords$x, width = width)

                     grobTree(bars, tg)
                   }
)

geom_fit <- function(mapping = NULL, data = NULL,
                     stat = "count", position = "stack",
                     ...,
                     width = NULL,
                     binwidth = NULL,
                     na.rm = FALSE,
                     show.legend = NA,
                     inherit.aes = TRUE) {

  layer(
    data = data,
    mapping = mapping,
    stat = stat,
    geom = GeomFit,
    position = position,
    show.legend = show.legend,
    inherit.aes = inherit.aes,
    params = list(
      width = width,
      na.rm = na.rm,
      ...
    )
  )
}


set.seed(1234567)
data_gd <- data.frame(x = letters[1:5], 
                      y = runif(5, 100, 99999))

ggplot(data = data_gd,
       mapping = aes(x = x, y = y, fill = x, label=round(y))) +
  geom_fit(stat = "identity") +
  theme()

ここに画像の説明を入力

于 2016-03-31T08:22:59.520 に答える