2015-05-28 13 views
16

Sto utilizzando Shiny per creare una semplice applicazione Web con un slider che controlla quali valori di p devono essere visualizzati nell'output.Dispositivo di scorrimento lucido su scala logaritmica

Come si può far agire il cursore su una scala logaritmica, piuttosto che lineare?

Al momento ho:

sliderInput("pvalue", 
      "PValue:", 
      min = 0, 
      max = 1e-2, 
      value = c(0, 1e-2) 
), 

Grazie!

+2

'input_slider' da' ggvis' ha un argomento 'map'. Puoi usare 'ggivs' direttamente o guardare l'implementazione dell'argomento della mappa. – shadow

+0

Penso che potrei ottenere un javascript molto semplice per risolverlo, non dovrebbe essere più di poche righe, potresti mostrarci esattamente cosa vuoi? –

risposta

11

non ero sicuro di quello che si voleva, come l'uscita, ma quello che ho fatto è stato hanno i possibili valori di p siano [0, 0,00001, 0,0001, 0,001, 0,01]. Se vuoi qualcosa di diverso, spero che questa risposta sia un buon punto di partenza.

Fondamentalmente, per prima cosa ho creato un array che contiene i valori dei numeri (0, 0.0000.1, ...), quindi utilizzo la funzione di aggiornamento speciale dall'API del cursore per rendere questi valori conformi slider. È piuttosto semplice una volta capito come usare l'API del cursore. Inoltre, per qualche ragione l'esecuzione di questo all'interno di RStudio sembra strano, ma in un browser va bene. Inoltre, nota che ho un ritardo di 5 ms perché voglio assicurarmi che questo funzioni dopo che il cursore è stato inizializzato. Non è la soluzione più pulita, probabilmente c'è un modo migliore per farlo, ma funziona.

library(shiny) 

JScode <- 
    "$(function() { 
    setTimeout(function(){ 
     var vals = [0]; 
     var powStart = 5; 
     var powStop = 2; 
     for (i = powStart; i >= powStop; i--) { 
     var val = Math.pow(10, -i); 
     val = parseFloat(val.toFixed(8)); 
     vals.push(val); 
     } 
     $('#pvalue').data('ionRangeSlider').update({'values':vals}) 
    }, 5)})" 

runApp(shinyApp(
    ui = fluidPage(
    tags$head(tags$script(HTML(JScode))), 

    sliderInput("pvalue", 
       "PValue:", 
       min = 0, 
       max = 1e-2, 
       value = c(0, 1e-2) 
    ) 
), 
    server = function(input, output, session) { 
    } 
)) 
+0

OP/generoso richiedente: è questo quello che volevi? –

+0

Questo sembra davvero buono, ma qualcosa di strano accade con le etichette, è come se fossero tutte concatenate - qualche idea? – alexwhan

+1

Hmm sul mio browser hanno un bell'aspetto (in RStudio sono tutti raggruppati). Ti sembra strano in un browser vero? Penso che potrebbe essere a causa del problema in virgola mobile (se si guardano i numeri, sono come ".00010000000000002"), quindi la soluzione sarebbe quella di arrotondarli a 5 cifre o di costruire i numeri come stringhe anziché di 10^-n –

0

Il motivo per cui la domanda non ha ottenuto più attenzione è che è difficile rispondere. Per fare ciò che vuole il richiedente, devi scrivere javascript e inserirlo nella pagina web. Di seguito è riportato il codice che ho adattato per formattare correttamente un cursore shiny come date. Non ho provato a modificarlo per logaritmico perché ho solo imparato abbastanza javascript per armeggiare con questo script, e poi prontamente cancellato dalla memoria per fare spazio a cose più importanti come il menu di birra stagionale al bar in fondo all'isolato.

Anyhoo:

