私は光沢のあるアプリを持っていて、それにrgl3d-plotを統合しています。パッケージrenderRglwidget
から、rglwidget
webglを使用してrglグラフィックを光沢のあるアプリに挿入するために使用しています。
アプリでは、ユーザーはグラフィックを回転させることができます。ここで、回転状態を保存したいので、userMatrixまたはmodelMatrixを使用して、ユーザーが前のグラフを離れたときと同じ回転で同様のプロットを後で生成します。
ここでは、userMatrixやその他のパラメーターを格納するJava変数について説明します。光沢のあるアプリ内から(Rコードで)それらにアクセスできますか?
rgl自体で、モデルの回転を使用rotationMatrix <- rgl.projection()$model
またはrotationMatrix <- par3d()$modelMatrix
保存できます。しかし、私の場合、グラフィックはrgl自体で回転されていないため、これらの関数は役に立ちません。
私が試したのはこれです:
library(shiny)
library(rgl)
library(rglwidget)
ui <- fluidPage(
rglwidgetOutput("3D-plot"),
actionButton("showMatrix", "show rotation Matrix")
)
server <- function(input, output, session){
open3d(useNULL = T)
x <- sort(rnorm(1000))
y <- rnorm(1000)
z <- rnorm(1000) + atan2(x, y)
plot3d(x, y, z, col = rainbow(1000))
scene1 <- scene3d()
rgl.close()
output$"3D-plot" <- renderRglwidget({
rglwidget(scene1)
})
observe({
input$showMatrix
par3d()$modelMatrix
})
}
shinyApp(ui=ui, server=server)
しかし、par3d()$modelMatrix
何も返さないようです。
その理由は、rgl:par3d()
何も返さないためであるrgl
パッケージは実際に光沢のためのシーンを管理していません。rglwidget
活用するjavascriptベースのライブラリがそれWebGL
を管理しており、シーンを別の非常に互換性のあるGLライブラリにコピーして(おそらく同じコンパイル済みライブラリを使用しているかもしれませんが、疑わしいです)、それを光沢のある状態で表示しています。だからrgl.dev()
あなたを助けません。
AFAIK、これらの値はrglwidget
javascriptに隠されているため、簡単に取得することはできませんが、取得したかったので、それを実行できる光沢のあるカスタム入力コントロールを作成しました。それはかなりの量の作業であり、もっと簡単な方法があるかもしれませんが、私はそれを見ませんでした、そして少なくとも今は光沢のあるカスタム入力コントロールを構築する方法を知っています。誰かがもっと簡単な方法を知っているなら、私に教えてください。
これがjavascriptです。これはwww
、光沢のあるコードと同じディレクトリに保存するサブフォルダに入ります。
// rglwidgetaux control for querying shiny rglwiget
var rglwidgetauxBinding = new Shiny.InputBinding();
$.extend(rglwidgetauxBinding, {
find: function(scope) {
return $(scope).find(".rglWidgetAux");
},
getValue: function(el) {
return el.value;
},
setValue: function(el, value) {
// $(el).text(value);
el.value = value;
},
getState: function(el) {
return { value: this.getValue(el) };
},
receiveMessage: function(el, data) {
var $el = $(el);
switch (data.cmd) {
case "test":alert("Recieved Message");
break;
case "getpar3d":
var rglel = $("#"+data.rglwidgetId);
if (rglel.length===0){
alert("bad rglwidgetId:"+ data.rglwidgetId);
return null;
}
var rglinst = rglel[0].rglinstance;
var sid = rglinst.scene.rootSubscene;
var par3d = rglinst.getObj(sid).par3d;
this.setValue(el,JSON.stringify(par3d));
$el.trigger("change"); // tell myself that I have changed
break;
}
},
subscribe: function(el, callback) {
$(el).on("change.rglwidgetauxBinding", function(e) {
callback();
});
},
unsubscribe: function(el) {
$(el).off(".rglwidgetauxBinding");
}
});
Shiny.inputBindings.register(rglwidgetauxBinding);
これがR / shinyコードです。通常のテストシーンを使用し、シーンをクエリuserMatrix
してテーブルに表示するためのボタンがあります。前者はマウスで簡単に変更できるので、userMatrix
ではなくを使用しましたmodelMatrix
。これにより、最新の値を取得していることがわかります。
「app.R」という名前は実際にはオプションではないことに注意してください。それを使用するか、ファイルを「ui.R」と「server.R」に分割する必要があります。そうしないと、上記のjavascriptファイルがインポートされません。
library(shiny)
library(rgl)
library(htmlwidgets)
library(jsonlite)
rglwgtctrl <- function(inputId, value="", nrows, ncols) {
# This code includes the javascript that we need and defines the html
tagList(
singleton(tags$head(tags$script(src = "rglwidgetaux.js"))),
tags$div(id = inputId,class = "rglWidgetAux",as.character(value))
)
}
ui <- fluidPage(
rglwgtctrl('ctrlplot3d'),
actionButton("regen", "Regen Scene"),
actionButton("queryumat", "Query User Matrix"),
rglwidgetOutput("plot3d"),
tableOutput("usermatrix")
)
server <- function(input, output, session)
{
observe({
# tell our rglWidgetAux to query the plot3d for its par3d
input$queryumat
session$sendInputMessage("ctrlplot3d",list("cmd"="getpar3d","rglwidgetId"="plot3d"))
})
output$usermatrix <- renderTable({
# grab the user matrix from the par3d stored in our rglWidgetAux
# note we are using two different "validate"s here, which is quite the pain if you
# don't notice that it is declared in two different libraries
shiny::validate(need(!is.null(input$ctrlplot3d),"User Matrix not yet queried"))
umat <- matrix(0,4,4)
jsonpar3d <- input$ctrlplot3d
if (jsonlite::validate(jsonpar3d)){
par3dout <- fromJSON(jsonpar3d)
umat <- matrix(unlist(par3dout$userMatrix),4,4) # make list into matrix
}
return(umat)
})
scenegen <- reactive({
# make a random scene
input$regen
n <- 1000
x <- sort(rnorm(n))
y <- rnorm(n)
z <- rnorm(n) + atan2(x, y)
plot3d(x, y, z, col = rainbow(n))
scene1 <- scene3d()
rgl.close() # make the app window go away
return(scene1)
})
output$plot3d <- renderRglwidget({ rglwidget(scenegen()) })
}
shinyApp(ui=ui, server=server)
そして最後にこれがどのように見えるかです:
コマンドを追加できるように設定したことに注意してください。これに基づくコントロールを使用して、(おそらく)パラメーターやその他のものを変更できます。
また、par3d
ここの構造(jsonに変換されてからrglwidget
javascriptからRに変換される)との構造rgl
は完全に同一ではないことに注意してください。たとえばuserMatrix
、WebGLは他の構造よりも名前リストとしてそれを好むようであるため、フラット化する必要がありました。期待通りにやってきた行列。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加