37

plot()と の両方を呼び出す関数を作成したいと考えています。ユーザーがいくつかの追加の引数を指定してから、またはlegend()に渡すことができれば理想的です。を使用して2つの関数のいずれかでこれを達成できることを私は知っています:plot()legend()...

foo.plot <- function(x,y,...) {
    plot(x,y,...)
    legend("bottomleft", "bar", pch=1)
}

foo.plot(1,1, xaxt = "n")

xaxt = "n"これはプロットに渡されます。しかし、たとえば、関数ヘッダーで引数を事前に指定せずtitle = "legend"に呼び出しに渡す方法はありますか?legend()


受け入れられた回答からの更新: VitoshKa の方法は、私が望むことを達成するのに最もエレガントだと思いました。ただし、希望どおりに機能するまで、回避しなければならない小さな問題がいくつかありました。

最初に、どのパラメーターに渡しlegend、どのパラメーターに渡すかを確認しましたplot。この目的のための最初のステップは、どの引数がplot および/または par にlegend固有で、一部ではないかを確認することでした。legend

legend.args <- names(formals(legend))
plot.args <- c(names(formals(plot.default)), names(par()))
dput(legend.args[!(legend.args %in% plot.args)])

私がdput()ここで使用するのは、行plot.args <- c(names(formals(plot.default)), names(par()))が常に私が望まない新しい空のプロットを呼び出すためです。dputそのため、次の関数での出力を使用しました。

次に、重複する引数に対処する必要がありました ( 経由で取得しますdput(largs.all[(largs.all %in% pargs.all)]))。いくつかの場合、これは些細なことでした (例: )。他xyものは両方の関数に渡されます (例: pch)。しかし、私の実際のアプリケーションでは、他の戦略も使用しています (たとえば、 の変数名は異なりますadjが、この例では実装されていません)。

最後に、do.call関数を 2 つの方法で変更する必要がありました。まず、what の部分 (つまり、関数と呼ばれる部分) は文字にする必要があります (つまり、 の'plot'代わりにplot)。また、引数リストは少し異なる方法で作成する必要があります。

foo.plot <- function(x,y,...) {
    leg.args.unique <- c("legend", "fill", "border", "angle", "density", "box.lwd", "box.lty", "box.col", "pt.bg", "pt.cex", "pt.lwd", "xjust", "yjust", "x.intersp", "y.intersp", "text.width", "text.col", "merge", "trace", "plot", "ncol", "horiz", "title", "inset", "title.col", "title.adj")
    leg.args.all <- c(leg.args.unique, "col", "lty", "lwd", "pch", "bty", "bg", "cex", "adj", "xpd")
    dots <- list(...)
    do.call('plot', c(list(x = x, y = x), dots[!(names(dots) %in% leg.args.unique)]))
    do.call('legend', c(list("bottomleft", "bar"), dots[names(dots) %in% leg.args.all]))
}


foo.plot(1,1,pch = 4, title = "legendary", ylim = c(0, 5))

この例でpchは、 は と の両方plotに渡されlegend、はとのみにtitle渡されます。legendylimplot


Gavin Simpson のコメントに基づく更新 2 (Vitoshka の回答のコメントも参照):
(i) その通りです。
(ii) いつでも文字にできます。ただし、関数と同じ名前の変数がある場合は、関数名を で引用する必要がありますdo.call

min.plot <- function(x,y,plot=TRUE) if(plot == TRUE) do.call(plot, list(x = x, y = y))
min.plot(1,1)
Error in do.call(plot, list(x = x, y = y)) : 
  'what' must be a character string or a function

(iii) 使用できc(x = 1, y = 1, list())、正常に動作します。しかし、私が実際に行ったこと (私が与えた例ではなく、私の実際の関数) は次のとおりです:これを 次とc(x = 1, y = 1, xlim = c(0, 2), list(bla='foo'))
比較してください:リストには(長さ 2 のベクトルで、私が欲しかったものです) しかありません。c(list(x = 1, y = 1, xlim = c(0, 2)), list(bla='foo'))
xlimxlim1xlim2xlim

したがって、あなたは私の例についてすべての点で正しいです。しかし、私の実際の関数 (より多くの変数を使用) では、これらの問題に遭遇したため、ここで文書化したいと思いました。不正確で申し訳ありません。

4

4 に答える 4

25

自動的な方法:

foo.plot <- function(x,y,...) {
    lnames <- names(formals(legend))
    pnames <- c(names(formals(plot.default)), names(par()))
    dots <- list(...)
    do.call('plot', c(list(x = x, y = x), dots[names(dots) %in% pnames]))
    do.call('legend', c("bottomleft", "bar", pch = 1, dots[names(dots) %in% lnames]))
}

