2016-04-14 11 views
4

を生成し、私はグラフの多くを生成するggplotためのループを使用する方法についての記事をたくさん読みましたが、私の問題を説明しているいずれかを見つけることができません...が同じ値を持つグラフが異なる見出し

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

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

サンプルdatafame:

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のプロットを作るとき、それは私だけの最終値からのデータをレンダリングすることを考えていますか?それとも何か?これを回避する方法はありますか?

グラフの数が多いので、私はそれをしたいと思うし、図のためにプロットを混ぜ合わせたい。

ありがとうございます!

答えて

2

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

2 - 長い形式のdata.frameと

の1-作業はワイドフォーマットdata.frameに変数名を参照するためにaes_stringを使用して、

ここに、可能な戦略の図があります。

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) 

関数内ggplot呼び出しをラップするとき(aes_stringが使用される場合、ここでない場合、)時には、/ forループ一つはローカル変数の問題に直面しています。そのような場合には、define a local environmentがあります。

aes(y=df[,i])のような構文を使用すると動作するように見えますが、間違った結果が生じることがあります。 Consider a facetted plotの場合、data.frameは各パネルごとに異なるグループに分割され、変数名の代わりに数値が直接aes()に渡された場合、このサブセット化は偶然失敗して正しいデータをグループ化できません。

3

サンプルデータフレームをどのように生成したかを整理しました。

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ループ'の後処理がすべてデータフレームを数値に変換し、生成された要素を削除する必要がなくなります。as.data.frame()およびcbind()はデフォルト'stringsAsFactors = FALSE'がなく、cbind()ではなくcbind.data.frame()を使用することで、数値から文字への変換を避けることができます。

私はあなたのプロットを生成する 'forループ'もリファクタリングしました。 'cols'(cols < - 2:4)という整数のリストを生成し、各データ列からプロットを生成するために繰り返します。これは不要ですが、for文の条件で範囲を作成することができます - 'for(i in 2:ncol(df))' - これは2から4(データフレーム内の列数)メタデータを含む列1を避ける必要があります。 )Rは、同様にあなたの変数「colsのに名前付き関数/パラメータの数を持っている

私は)あなたのコードを確認するときに使用条件はあなたのコードの残りを

IIを検索しなくてもすぐには明らかである:これは望ましいです混乱を避けることが最善です。クリーンアップコードで

我々は今、バグの原因を突き止めることを試みることができます。

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()関数の評価方法を深く理解する必要があります。答えはhereKonrad Rudolphで提供されています。次のコードは元のコードのスタイルを保持します。 Konradが彼の答えで示唆するように、lapplyを使うような "R"がもっとあるかもしれません。ループのローカルスコープのを与え、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) 

私には飲み物があります。

+0

詳細な回答Graemeに感謝します。私は地元のことを考え、 '私'を再定義する必要があります。 – Harry

+0

'aes()'は 'df [、i]'のような数値ベクトルではなく、変数名を参照する必要があります。これを行うと、間違ったデータを気付かずにプロットするなど、予期しない結果が生じることがあります。 '<< - 'や 'assign'を使うことは、ほとんどの場合、Rの問題について間違った方向へ行くという明確な兆候ではありません。 – baptiste

関連する問題