I would like to be able to zoom in on the vlines in a density plot in shiny. I am using the iris dataset for reproducible purposes. The vlines are labeled with row names.
In my actual dataset, I have many vlines very close to each other. They are so close that I often cannot distinguish the row number labels. I would like to find a way to zoom in on the vline labels. I have attempted using a brush but that is not working.
library(tidyverse)
library(cluster)
library(shiny)
ui <- fluidPage({
pageWithSidebar(
headerPanel('Iris k-means clustering'),
sidebarPanel(
numericInput('clusters', 'Cluster count', 3, min = 1, max = 9)
),
mainPanel(
plotOutput('plot1',
dblclick = 'plot1_dblclick',
brush = brushOpts(
id = 'plot1_brush',
resetOnNew = TRUE
))
)
)
})
server <- function(input, output){
ClusterData <- reactive({
iris[,1:4]
})
# need to keep row numbers for outlier labels
ClusterData2 <- reactive({
ClusterData2 <- data.frame(ClusterData())
row.names(ClusterData2) <- 1:nrow(ClusterData2)
return(ClusterData2)
})
# scale the iris data
ScaledData <- reactive({
scale(ClusterData2())
})
# kmeans clustering
final <- reactive({
kmeans(ScaledData(), input$clusters, nstart = 25)
})
# find centers
states.centers <- reactive({
final()$centers[final()$cluster, ]
})
# find outliers
distances <- reactive({
sqrt(rowSums((ScaledData() - states.centers())^2))
})
# bind distances back to data
outliers <- reactive({
cbind(ClusterData(), Distance = distances())
})
# bind cluster number to data
clusterMember <- reactive({
cbind(outliers(), clusterNum = final()$cluster)
})
# turn into data frame
clusterMember2 <- reactive({
as.data.frame(clusterMember())
})
# find points that are their own cluster
dist0 <- reactive({
clusterMember() %>%
filter(distances() == 0)
})
# arrange distances largest to smallest
distArrange <- reactive({
clusterMember() %>%
arrange(desc(Distance))
})
# find top 5 outliers
filtTop5 <- reactive({
distArrange()[1:5,]
})
# bind outliers and single clusters together
AllOutliers <- reactive({
rbind(filtTop5(), dist0())
})
########## output plot
output$plot1 <- renderPlot({
ClusterData() %>%
ggplot(aes(x = Petal.Length)) +
geom_density(fill = "blue", alpha = 0.4) +
geom_vline(xintercept = AllOutliers()$Petal.Length) +
annotate("text", x = AllOutliers()$Petal.Length,
y = 0,
label = rownames(AllOutliers()),
hjust = 0.5,
vjust = -1)
})
######### zoom brush
observeEvent(input$plot1_dblclick, {
brush <- input$plot1_brush
if (!is.null(brush)) {
ranges$x <- c(brush$xmin, brush$xmax)
ranges$y <- c(brush$ymin, brush$ymax)
} else {
ranges$x <- NULL
ranges$y <- NULL
}
})
}
shinyApp(ui, server)
I am not invested in the above approach. Any suggestions would be welcome.
Thank you.
I advise you to try plotly package.
Modified code from your question:
library(tidyverse)
library(cluster)
library(shiny)
library(plotly)
ui <- fluidPage({
pageWithSidebar(
headerPanel('Iris k-means clustering'),
sidebarPanel(
numericInput('clusters', 'Cluster count', 3, min = 1, max = 9)
),
mainPanel(
plotlyOutput('plot1')
)
)
})
server <- function(input, output){
ClusterData <- reactive({
iris[,1:4]
})
# need to keep row numbers for outlier labels
ClusterData2 <- reactive({
ClusterData2 <- data.frame(ClusterData())
row.names(ClusterData2) <- 1:nrow(ClusterData2)
return(ClusterData2)
})
# scale the iris data
ScaledData <- reactive({
scale(ClusterData2())
})
# kmeans clustering
final <- reactive({
kmeans(ScaledData(), input$clusters, nstart = 25)
})
# find centers
states.centers <- reactive({
final()$centers[final()$cluster, ]
})
# find outliers
distances <- reactive({
sqrt(rowSums((ScaledData() - states.centers())^2))
})
# bind distances back to data
outliers <- reactive({
cbind(ClusterData(), Distance = distances())
})
# bind cluster number to data
clusterMember <- reactive({
cbind(outliers(), clusterNum = final()$cluster)
})
# turn into data frame
clusterMember2 <- reactive({
as.data.frame(clusterMember())
})
# find points that are their own cluster
dist0 <- reactive({
clusterMember() %>%
filter(distances() == 0)
})
# arrange distances largest to smallest
distArrange <- reactive({
clusterMember() %>%
arrange(desc(Distance))
})
# find top 5 outliers
filtTop5 <- reactive({
distArrange()[1:5,]
})
# bind outliers and single clusters together
AllOutliers <- reactive({
rbind(filtTop5(), dist0())
})
########## output plot
output$plot1 <- renderPlotly({
plot1 <- ClusterData() %>%
ggplot(aes(x = Petal.Length)) +
geom_density(fill = "#6495ed", alpha = 0.3) +
geom_vline(xintercept = AllOutliers()$Petal.Length, size = 0.5, colour = "#013220") +
annotate("text", x = AllOutliers()$Petal.Length,
y = 0,
label = rownames(AllOutliers()),
colour = "#d4240b",
size = 4)
ggplotly(plot1)
})
}
shinyApp(ui, server)
Output (zoomed with cluster count = 9):
Related
I have the following App:
The objective is to:
Add new points to the plot when the user clicks on it.
These are updated in the table (where you can remove points also)
(Where the App fails): Plot the linear regression and spline regression based on the new users updated data.
When I comment-out the lines
#geom_line(aes(x=x, y=fitlm(), color="Simple")) +
#geom_line(aes(x=x, y=fitbslm(), color="B-spline")) +
in the ggplot renderPlot() function at the end, I am able to add points and update the plot without problem
The problem occurs when I try to add these two lines back into the plot and then the updated data is passed to the fitlm and fitBslm eventReactive() functions.
For some reason it doesn't want to re-compute the regressions and apply/update the plot.
Question:
How can I introduce the regressions to the ggplot based on the new users updated data. (I am happy with it updating automatically or through a button)
After clicking the Generate Plot button it makes the below plot. However, the plot failed Error: [object Object] when I click on the plot to add a new point.
App:
library(shiny)
library(dplyr)
library(splines2)
library(ggplot2)
# Get the Temp values, which defines the accepted range of knots
# for the b-spline model.
library(dplyr)
data("airquality")
airquality <- filter(airquality, !is.na(Ozone)) %>%
select(c(Ozone, Temp)) %>%
set_names(c("x", "y"))
uniqueTemps <- unique(airquality[order(airquality$x), "x"])
selectedTemps <- sample(uniqueTemps, 2)
# Define UI for application that draws a histogram
ui <- shinyUI(fluidPage(
# Application title
titlePanel("Simple Linear vs Spline Fit"),
# Sidebar
sidebarLayout(
sidebarPanel(
selectInput("knotSel", "Select knot values for B-spline fit:",
uniqueTemps, selected=selectedTemps,
multiple=TRUE),
actionButton("calcFit", "Generate Plot"),
actionButton("computeRegressions", "Compute Regressions")
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("plot_splines", click = "plot_click"),
h4("Example Data: airquality {datasets}"),
p("This plot uses linear models to predict ozone levels based on temperature readings.",
tags$br(),
tags$em("Simple formula: ")
# tags$code("lm(Ozone ~ Temp + I(Temp^2) + I(Temp^3) - 1, airquality)"),
# tags$br(),
# tags$em("Spline formula: "),
# tags$code("lm(airquality$Ozone ~ bSpline(airquality$Temp, knots=getKnots(), degree=3) - 1)")
),
fluidRow(column(width = 6,
h4("Click plot to add points"),
actionButton("rem_point", "Remove Last Point")
#plotOutput("plot1", click = "plot_click")
),
column(width = 6,
h4("Table of points on plot"),
tableOutput("table"))),
fluidRow(column(width = 6,
DTOutput('tab1')),
column(width = 6,
DTOutput('tab2'))
)
)
)))
server <- (function(input, output) {
# Load the airquality dataset.
# data("airquality")
# # Remove observations lacking an Ozone measure.
# airquality <- filter(airquality, !is.na(Ozone)) %>%
# select(c(Ozone, Temp)) %>%
# set_names(c("y", "x"))
########################### Add selections to plot ###########################
## 1. set up reactive dataframe ##
values <- reactiveValues()
values$DT <- data.frame(x = numeric(),
y = numeric()
) %>%
bind_rows(airquality)
## 2. Create a plot ##
# output$plot1 = renderPlot({
# ggplot(values$DT, aes(x = x, y = y)) +
# geom_point(size = 5) +
# lims(x = c(0, 100), y = c(0, 100)) +
# theme(legend.position = "bottom")
# # include so that colors don't change as more color/shape chosen
# # scale_color_discrete(drop = FALSE) +
# # scale_shape_discrete(drop = FALSE)
# })
## 3. add new row to reactive dataframe upon clicking plot ##
observeEvent(input$plot_click, {
# each input is a factor so levels are consistent for plotting characteristics
add_row <- data.frame(x = input$plot_click$x,
y = input$plot_click$y
)
# add row to the data.frame
values$DT <- rbind(values$DT, add_row)
})
## 4. remove row on actionButton click ##
observeEvent(input$rem_point, {
rem_row <- values$DT[-nrow(values$DT), ]
values$DT <- rem_row
})
## 5. render a table of the growing dataframe ##
output$table <- renderTable({
values$DT
})
##############################################################################
# Fit the simple linear model
fitlm <- eventReactive(input$calcFit, {
slm <- lm(y ~ x + I(x^2) + I(x^3) - 1, values$DT)
fitlm <- slm$fitted.values
fitlm
})
# Get knot selection
getKnots <- reactive({as.integer(input$knotSel)})
# Fit the spline model, with the knot selection
fitBslm <- eventReactive(input$calcFit, {
bsMat <- bSpline(values$DT$x, knots=getKnots(), degree=3)
bslm <- lm(values$DT$y ~ bsMat - 1)
bslm
})
# observeEvent({
# print(fitBslm())
# })
# Generate the plot
output$plot_splines <- renderPlot({
splineMdl <- fitBslm()
fitbslm <- splineMdl$fitted.values
cols <- c("Simple"="#ef615c", "B-spline"="#20b2aa", "knot"="black")
g <- ggplot(values$DT, aes(x=x, y=y)) +
geom_point(color="blue") +
geom_line(aes(x=x, y=fitlm(), color="Simple")) +
#geom_line(aes(x=x, y=fitbslm(), color="B-spline")) +
geom_vline(aes(color="knot"), xintercept=getKnots(), linetype="dashed", size=1) +
scale_colour_manual(name="Fit Lines",values=cols) +
ggtitle("Ozone as predicted by Temp", "(knots shown as vertical lines)")
g
})
output$tab1 <- renderDataTable(
airquality
)
output$tab2 <- renderDataTable(
values$DT
)
})
shinyApp(ui, server)
Change eventReactive to just reactive. Also, you just need fitbslm in the second geom_line without (). Try this
server <- (function(input, output) {
########################### Add selections to plot ###########################
## 1. set up reactive dataframe ##
values <- reactiveValues()
values$DT <- data.frame(x = numeric(),
y = numeric()
) %>%
bind_rows(airquality)
## 3. add new row to reactive dataframe upon clicking plot ##
observeEvent(input$plot_click, {
# each input is a factor so levels are consistent for plotting characteristics
add_row <- data.frame(x = input$plot_click$x,
y = input$plot_click$y
)
# add row to the data.frame
values$DT <- rbind(values$DT, add_row)
})
## 4. remove row on actionButton click ##
observeEvent(input$rem_point, {
rem_row <- values$DT[-nrow(values$DT), ]
values$DT <- rem_row
})
## 5. render a table of the growing dataframe ##
output$table <- renderTable({
values$DT
})
##############################################################################
# Fit the simple linear model
# fitlm <- eventReactive(input$calcFit, {
fitlm <- reactive({
slm <- lm(y ~ x + I(x^2) + I(x^3) - 1, values$DT)
fitlm <- slm$fitted.values
fitlm
})
# Get knot selection
getKnots <- reactive({as.integer(input$knotSel)})
# Fit the spline model, with the knot selection
#fitBslm <- eventReactive(input$calcFit, {
fitBslm <- reactive({
bsMat <- bSpline(values$DT$x, knots=getKnots(), degree=3)
bslm <- lm(values$DT$y ~ bsMat - 1)
bslm
})
myPlot <- reactive({
splineMdl <- fitBslm()
fitbslm <- splineMdl$fitted.values
cols <- c("Simple"="#ef615c", "B-spline"="#20b2aa", "knot"="black")
g <- ggplot(values$DT, aes(x=x, y=y)) +
geom_point(color="blue") +
geom_line(aes(x=x, y=fitlm(), color="Simple")) +
geom_line(aes(x=x, y=fitbslm , color="B-spline")) +
geom_vline(aes(color="knot"), xintercept=getKnots(), linetype="dashed", size=1) +
scale_colour_manual(name="Fit Lines",values=cols) +
ggtitle("Ozone as predicted by Temp", "(knots shown as vertical lines)")
g
})
# Generate the plot
output$plot_splines <- renderPlot({
myPlot()
})
output$tab1 <- renderDataTable(
airquality
)
output$tab2 <- renderDataTable(
values$DT
)
})
In Code1 below I am trying to create a draggable plot using the plotly package. The user should be able to drag the points of the plot and capture the new points in the data frame rendered to the left called "Data1". When running the code I get the error "Warning: Error in <-: invalid (NULL) left side of assignment". What am I doing wrong?
As an FYI, Code2 below does just this but using a different data set, though both are structured the same. In running Code2, I compare the data frame that works in Code2 (called "Data") with the data frame that does not work in Code1 ("Data1") to show how similarly the two data frames are in structure. Drag the plotted data points in Code2 and see how nicely the "Data" table to the left updates. This is what I'm trying to get at in Code1, but instead by using Data1 data.
Solution spoiler: see ismirsehregal answer below. The difference between Code1 and Code2, where Code1 fails and Code2 doesn't, is due to the inappropriate use of reactive() in defining the data1() dataframe in Code1. Since data1() is modified from different places (sliderInput(), the drag feauture in plotly), reactiveVal() or reactiveValues() must be used and not reactive() in defining the dataframe. Also note the use of reactiveValuesToList() in rendering the modified dataframe after dragging a plot point.
Code1:
library(plotly)
library(purrr)
library(shiny)
ui <- fluidPage(
fluidRow(column(5,sliderInput('periods','Nbr of periods:',min=0,max=24,value=12))),
fluidRow(column(2,h5("Data1:"),tableOutput('data1')),
column(6, plotlyOutput("p")))
)
server <- function(input, output, session) {
data1 <- reactive({
data.frame(
x = c(1:input$periods),
y = c((0.15-0.70)*(exp(-50/100*(1:input$periods))-exp(-50/100*input$periods)*
(1:input$periods)/input$periods)) + 0.70
)
})
output$p <- renderPlotly({
circles <- map2(data1()$x, data1()$y,
~list(type = "circle",
xanchor = .x,
yanchor = .y,
x0 = -4, x1 = 4,
y0 = -4, y1 = 4,
xsizemode = "pixel",
ysizemode = "pixel",
fillcolor = "blue",
line = list(color = "transparent"))
)
plot_ly() %>%
add_lines(x = data1()$x, y = data1()$y, color = I("red")) %>%
layout(shapes = circles) %>%
config(edits = list(shapePosition = TRUE))
})
output$data1 <- renderTable(data1())
# update x/y reactive values in response to changes in shape anchors
observe({
ed <- event_data("plotly_relayout")
shape_anchors <- ed[grepl("^shapes.*anchor$", names(ed))]
if (length(shape_anchors) != 2) return()
row_index <- unique(readr::parse_number(names(shape_anchors)) + 1)
pts <- as.numeric(shape_anchors)
data1()$x[row_index] <- pts[1]
data1()$y[row_index] <- pts[2]
})
}
shinyApp(ui, server)
Code2:
library(plotly)
library(purrr)
library(shiny)
ui <- fluidPage(
fluidRow(column(5,sliderInput('periods','Nbr of periods:',min=0,max=24,value=12))),
fluidRow(
column(2,h5(strong(("Data:"))),tableOutput('data')),
column(2,h5(strong(("Data1:"))),tableOutput('data1')),
column(6,h5(strong(("Move the points and see how `Data` table to left updates:"))), plotlyOutput("p")),
),
fluidRow(h5(strong(("Data1 above shown for comparison purposes, would like to substitute Data with Data1 in the plot"))))
)
server <- function(input, output, session) {
rv <- reactiveValues( x = mtcars$mpg,y = mtcars$wt)
data <- reactive(data.frame(x=(rv$x_sub),y=(rv$y_sub)))
data1 <- reactive({
data.frame(
x = c(1:input$periods),
y = c((0.15-0.70) * (exp(-50/100*(1:input$periods))-
exp(-50/100*input$periods)*(1:input$periods)/input$periods)) + 0.70
)
})
observe({
rv$x_sub <- rv$x[1:input$periods]
rv$y_sub <- rv$y[1:input$periods]
})
output$p <- renderPlotly({
circles <- map2(rv$x_sub, rv$y_sub,
~list(
type = "circle",
xanchor = .x,
yanchor = .y,
x0 = -4, x1 = 4,
y0 = -4, y1 = 4,
xsizemode = "pixel",
ysizemode = "pixel",
fillcolor = "blue",
line = list(color = "transparent")
)
)
plot_ly() %>%
add_lines(x = rv$x_sub, y = rv$y_sub, color = I("red")) %>%
layout(shapes = circles) %>%
config(edits = list(shapePosition = TRUE))
})
output$data <- renderTable(data())
output$data1 <- renderTable(data1())
# update x/y reactive values in response to changes in shape anchors
observe({
ed <- event_data("plotly_relayout")
shape_anchors <- ed[grepl("^shapes.*anchor$", names(ed))]
if (length(shape_anchors) != 2) return()
row_index <- unique(readr::parse_number(names(shape_anchors)) + 1)
pts <- as.numeric(shape_anchors)
rv$x[row_index] <- pts[1]
rv$y[row_index] <- pts[2]
})
}
shinyApp(ui, server)
Unfortunately you can't modify a reactive in multiple places. For this use case reactiveVal or reactiveValues are intended.
Please check the following:
library(plotly)
library(purrr)
library(shiny)
ui <- fluidPage(
fluidRow(column(5,sliderInput('periods','Nbr of periods:',min=0,max=24,value=12))),
fluidRow(column(2,h5("Data1:"),tableOutput('data1table')),
column(6, plotlyOutput("p")))
)
server <- function(input, output, session) {
data1 <- reactiveValues(x = NULL, y = NULL)
observe({
data1$x <- c(1:input$periods)
data1$y <- c((0.15-0.70)*(exp(-50/100*(1:input$periods))-exp(-50/100*input$periods)*
(1:input$periods)/input$periods)) + 0.70
})
output$p <- renderPlotly({
circles <- map2(data1$x, data1$y,
~list(type = "circle",
xanchor = .x,
yanchor = .y,
x0 = -4, x1 = 4,
y0 = -4, y1 = 4,
xsizemode = "pixel",
ysizemode = "pixel",
fillcolor = "blue",
line = list(color = "transparent"))
)
plot_ly() %>%
add_lines(x = data1$x, y = data1$y, color = I("red")) %>%
layout(shapes = circles) %>%
config(edits = list(shapePosition = TRUE))
})
output$data1table <- renderTable({
as.data.frame(reactiveValuesToList(data1))
})
# update x/y reactive values in response to changes in shape anchors
observe({
ed <- event_data("plotly_relayout")
shape_anchors <- ed[grepl("^shapes.*anchor$", names(ed))]
if (length(shape_anchors) != 2) return()
row_index <- unique(readr::parse_number(names(shape_anchors)) + 1)
pts <- as.numeric(shape_anchors)
data1$x[row_index] <- pts[1]
data1$y[row_index] <- pts[2]
})
}
shinyApp(ui, server)
I am trying to add vlines to a density plot in shiny for R. For reproducible purposes, I will use the iris data set. The data is clustered using kmeans from the cluster package. Outliers are located by measuring distances from the centers of clusters. Then I wish to create a density plot that has vlines and labels for each of the outliers.
The code works outside of shiny. Inside my shiny app, I get an error message: Error in [: invalid subscript type 'list'. I have tried unlist and making the outliers a variety of other forms and still get the list error. How do I add the vlines?
Global
library(tidyverse)
library(cluster)
library(shiny)
require(iris)
UI
ui <- fluidPage({
pageWithSidebar(
headerPanel('Iris k-means clustering'),
sidebarPanel(
numericInput('clusters', 'Cluster count', 3, min = 1, max = 9)
),
mainPanel(
plotOutput('plot1')
)
)
})
Server
server <- function(input, output){
ClusterData <- reactive({
iris[,1:4]
})
# need to keep row numbers for outlier labels
ClusterData2 <- reactive({
ClusterData2 <- data.frame(ClusterData())
row.names(ClusterData2) <- 1:nrow(ClusterData2)
return(ClusterData2)
})
# scale the iris data
ScaledData <- reactive({
scale(ClusterData2())
})
# kmeans clustering
final <- reactive({
kmeans(ScaledData(), 3, nstart = 25)
})
# find centers
states.centers <- reactive({
final()$centers[final()$cluster, ]
})
# find outliers
distances <- reactive({
sqrt(rowSums((ScaledData() - states.centers())^2))
})
# bind distances back to data
outliers <- reactive({
cbind(ClusterData(), Distance = distances())
})
# bind cluster number to data
clusterMember <- reactive({
cbind(outliers(), clusterNum = final()$cluster)
})
# turn into data frame
clusterMember2 <- reactive({
as.data.frame(clusterMember())
})
# find points that are their own cluster
dist0 <- reactive({
clusterMember() %>%
filter(distances() == 0)
})
# arrange distances largest to smallest
distArrange <- reactive({
clusterMember() %>%
arrange(desc(Distance))
})
# find top 5 outliers
filtTop5 <- reactive({
distArrange()[1:5,]
})
# bind outliers and single clusters together
AllOutliers <- reactive({
rbind(filtTop5(), dist0())
})
# for density plot: vlines and labels
lines_amt <- reactive({
data.frame(vlines = (clusterMember2()$Petal.Length[c(AllOutliers())]), labels = c(AllOutliers()))
})
########## output
output$plot1 <- renderPlot({
ClusterData() %>%
ggplot(aes(x = Petal.Length)) +
geom_density(fill = "blue", alpha = 0.4) #+
geom_vline(data = lines_amt(), aes(xintercept = get(vlines)))
})
}
Run App
shinyApp(ui, server)
Thank you.
The plot should look like the link.
PetalLengthDensityPlot
I think I have it all sorted out. Essentially I removed your lines_amt() reactive, and replaced geom_vline(), while also adding an annotate() for the labels:
library(tidyverse)
library(cluster)
library(shiny)
ui <- fluidPage({
pageWithSidebar(
headerPanel('Iris k-means clustering'),
sidebarPanel(
numericInput('clusters', 'Cluster count', 3, min = 1, max = 9)
),
mainPanel(
plotOutput('plot1')
)
)
})
server <- function(input, output){
ClusterData <- reactive({
iris[,1:4]
})
# need to keep row numbers for outlier labels
ClusterData2 <- reactive({
ClusterData2 <- data.frame(ClusterData())
row.names(ClusterData2) <- 1:nrow(ClusterData2)
return(ClusterData2)
})
# scale the iris data
ScaledData <- reactive({
scale(ClusterData2())
})
# kmeans clustering
final <- reactive({
kmeans(ScaledData(), 3, nstart = 25)
})
# find centers
states.centers <- reactive({
final()$centers[final()$cluster, ]
})
# find outliers
distances <- reactive({
sqrt(rowSums((ScaledData() - states.centers())^2))
})
# bind distances back to data
outliers <- reactive({
cbind(ClusterData(), Distance = distances())
})
# bind cluster number to data
clusterMember <- reactive({
cbind(outliers(), clusterNum = final()$cluster)
})
# turn into data frame
clusterMember2 <- reactive({
as.data.frame(clusterMember())
})
# find points that are their own cluster
dist0 <- reactive({
clusterMember() %>%
filter(distances() == 0)
})
# arrange distances largest to smallest
distArrange <- reactive({
clusterMember() %>%
arrange(desc(Distance))
})
# find top 5 outliers
filtTop5 <- reactive({
distArrange()[1:5,]
})
# bind outliers and single clusters together
AllOutliers <- reactive({
rbind(filtTop5(), dist0())
})
# for density plot: vlines and labels #Made the lines and labels without this
# lines_amt <- reactive({
# data.frame(vlines = (clusterMember2()$Petal.Length[c(AllOutliers()$Petal.Length)]), labels = c(AllOutliers()))
# })
########## output
output$plot1 <- renderPlot({
ClusterData() %>%
ggplot(aes(x = Petal.Length)) +
geom_density(fill = "blue", alpha = 0.4) +
# geom_vline(xintercept = lines_amt()$vlines)
geom_vline(xintercept = AllOutliers()$Petal.Length)+ #Used this in place of your current geom_vline()
annotate("text", x = AllOutliers()$Petal.Length, #Added this to add the text
y = 0,
label = rownames(AllOutliers()),
hjust = -1,
vjust = -1)
# geom_vline(data = lines_amt(), aes(xintercept = get(vlines)))
})
}
shinyApp(ui, server)
Hopefully this helps!
I have a question about the checkboxInput in R shiny. When it is checked, the scatter plot should be colorful while when it is unchecked, the plot should be black. I have tried several methods, but it keeps colorful no matter whether it is checked or not. Could you please help me with fix the code? Thanks so much.
library(shiny)
library(dplyr)
library(ggplot2)
# Start a 'Shiny' part
shinyServer(function(input, output, session) {
# Create a new reactive variable
newVar <- reactive({
newData <- msleep %>% filter(vore == input$vore)
})
# Create a scatter plot
output$sleepPlot <- renderPlot({
newDat <- newVar()
g <- ggplot(newDat, aes(x = bodywt, y = sleep_total))
g + geom_point(size = input$size, aes(col = conservation))
})
# Create text info
output$info <- renderText({
newDat <- newVar()
paste("The average body weight for order", input$vore, "is", round(mean(newDat$bodywt, na.rm = TRUE), 2),
"and the average total sleep time is", round(mean(newDat$sleep_total, na.rm = TRUE), 2), sep = " ")
})
# Create output of observations
output$table <- renderTable({
newDat <- newVar()
newDat
})
})
library(ggplot2)
shinyUI(fluidPage(
# Application title
titlePanel("Investigation of Mammal Sleep Data"),
# Sidebar with options for the data set
sidebarLayout(
sidebarPanel(
h3("Select the mammal's biological order:"),
selectizeInput("vore", "Vore", selected = "omni",
choices = levels(as.factor(msleep$vore))),
br(),
sliderInput("size", "Size of Points on Graph",
min = 1, max = 10, value = 5, step = 1),
checkboxInput("conservation", h4("Color Code Conservation Status", style = "color:red;"))
),
# Show output
mainPanel(
plotOutput("sleepPlot"),
textOutput("info"),
tableOutput("table")
)
)
))
Try this
# Create a scatter plot
output$sleepPlot <- renderPlot({
newDat <- newVar()
colorme <- unique(newVar()$conservation)
ncolor <- length(colorme)
if (!input$conservation) {
mycolor <- c(rep("black",ncolor))
mylabels <- c(rep(" ",ncolor))
}
g <- ggplot(newDat, aes(x = bodywt, y = sleep_total)) +
geom_point(size = input$size, aes(col = conservation)) +
{if (!input$conservation) scale_color_manual(name=" ", values=mycolor, labels=mylabels)} +
{ if (!input$conservation) guides(color='none')}
g
})
You can adjust, as necessary.
I've put together this Shiny app from tutorial and examples, and I've become stuck. My aim is to make the plot reactive, so that the data points in 'uval$df' are plotted, meaning that selected points will be removed from the graph, and it can't be selected twice. How do I do this? (I've got a feeling it's something lacking in my basic understanding)
Thanks!
library(shiny)
library(plotly)
library(dplyr)
ui <- fluidPage(
fluidRow(
column(12,plotlyOutput("plot"),
verbatimTextOutput("txtout1"),
verbatimTextOutput("txtout2"),
verbatimTextOutput("txtout3"))
)
)
server <- function(input, output, session) {
x<-c(1,2,34,2,1,23,24)
y<-c(10,20,30,40,50,60,70)
df<-data.frame(x,y)
vector.is.empty <- function(x) return(length(x) ==0 )
K <-reactive({
event_data("plotly_selected",source = "B")
})
M<-reactive({
K()[,c("x","y")]
})
values <- reactiveValues()
values$df <- data.frame(x = numeric(0), y = numeric(0))
newEntry <- observeEvent(K(),priority = 1,{
new0 <- isolate(M())
isolate(values$df <- rbind(values$df, new0))
})
uval <- reactiveValues()
uval$df <- df
newEntry1 <- observeEvent({values$df},priority = 2,{
new1 <- isolate(data.frame(values$df))
isolate(uval$df <- setdiff(df,new1))
})
output$plot <- renderPlotly({
plot_ly(x = df$x, y = df$y, mode = "markers",source="B") %>%
layout(dragmode = "select", title = "Original Plot", font=list(size=10))
})
output$txtout1 <- renderPrint({
if(vector.is.empty(K())) "Click and drag across points" else M()
})
output$txtout2 <- renderPrint({
uval$df
})
output$txtout3 <- renderPrint({
values$df
})
}
shinyApp(ui, server, options = list(display.mode = "showcase"))
Simple, as I thought.
plot_ly(uval$df, x = x, y = y, mode = "markers",source="B")