5

ggplot のループを使用して多くのグラフを生成することに関する多くの投稿を読みましたが、私の問題を説明するものは見つかりません...

データフレームがあり、92 列をループして、列ごとに新しいグラフを作成しようとしています。各プロットを個別のオブジェクトとして保存したい。ループ (以下のコード) を実行してグラフを印刷すると、すべてのグラフが正しく表示されます。ただし、print() コマンドを assign() で変更すると、グラフが正しくありません。タイトルは変更されていますが、グラフの値はすべて同じです (最終的なグラフのすべての値です)。これを見つけたのは、plot_grid() を使用して 10 個のプロットの図を生成したとき、グラフのタイトルと軸のラベルはすべて正しいのに、値が同じだったからです。

私のデータセットは大きいので、下の図に小さなデータセットを用意しました。

サンプルデータ名:

library(ggplot)
library(cowplot)
df <- as.data.frame(cbind(group=c(rep("A", 4), rep("B", 4)), a=sample(1:100, 8), b=sample(100:200, 8), c=sample(300:400, 8))) #make data frame
cols <- 2:4 #define columns for plots
for(i in 1:length(cols)){
  df[,cols[i]] <- as.numeric(as.character(df[,cols[i]]))
} #convert columns to numeric

プロット:

for (i in 1:length(cols)){
  g <- ggplot(df, aes(x=group, y=df[,cols[i]])) +
    geom_boxplot() +
    ggtitle(colnames(df)[cols[i]])
  print(g)
  assign(colnames(df)[cols[i]], g) #generate an object for each plot
}

plot_grid(a, b, c)

ggplots がプロットを作成すると、i の最終値からのデータのみがレンダリングされると考えていますか? それともそのようなものですか?これを回避する方法はありますか?

作成したいグラフがたくさんあり、図のプロットを組み合わせて一致させたいので、このようにしたいと思います。

ありがとう!

4

2 に答える 2

4

サンプル データ フレームの生成方法を整理しました。

library(ggplot2)
library(cowplot)

df <- data.frame(group=c(rep("A", 4), rep("B", 4)),
                          a=sample(1:100, 8),
                          b=sample(100:200, 8),
                          c=sample(300:400, 8)) #make data frame

data.frame() を使用するだけで十分です。これにより、コードがより明確になり、「for ループ」でデータフレームを数値に変換し、生成された要素を削除するための後処理が不要になります。 「stringsAsFactors = FALSE」がなく、cbind() ではなく cbind.data.frame() を使用することで数値から文字への変換を回避できる場合は、因数分解します。

また、プロットを生成する「for ループ」もリファクタリングしました。'cols' (cols <- 2:4 ) と呼ばれる整数のリストを生成し、それを繰り返してデータの各列からプロットを生成します。これは不要です。for ステートメント条件で範囲を作成するだけです - 'for (i in 2:ncol(df))' - これは単純に 2 から 4 (データフレーム内の列の数) まで繰り返します - 2 から始まりますメタデータを含む列 1 を避けるために必要です。これは次の理由で望ましいです。

i) コードを確認すると、コードの残りの部分を検索しなくても、使用されている条件がすぐにわかります

ii) R には、変数「cols」に似た名前の関数/パラメーターが多数あり、混乱を避けるのが最善です。

コードがクリーンアップされたので、バグの原因を突き止めることができます。

library(ggplot2)
library(cowplot)

df <- data.frame(group=c(rep("A", 4), rep("B", 4)),
                          a=sample(1:100, 8),
                          b=sample(100:200, 8),
                          c=sample(300:400, 8)) #make data frame


for (i in 2:ncol(df)){

  g <- ggplot(df, aes(x=group, y=df[,i])) +
    geom_boxplot() +
    ggtitle(colnames(df)[i])

  print(g)
  assign(colnames(df)[i], g) #generate an object for each plot
}   

コードが機能しない理由はすぐにはわかりません。Imo の提案にはメリットがあります。プロットをリストに保存すると、環境がオブジェクトで雑然とするのを防ぐことができますが、このバグは解決されません。その原因は直観的ではなく、assign() 関数がどのように評価されるかについて深く理解する必要があります。ここKonrad Rudolphが提供する回答を参照してください。以下は機能し、元のコードのスタイルを保持するはずです。コンラッドが彼の答えで示唆しているように、ラップリーを使用するのはより「R」のようかもしれません。for ループを指定したことに注意してくださいローカル スコープであり、i をローカルに再定義するようになりました。以前は、ループで生成された i の最後の値が、assign() 関数を介して作成された各オブジェクトの生成に使用されていました。g をグローバル環境に割り当てるために <<- を使用していることに注意してください。

for (i in 2:ncol(df))  
     local({
  i <- i
  g <<- ggplot(df, aes(x=group, y=df[,i])) +
    geom_boxplot() +
    ggtitle(colnames(df)[i])
  print(i)
  print(g)
  assign(colnames(df)[i], g, pos =1) #generate an object for each plot
     })

plot_grid(a, b, c)

あなたは私に飲み物を借りています。

于 2016-04-14T17:00:17.417 に答える
2

この問題に対処するには、次の 2 つの標準的な方法があります。

1- 長い形式の data.frame を操作する

2-aes_stringワイド フォーマット data.frame で変数名を参照するために使用します。

考えられる戦略の例を次に示します。

library(ggplot2)
library(gridExtra)

# data from other answer
df <- data.frame(group=c(rep("A", 4), rep("B", 4)),
                 a=sample(1:100, 8),
                 b=sample(100:200, 8),
                 c=sample(300:400, 8))

## first method: long format
m <- reshape2::melt(df, id = "group")
p <- ggplot(m, aes(x=group, y=value)) +
    geom_boxplot() 

pl <- plyr::dlply(m, "variable", function(.d) p %+% .d + ggtitle(unique(.d$variable)))
grid.arrange(grobs=pl)

## second method: keep wide format
one_plot <- function(col = "a")  ggplot(df, aes_string(x="group", y=col)) +  geom_boxplot() + ggtitle(col)
pl <- plyr::llply(colnames(df)[-1], one_plot)
grid.arrange(grobs=pl)

## third method: more explicit looping

pl <- vector("list", length = ncol(df)-1)
for(ii in seq_along(pl)){
  .col <- colnames(df)[-1][ii]
  .p <- ggplot(df, aes_string(x="group", y=.col)) +  geom_boxplot() + ggtitle(.col)
  pl[[ii]] <- .p
}

grid.arrange(grobs=pl)

関数/ for ループ内で ggplot 呼び出しをラップすると、ローカル変数の問題に直面することがあります (aes_string使用されている場合は、ここでは当てはまりません)。このような場合、ローカル環境を定義できます。

like の構文を使用すると、動作しているようaes(y=df[,i])に見えますが、非常に間違った結果が生じる可能性があることに注意してください。ファセット化された plot を考えてみましょうaes()。data.frame はパネルごとに異なるグループに分割されます。変数名の代わりに数値が直接渡されると、このサブセット化は適切なデータをグループ化するのに無残に失敗する可能性があります。

于 2016-04-15T21:50:28.350 に答える