output$selectUI <- 
     renderUI(
      list(sliderInput(inputId = "target", label = "Date", 
              min = 0, max = diff_months(targetEnd(),targetStart()) - 1, 
              value = diff_months(targetEnd(),targetStart()) - 1, 
              animate = animationOptions(loop = T)), 
        singleton(HTML(
       ' 
      <script type="text/javascript"> 
      $(document).ready(function() { 
      var monthNames = [ "Jan.", "Feb.", "Mar.", "Apr.", "May", "June", 
      "July", "Aug.", "Sept.", "Oct.", "Nov.", "Dec." ]; 
      var endDate = new Date(', 
       year(Sys.Date()),',', month(Sys.Date()) 
       ,', 1); 
      var slider = $("#dates").slider(); 
      var labels = slider.domNode.find(".jslider-label span"); 
      labels.eq(0).text("Jan., 1962"); 
      labels.eq(1).text([monthNames[endDate.getUTCMonth() +1], endDate.getUTCFullYear()].join(", ")); 
      // override the default "nice" function. 
      slider.nice = function(value) { 
alert("hi") 
       var ref_date = new Date(1962, 1, 1); 
       var slider_date = new Date(ref_date.setMonth(ref_date.getMonth() + value)); 
       return [monthNames[slider_date.getUTCMonth()], slider_date.getUTCFullYear()].join(", "); 
      } 

      $(slider).trigger("slidechange"); 
      }) 

    $(document).ready(function() { 
       var monthNames = [ "Jan.", "Feb.", "Mar.", "Apr.", "May", "June", 
        "July", "Aug.", "Sept.", "Oct.", "Nov.", "Dec." ]; 
     var slider = $("#target").slider(); 
      var labels = slider.domNode.find(".jslider-label span"); 
      labels.eq(0).text([monthNames[', month(targetStart()) +1, '],', year(targetStart()), '].join(", ")); 
      labels.eq(1).text([monthNames[', month(targetEnd()) + 1, '], ', year(targetEnd()), '].join(", ")); 


     // override the default "nice" function. 
     slider.nice = function(value) { 
alert("hi") 
     var ref_date = new Date(', year(targetStart()), ', ', month(targetStart()),',1); 
     // each slider step is 4 weeks, translating to 24 * 3600 * 1000 milliseconds 
     var slider_date = new Date(ref_date.setMonth(ref_date.getMonth() + value - 1)); 

     return [monthNames[slider_date.getUTCMonth()], 
       slider_date.getUTCFullYear()].join(", "); 
     } 

      $(slider).trigger("slidechange"); 
    }) 
    </script> 
      ') 
      ) 
     ) 
) 
+0

Beh, direi che per essere una risposta alla domanda, ha davvero bisogno di affrontare l'aspetto logaritmico! – alexwhan

+0

Non credo. Definire la mappatura è banale (se conosci javascript).La parte difficile è capire come essere brillanti per farlo. Il codice di cui sopra ha impiegato circa 4 giorni per funzionare, di cui sono stati spesi 10 minuti sul codice per creare il formato della data. Se quello. – Bob

+0

Ottimo! Quindi apportare queste modifiche in modo che risponda alla domanda dovrebbe essere facile ...! – alexwhan

-1

Non ho lucido al momento con me, ho ampliato la gamma un po ', che cosa accadrà se si cerca qualcosa di simile:

sliderInput("pvalue", 
      "PValue:", 
      min = 1e-02, 
      max = 1e+02, 
      value = -10^seq(-2, 2) 
), 

tuo post è menzionato 1e -2, ho usato 1e-02, ho controllato come qui di seguito

> 1e-2==1e-02 
[1] TRUE 
+0

Questo doesn lavorare Il parametro value accetta solo uno o due valori (vedi http://shiny.rstudio.com/reference/shiny/latest/sliderInput.html). L'unico modo per farlo è mostrare il 'log (pValue)' sulla bilancia o le soluzioni JavaScript piuttosto pulite che altri hanno pubblicato. –

10

Non sono sicuro questa discussione è ancora attivo, ma solo nel caso in cui volessi aggiungere un modo più generico di "logifying" un inputSlider utilizzando la funzione attrib Prettify ute di ionRangeSlider invece di sovrascrivere i valori con il vantaggio che è possibile definire il minimo, il massimo, il passo e il valore predefinito di inputSlider come al solito e quindi tutto ciò che accade sul lato Javascript è un cambiamento dei valori visualizzati (due opzioni presentato, uno per l'uscita numerica, uno per la notazione scientifica):

library(shiny) 

# logifySlider javascript function 
JS.logify <- 
" 
// function to logify a sliderInput 
function logifySlider (sliderId, sci = false) { 
    if (sci) { 
    // scientific style 
    $('#'+sliderId).data('ionRangeSlider').update({ 
     'prettify': function (num) { return ('10<sup>'+num+'</sup>'); } 
    }) 
    } else { 
    // regular number style 
    $('#'+sliderId).data('ionRangeSlider').update({ 
     'prettify': function (num) { return (Math.pow(10, num)); } 
    }) 
    } 
}" 

# call logifySlider for each relevant sliderInput 
JS.onload <- 
" 
// execute upon document loading 
$(document).ready(function() { 
    // wait a few ms to allow other scripts to execute 
    setTimeout(function() { 
    // include call for each slider 
    logifySlider('log_slider', sci = false) 
    logifySlider('log_slider2', sci = true) 
    }, 5)}) 
" 

ui <- fluidPage(
    tags$head(tags$script(HTML(JS.logify))), 
    tags$head(tags$script(HTML(JS.onload))), 

    sliderInput("log_slider", "Log Slider (numbers):", 
       min = -5, max = 3, value = -4, step = 1), 

    sliderInput("log_slider2", "Log Slider (sci. notation):", 
       min = -5, max = 3, value = 1, step = 0.5), 

    br(), 

    textOutput("readout1"), 
    textOutput("readout2") 
) 

server <- function(input, output, session) { 
    output$readout1 <- reactive({ 
    paste0("Selected value (numbers): ", input$log_slider, " = ", 10^input$log_slider) 
    }) 

    output$readout2 <- reactive({ 
    paste0("Selected value (sci. notation): ", input$log_slider2, " = ", 10^input$log_slider2) 
    }) 
} 

shinyApp(ui, server) 

output

+0

Questo non funziona con il browser RStudio, ma con chrome e FF –

+0

Funziona bene ma non quando lo sliderInput viene creato sul lato server in un renderUI. Il problema è che lo script si attiva prima che venga creato l'oggetto (se si imposta il tempo di attesa abbastanza a lungo funziona). Qualche buona soluzione? –

+3

Ho trovato un modo. l'inserimento della chiamata in JS.onload nell'interfaccia utente di rendering fa il trucco. 'session $ sendCustomMessage (type = 'jsCode', list (value = JS.onload))'. Hai bisogno anche di questo in ui: 'tags $ head (tag $ script (HTML ('Shiny.addCustomMessageHandler (" jsCode ", funzione (messaggio) {eval (message.value);});')))' –

Problemi correlati