Der Grund rgl:par3d()
gibt nichts zurück ist, weil die rgl
Pakete nicht wirklich die Szene für glänzend verwaltet. Die Javascript basierte rglwidget
Bibliothek, die WebGL
nutzt, verwaltet es, und Sie kopieren über die Szene in eine andere sehr kompatible GL-Bibliothek (vielleicht verwenden sie sogar die gleiche kompilierte Bibliothek, aber ich bezweifle es) und das in glänzendem anzeigen. So rgl.dev()
wird dir nicht helfen.
AFAIK, es ist nicht leicht, diese Werte zu erhalten, da sie in rglwidget
Javascript versteckt sind, aber ich wollte auf sie zu bekommen, so baute ich eine glänzende benutzerdefinierte Eingabesteuerung, die es tun kann. Es war ziemlich viel Arbeit, und es könnte einen einfacheren Weg geben, aber ich habe es nicht gesehen und weiß zumindest, wie man jetzt benutzerdefinierte Eingabesteuerungen für glänzend baut. Wenn jemand einen leichteren Weg kennt, bitte erleuchte mich.
Hier ist das Javascript, es geht in einen www
Unterordner, den Sie im selben Verzeichnis wie Ihr glänzender Code speichern.
rglwidgetaux.js
// 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);
ist die R/glänzend Code. Es verwendet die übliche Testszene und verfügt über eine Schaltfläche zum Abfragen der Szenen userMatrix
und zeigt diese in einer Tabelle an. Ich habe die userMatrix
und nicht die modelMatrix
verwendet, weil die ehemalige ist einfach mit der Maus zu ändern, so können Sie sehen, dass Sie die frischesten Werte erhalten.
Beachten Sie, dass der Name "app.R" nicht wirklich optional ist. Entweder Sie müssen das verwenden, oder teilen Sie die Datei in "ui.R" und "server.R", sonst wird die oben genannte JavaScript-Datei nicht importiert.
app.R
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)
Und hier endlich ist, wie es aussieht:
Bitte beachte, dass ich es so einrichten, können Sie Befehle, um es hinzuzufügen, man konnte (wahrscheinlich) Ändern Sie Parameter und alles andere mit einer Steuerung, die auf diesem basiert.
Beachten Sie auch, dass die par3d
Struktur hier (zu json umgewandelt und dann zu R aus dem rglwidget
JavaScript) und die in rgl
sind nicht ganz identisch, so zum Beispiel ich die userMatrix
abzuflachen hatte als WebGL es zu bevorzugen scheint, als eine Namensliste im Gegensatz zu den anderen Matrizen, die wie erwartet kamen.
Ich sehe nicht, wie deine Shiny-App irgendetwas tut, um die Matrix anzuzeigen, aber ich weiß nicht, dass Shiny gut genug ist, um zu wissen, dass es falsch ist. Nur für den Fall, dass es in Ordnung ist: Die open3d() - Funktion gibt einen Wert der rgl-Gerätenummer zurück, die geöffnet wurde, und par3d() hat ein optionales Argument "dev", das ein bestimmtes Gerät abfragen kann. Vielleicht, wenn Sie diese verwenden, bekommen Sie, was Sie wollen. – user2554330
Haben Sie ein Feedback für mich? –
Bist du da? Hast du meine Antwort versucht? –