legendユーザーが「pch」を指定した場合に呼び出しで重複を避けるために、lnames から pch をフィルタリングする必要がありますが、アイデアは得られました。2012 年 1 月に Carl W によって編集: "do.call" は、Henrik による更新のように、引用符で囲まれた関数でのみ機能します。将来の混乱を避けるために、ここで編集しました。

于 2010-11-08T21:47:33.033 に答える
18

これらは扱いにくく、関数に追加の引数を指定しないと簡単な解決策はありません。と...の両方の呼び出しがあった場合、特定の引数を渡すときに警告が表示されます。たとえば、次のようにします。plotlegendlegend

foo.plot <- function(x,y,...) {
    plot(x,y,...)
    legend("bottomleft", "bar", pch = 1, ...)
}

次の警告が表示されます。

> foo.plot(1, 1, xjust = 0.5)
Warning messages:
1: In plot.window(...) : "xjust" is not a graphical parameter
2: In plot.xy(xy, type, ...) : "xjust" is not a graphical parameter
3: In axis(side = side, at = at, labels = labels, ...) :
  "xjust" is not a graphical parameter
4: In axis(side = side, at = at, labels = labels, ...) :
  "xjust" is not a graphical parameter
5: In box(...) : "xjust" is not a graphical parameter
6: In title(...) : "xjust" is not a graphical parameter

この問題を回避する方法があります。 などの関数のラッパーとして定義されているローカル関数を参照しplot.defaultてください。直接ではなく、ラッパー、インライン関数のようなものがあり、それを呼び出します。axisboxlocalPlot()plot()

bar.plot <- function(x, y, pch = 1, ...) {
    localPlot <- function(..., legend, fill, border, angle, density,
                          xjust, yjust, x.intersp, y.intersp,
                          text.width, text.col, merge, trace, plot = TRUE, ncol,
                          horiz, title, inset, title.col, box.lwd,
                          box.lty, box.col, pt.bg, pt.cex, pt.lwd) plot(...)
    localPlot(x, y, pch = pch, ...)
    legend(x = "bottomleft", legend = "bar", pch = pch, ...)
}

(引数にデフォルトが必要な理由は'plot'私にはわかりませんが、デフォルトを指定しないと機能しませんTRUE。)

これで警告なしで動作します:

bar.plot(1, 1, xjust = 0.5, title = "foobar", pch = 3)

btyたとえば、グラフィカル パラメータをどのように処理するかは、あなた次第ですbty。プロット ボックスのタイプと凡例ボックスのタイプに影響します。'pch'誰かが呼び出しでその引数を使用すると、i) 凡例/プロットで異なる文字を使用し、 2 回一致するbar.plot()ことに関する警告またはエラーが発生するため、私は別の方法で処理したことにも注意してください。'pch'

ご覧のとおり、これはかなりトリッキーになり始めています...


Joris' Answer は興味深い解決策を提供します。私がコメントしたのは、 のような関数のコントロール リストの引数を思い出させるものlme()でした。これが、このコントロールリストのアイデアを実装した Joris' Answer の私のバージョンです。

la.args <- function(x = "bottomleft", legend = "bar", pch = 1, ...)
    c(list(x = x, legend = legend, pch = pch), list(...))

foo.plot <- function(x,y, legend.args = la.args(), ...) {
    plot(x, y, ...)
    do.call(legend, legend.args)
}

これは、適切に変更された Jori の 2 番目の呼び出し例を使用して、次のように機能します。

foo.plot(1,1, xaxt = "n", legend.args=la.args(bg = "yellow", title = "legend"))

関数を設定するときは、好きなだけ完全にすることができます。la.args()ここでは、Joris が設定した引数のデフォルトのみを設定し、他の引数を連結します。la.args()すべての凡例引数がデフォルトで含まれていると、より簡単になります。

于 2010-11-08T15:36:06.967 に答える
6

1つの方法は、引数のリストを。と組み合わせて使用​​することdo.callです。これは最も美しいソリューションではありませんが、機能します。

foo.plot <- function(x,y,legend.args,...) {
    la <- list(
        x="bottomleft",
        legend="bar",
        pch=1
    )
    if (!missing(legend.args)) la <- c(la,legend.args)
    plot(x,y,...)
    do.call(legend,la)
}
foo.plot(1,1, xaxt = "n")    
foo.plot(1,1, xaxt = "n",legend.args=list(bg="yellow",title="legend"))

1つの欠点は、たとえば、legend.argsリストでpch=2などを指定できないことです。いくつかのif句を使用してそれを回避できます。さらにいじくりまわすために、それをあなたに任せます。


編集:このアイデアのより良いバージョンについては、GavinSimpsonの回答を参照してください。

于 2010-11-08T15:34:26.730 に答える