Después de varios días de prueba, publico el código de la aplicación shiny para extraer datos de un archivo netcdf y generar unas gráficas para un punto dado.
Una aplicación shiny es una manera muy sencilla de crear una aplicación que muestre datos y se pueda interaccionar con ellos.
Toda aplicación shiny tiene dos archivos R obligatorios:
server.R: donde está el código para el análisis.
ui.R: donde está el diseño de la aplicación.
server.R
library ( shiny )
library ( scales )
library ( ggmap )
library ( ggplot2 )
library ( gridExtra )
library ( raster )
library ( ncdf )
library ( rgdal )
library ( markdown )
archivo <- "datos/datosnetcdf.nc"
idx <- seq ( as . POSIXct ( '2014-03-10 01:00:00' , tz = "UTC" ), as . POSIXct ( '2014-03-14 00:00:00' , tz = "UTC" ), 'hour' )
idx <- as . POSIXct ( idx )
##
t <- stack ( archivo , varname = "temp" )
t <- t - 273 # pasar a grados C
proj4string ( t ) <- CRS ( "+proj=lcc +lon_0=-14.1 +lat_0=34.823 +lat_1=43 +lat_2=43 +x_0=536402.3 +y_0=-18558.61 +units=km +ellps=WGS84" )
s <- stack ( archivo , varname = "snowlevel" )
proj4string ( s ) <- CRS ( "+proj=lcc +lon_0=-14.1 +lat_0=34.823 +lat_1=43 +lat_2=43 +x_0=536402.3 +y_0=-18558.61 +units=km +ellps=WGS84" )
p <- stack ( archivo , varname = "prec" )
proj4string ( p ) <- CRS ( "+proj=lcc +lon_0=-14.1 +lat_0=34.823 +lat_1=43 +lat_2=43 +x_0=536402.3 +y_0=-18558.61 +units=km +ellps=WGS84" )
snow <- stack ( archivo , varname = "snow_prec" )
proj4string ( snow ) <- CRS ( "+proj=lcc +lon_0=-14.1 +lat_0=34.823 +lat_1=43 +lat_2=43 +x_0=536402.3 +y_0=-18558.61 +units=km +ellps=WGS84" )
#Panticosa -0.285628,42.7244749
#Formigal -0.37, 42.775
#Zapardiel -5.3292159, 40.3588136
#La morcuera (-3.830237, 40.828359)
#Madrid (,-3.6817174,40.4352117)
shinyServer ( function ( input , output ) {
punto <- reactive ({
cbind ( input $lat , input $lon )
})
puntoTRANS <- reactive ({
ptoWGS <- SpatialPoints ( punto (), CRS ( "+proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0" ))
projLCC <- projection ( t )
spTransform ( ptoWGS , CRS ( projLCC ))
})
plotFunc = function () {
puntoLCC <- puntoTRANS ()
vals <- extract ( t , puntoLCC , ncol = 2 )
datos <- data . frame ( t ( vals ))
vsl <- extract ( s , puntoLCC , ncol = 2 )
datos $snow_level <- t ( vsl )
vpreci <- extract ( p , puntoLCC , ncol = 2 )
datos $lluvia <- t ( vpreci )
spreci <- extract ( snow , puntoLCC , ncol = 2 )
datos $nieve <- t ( spreci )
datos $time <- idx
t_plot <- ggplot ( datos , aes ( x = time , y = t . vals . )) + geom_line ( colour = "red" , size = 1 ) + ylab ( "Temperatura ºC" ) + xlab ( "Fecha" ) + ggtitle ( "Temperatura" ) + scale_x_datetime ( breaks = date_breaks ( "4 hours" ), labels = date_format ( "%d-%m %H h" )) + theme ( axis . text . x = element_text ( angle = 90 ))
s_plot <- ggplot ( datos , aes ( x = time , y = nieve )) + geom_bar ( stat = "identity" , fill = "orange" , colour = "orange" ) + ylab ( "mm/h" ) + xlab ( "Fecha" ) + ggtitle ( "Nieve" ) + scale_x_datetime ( breaks = date_breaks ( "4 hours" ), labels = date_format ( "%d-%m %H h" )) + theme ( axis . text . x = element_text ( angle = 90 ))
sl_plot <- ggplot ( datos , aes ( x = time , y = snow_level )) + geom_line ( colour = "green" , size = 1 ) + ylab ( "Altura (m)" ) + xlab ( "Fecha" ) + ggtitle ( "Snow level" ) + scale_x_datetime ( breaks = date_breaks ( "4 hours" ), labels = date_format ( "%d-%m %H h" )) + theme ( axis . text . x = element_text ( angle = 90 ))
p_plot <- ggplot ( datos , aes ( x = time , y = lluvia )) + geom_bar ( stat = "identity" , fill = "blue" , colour = "blue" ) + ylab ( "mm/h" ) + xlab ( "Fecha" ) + ggtitle ( "Lluvia" ) + scale_x_datetime ( breaks = date_breaks ( "4 hours" ), labels = date_format ( "%d-%m %H h" )) + theme ( axis . text . x = element_text ( angle = 90 ))
multiplot <- grid . arrange ( t_plot , sl_plot , s_plot , p_plot , ncol = 2 , main = paste ( 'Coordenadas ' , input $lat , ', ' , input $lon ))
print ( multiplot )
}
output $plot <- renderPlot ( plotFunc (), height = 500 )
# Summary()
output $summary <- renderPrint ({
puntoLCC <- puntoTRANS ()
vals <- extract ( t , puntoLCC , ncol = 2 )
datos <- data . frame ( t ( vals ))
vsl <- extract ( s , puntoLCC , ncol = 2 )
datos $snow_level <- t ( vsl )
vpreci <- extract ( p , puntoLCC , ncol = 2 )
datos $lluvia <- t ( vpreci )
spreci <- extract ( snow , puntoLCC , ncol = 2 )
datos $nieve <- t ( spreci )
datos $time <- idx
summary ( datos )
})
#
output $table <- renderTable ({
puntoLCC <- puntoTRANS ()
vals <- extract ( t , puntoLCC , ncol = 2 )
datos <- data . frame ( t ( vals ))
vsl <- extract ( s , puntoLCC , ncol = 2 )
datos $snow_level <- t ( vsl )
vpreci <- extract ( p , puntoLCC , ncol = 2 )
datos $lluvia <- t ( vpreci )
spreci <- extract ( snow , puntoLCC , ncol = 2 )
datos $nieve <- t ( spreci )
datos $time <- idx
datos
})
output $map <- renderPlot ({
map . base <- get_googlemap (
center = punto (),
maptype = 'hybrid' , ## Map type as defined above (roadmap, terrain, satellite, hybrid)
markers = data . frame ( punto ()),
zoom = 10 , ## 14 is just about right for a 1-mile radius
scale = 1 , ## Set it to 2 for high resolution output
)
#map.base = get_map(location = c(input$lat,input$lon),zoom=14, source = "osm")
print ( ggmap ( map . base ))
}, width = 600 , height = 600 )
})
ui.R
library ( shiny )
library ( scales )
library ( ggmap )
library ( ggplot2 )
library ( gridExtra )
library ( raster )
library ( ncdf )
library ( rgdal )
library ( markdown )
# Define UI for dataset viewer application
shinyUI ( pageWithSidebar (
# Application title
headerPanel ( "Climatic hourly data" ),
sidebarPanel (
wellPanel (
helpText ( HTML ( "<b>Extract data</b>" )),
HTML ( "Insert the coordinates. Press update button to refresh the data." ),
submitButton ( "Update" )
),
wellPanel (
helpText ( HTML ( "<b>Insert Lat - Lon</b>" )),
numericInput ( "lat" , "Latitude:" , - 0 . 285628 ),
numericInput ( "lon" , "Longitude:" , 42 . 7244749 )
)
),
mainPanel (
tabsetPanel (
tabPanel ( "Plot" , plotOutput ( "plot" )),
tabPanel ( "Map" , plotOutput ( "map" )),
tabPanel ( "Summary" , verbatimTextOutput ( "summary" )),
tabPanel ( "Data" , tableOutput ( "table" )),
tabPanel ( "About" , includeMarkdown ( "datos/intro.md" ))
)
)
))
La aplicación
Seguro que el código que presento se puede mejorar (he de seguir profundizando en las funciones reactivas y por supuesto en R).
El código y los datos se puede descargar de mi
repositorio de Github . Se puede probar la aplicación shiny alojada en shinyapps en Aplicación meteo .