I have multiple selectizeInput in my Shiny app. Most of them are not supposed to be full of variables/elements, but one of them yes. The problem is the more variables/elements in the box, the larger is this one and the display is not good at all. I have found solutions to manipulate the height, font, width, etc. of a input widget:
library(shiny)
ui <- fluidPage(
fluidRow(
selectInput("speed", label=NULL, choices = list("1" = 1, "2" = 2), selected = 1),
tags$head(tags$style(HTML(".selectize-input {height: 100px; width: 500px; font-size: 100px;}")))
)
)
server <- function(input, output){}
shinyApp(ui, server)
This works. But this solution affects to all the selectizeInput I have in my app, I'm interested in just target one selectizeInput. Is there a way to do that?
You can use some advanced CSS to select the .selectize-input box. So in selectInput structure, the element with the actual id is assigned to a select tag and the box you want is the first child of the following tag after the select tag. We can use + to select the following tag and use > to select the first child containing the .selectize-input class of the following tag.
library(shiny)
ui <- fluidPage(
tags$head(tags$style(HTML("#speed + div > .selectize-input {height: 100px; width: 500px; font-size: 100px;}"))),
fluidRow(
selectInput("speed", label=NULL, choices = list("1" = 1, "2" = 2), selected = 1),
selectInput("speed2", label=NULL, choices = list("1" = 1, "2" = 2), selected = 1)
)
)
server <- function(input, output){}
shinyApp(ui, server)
#ID + div > .selectize-input is what you want to apply.
Try to run my example, I created two selectInput and only the first one will have the CSS style.
Related
I am building a Shiny App where users have to complete several mandatory questions in the form of radioButtons, numericInputs, and textInputs in order to generate an output. To highlight which questions still need to be completed, I would like the label text to initially be rendered as "red", but then switch to "black" once a value has been selected and/or inputted into the widgets.
library(shiny)
ui <- fluidPage(
sidebarPanel(
radioButtons("my_radio_button", tags$p("Choose an Option", style = "color:red;"), choices = c("Option 1", "Option 2"), selected = character(0)),
)
)
server <- function(input, output, session) {
observeEvent(input$val, {
x <- input$my_radio_button
if (x == "Option 1" | x == "Option 2") {
## MAKE "Choose an Option" LABEL TURN BLACK
}
})
}
shinyApp(ui, server)
I found this example on stack exchange (R shiny conditionally change numericInput background colour) where they conditionally changed the background colour of the widget, but I don't know enough about programming to modify it to change the label text instead.
Any help would be greatly appreciated. Thanks!
You can use shinyjs
add shinyjs::useShinyjs() to the beginning of ui
add an id to the label param of the radioButtons ui element. I've used r_label in the example below
Observe for changes to input$my_radio_button, which trigger calls to shinyjs::html()
Full code below:
library(shiny)
library(shinyjs)
ui <- fluidPage(
shinyjs::useShinyjs(),
sidebarPanel(
radioButtons("my_radio_button",
label=tags$p("Choose an Option", style = "color:red;", id="r_label"),
choices = c("Option 1", "Option 2"), selected = character(0)),
)
)
server <- function(input, output, session) {
observeEvent(input$my_radio_button, {
shinyjs::html("r_label", "<p style='color:black'>Choose an Option</p>")
})
}
shinyApp(ui, server)
I have been developing an application in Julia using Genie Framework and Stipple, and the main task of this app is to implement Sobel and Prewitt operator. The problem that I am struggling with is the uploader component. So basically I am able to upload an image, on button click the image is transformed, but then when i upload another image and try to output the transformed version of it, the output that i get is still the old image. I have been trying to find the issue and I noticed that QUploader API has some methods that could help solve this problem: reset() method, or removeUploadedFiles() method, but I do not know how to call/use these functions regarding Julia syntax. Are there any solutions available?
const FILE_PATH = "public/sample.jpg"
const FINAL_PATH = "final.jpg"
#const IMGPATH = "demo.png"
model = Model |> init
on(model.process_s3) do _
model.imageurl[] = ""
#info "Working"
img = FileIO.load(FILE_PATH)
img_gray = Gray.(img)
#info img_gray
sobel_image = convert(Array{Float64}, img_gray)
lastImage = clamp01nan.(sobel(sobel_image, sobel3_kernel_x, sobel3_kernel_y))
save(joinpath(#__DIR__, "public", FINAL_PATH), lastImage)
model.imageurl[] = "/$FINAL_PATH#$(Base.time())" * string(rand())
#info model.imageurl[]
if (model.process_s3[])
model.process_s3[] = false
end
end
function ui(model)
[
page( model,
class = "container",
title = "Card Demo",
partial = true,
[
row( # row takes a tuple of cells. Creates a `div` HTML element with a CSS class named `row`.
cell([h1("Edge Detection Project")]),
)
row(
[
cell(class="st-module", [
h2("Initial Image"),
card(
class = "q-pa-md row items-start q-gutter-md",
uploader(
label = "Upload Image",
method = "POST",
:multiple,
url = "http://localhost:8000/upload",
field__name = "img",
:finish="finished",
ref="uploader"
),
),
btn("Sobel 3x3",color="primary", #click("process_s3 = true")),
])
cell(class="st-module", [
h2("Transformed Image"),
card(
class = "q-pa-md row items-start q-gutter-md",
#quasar(:img, src=:imageurl, spinner__color="white", style="height: 300px; max-width: 350px")
imageview(src=:imageurl, spinner__color="white", style="height: 250px; max-width: 250px")
),
])
],
)
],
),
]
end
route("/") do
html(ui(model), context = #__MODULE__)
end
route("/upload", method = POST) do
if infilespayload(:img)
#info Requests.filename(filespayload(:img))
open(FILE_PATH, "w") do io
write(FILE_PATH, filespayload(:img).data)
#info File
end
else
#info "No image uploaded"
end
Genie.Renderer.redirect(:get)
end
# isrunning(:webserver) || up()
Replace:
"/$FINAL_PATH#$(Base.time())"
with
"/$(FINAL_PATH)?t=$(Base.time())"
Explanation:
# makes just an anchor link to an HTML document. This will obviously result in buffering the document as the browser might just look for different anchors (and not find them) yet has no motivation to re-download.
On the other hand adding the ? makes the request actually different every time (understood by browser as a different document). In result the cache will not be used - a new copy gets requested.
i want to display some geo locations on map, but i want the map-pin icon to display numbers instead of the default map pin.
Is there any way to do that?
I checked in font awesome icons but it didn't work.
Below is my code:
import folium
m = folium.Map(
location=[45.3288, -121.6625],
zoom_start=12,
#tiles='Mapbox Bright'
)
folium.Marker([45.3288, -121.6625], popup='<i>Mt. Hood Meadows</i>').add_to(m)
folium.Marker([45.3311, -121.7113], popup='<b>Timberline Lodge</b>',icon=folium.Icon(color='red')).add_to(m)
m
What i want is instead of this default map marker i want to include numbers in my marker instead of info-sign
Something like this:
i couldn't find the answer anywhere. Any leads on this?
display number 1 to 9 inside map marker pin
I was attempting something similar on a recent project and this is what I came up with. Might work for you.
It plots a DivCon marker with html and then a transparent circle marker in the same location.
import folium
from folium.features import DivIcon
m = folium.Map(
location=[45.3288, -121.6625],
zoom_start=12,
#tiles='Mapbox Bright'
)
p1 = [45.3288, -121.6625]
folium.Marker(p1, icon=DivIcon(
icon_size=(150,36),
icon_anchor=(7,20),
html='<div style="font-size: 18pt; color : black">1</div>',
)).add_to(m)
m.add_child(folium.CircleMarker(p1, radius=15))
p2 = [45.3311, -121.7113]
folium.Marker(p2, icon=DivIcon(
icon_size=(150,36),
icon_anchor=(7,20),
html='<div style="font-size: 18pt; color : black">2</div>',
)).add_to(m)
m.add_child(folium.CircleMarker(p2, radius=15))
Adapting the previous answer by #bob I found a solution that fit my needs. I put it below in case it is useful for anyone:
import folium
from folium.features import DivIcon
def number_DivIcon(color,number):
""" Create a 'numbered' icon
"""
icon = DivIcon(
icon_size=(150,36),
icon_anchor=(14,40),
# html='<div style="font-size: 18pt; align:center, color : black">' + '{:02d}'.format(num+1) + '</div>',
html="""<span class="fa-stack " style="font-size: 12pt" >>
<!-- The icon that will wrap the number -->
<span class="fa fa-circle-o fa-stack-2x" style="color : {:s}"></span>
<!-- a strong element with the custom content, in this case a number -->
<strong class="fa-stack-1x">
{:02d}
</strong>
</span>""".format(color,number)
)
return icon
col_hex = ['#440154',
'#481a6c',
'#472f7d',
'#414487',
'#39568c',
'#31688e',
'#2a788e',
'#23888e',
'#1f988b',
'#22a884',
'#35b779',
'#54c568',
'#7ad151',
'#a5db36',
'#d2e21b']
num = 0
loc = (43.613, 3.888)
fm = folium.Map(location=loc, tiles="Stamen Terrain")
folium.Marker(
location=loc,
popup="Delivery " + '{:02d}'.format(num+1),
icon=folium.Icon(color='white',icon_color='white'),
markerColor=col_hex[num],
).add_to(fm)
folium.Marker(
location=loc,
popup="Delivery " + '{:02d}'.format(num+1),
icon= number_DivIcon(col_hex[num],num+1)
).add_to(fm)
fm
I need these numbers (1,2) to be dynamic, meaning, I have a for loop, I want index value to be printed in the HTML line
for point in range(0, len(coordinates_st)):
# showing number
folium.Marker(location=[72.89, -124.59+2], icon=DivIcon(
icon_size=(150, 36),
icon_anchor=(7, 20),
html='<div style="font-size: 18pt; color : black">r{point}</div>',
)).add_to(map_st)
I've been trying to find a solution how to add and remove input fields with a button in shiny. I don't have a source code since I haven't made that much progress, but this jQuery example (http://www.mkyong.com/jquery/how-to-add-remove-textbox-dynamically-with-jquery/) gives a good idea on what I'm trying to accomplish. Is this possible in shiny or should I use shinyjs to do this? Thank you in advance!
EDIT: I read the jQuery example a bit more, and added a code snippet doing what I think you were looking for.
I don't know jQuery, so I couldn't make much out of the example link. I took a guess on what you wanted, but I think the key idea is the use of renderUI and uiOutput even if my suggestion here misses the point.
To toggle a ui element:
If you specifically don't want to use shinyjs, you could do something like this:
library(shiny)
ui <- shinyUI(fluidPage(
actionButton("btn", "Toggle Textbox"),
textOutput("btn_val"),
uiOutput("textbox_ui")
))
server <- shinyServer(function(input, output, session) {
output$btn_val <- renderPrint(print(input$btn))
textboxToggle <- reactive({
if (input$btn %% 2 == 1) {
textInput("textin", "Write something:", value = "Hello World!")
}
})
output$textbox_ui <- renderUI({ textboxToggle() })
})
shinyApp(ui, server)
To add and remove elements:
After reading a bit of the jQuery example, I think this is similar to what you were looking for:
library(shiny)
ui <- shinyUI(fluidPage(
sidebarPanel(
actionButton("add_btn", "Add Textbox"),
actionButton("rm_btn", "Remove Textbox"),
textOutput("counter")
),
mainPanel(uiOutput("textbox_ui"))
))
server <- shinyServer(function(input, output, session) {
# Track the number of input boxes to render
counter <- reactiveValues(n = 0)
observeEvent(input$add_btn, {counter$n <- counter$n + 1})
observeEvent(input$rm_btn, {
if (counter$n > 0) counter$n <- counter$n - 1
})
output$counter <- renderPrint(print(counter$n))
textboxes <- reactive({
n <- counter$n
if (n > 0) {
lapply(seq_len(n), function(i) {
textInput(inputId = paste0("textin", i),
label = paste0("Textbox", i), value = "Hello World!")
})
}
})
output$textbox_ui <- renderUI({ textboxes() })
})
shinyApp(ui, server)
The problem with this approach is that each time you press the add or remove button, all of the input boxes get re-rendered. This means that any input you might have had on them disappears.
I think you could get around that by also saving the current input values of the input boxes into a reactiveValues object, and setting the values from the object as the starting values of the re-rendered input boxes by using the value option in textInput. I'll leave the implementation of that for now, though.
Thank you #Mikko Marttila for your answer. I was able to use it for my purpose. Also, referring to the issue of all input boxes getting re-rendered here I found a solution worked from this answer. You can save all user inputs using reactiveValuesToList(), then call the reactive list accordingly to set every value to the corresponding user's input in the lapply() statement.
library(shiny)
ui <- shinyUI(fluidPage(
sidebarPanel(
actionButton("add_btn", "Add Textbox"),
actionButton("rm_btn", "Remove Textbox"),
textOutput("counter")
),
mainPanel(uiOutput("textbox_ui"))
))
server <- shinyServer(function(input, output, session) {
# Track the number of input boxes to render
counter <- reactiveValues(n = 0)
# Track all user inputs
AllInputs <- reactive({
x <- reactiveValuesToList(input)
})
observeEvent(input$add_btn, {counter$n <- counter$n + 1})
observeEvent(input$rm_btn, {
if (counter$n > 0) counter$n <- counter$n - 1
})
output$counter <- renderPrint(print(counter$n))
textboxes <- reactive({
n <- counter$n
if (n > 0) {
isolate({
lapply(seq_len(n), function(i) {
textInput(inputId = paste0("textin", i),
label = paste0("Textbox", i),
value = AllInputs()[[paste0("textin", i)]])
})
})
}
})
output$textbox_ui <- renderUI({ textboxes() })
})
shinyApp(ui, server)
EDIT: I wrapped the lapply() statement in isolate() because it gets annoying when boxes are being re-rendered as you're trying to type in the field
Instead of re-rendering the entire list of inputs, try the following
I keep track of all the ids that are created, I remove the last one created, and I reuse the ids of the deleted ones.
I start with an initial box (there is no real need for that, but I guess in a real work scenario you would expect at least 1 textBox to appear and increase thereafter). It is straightforward to start without the initial box.
Also, I keep track of the values of the textInput boxes that are currently active, in a reactive List. You would definitely need this
Lastly, I think for the two reactiveValues I have [inserted and counter], one of them is possibly redundant, but hey...
Hope it helps!
library(shiny)
ui <- fluidPage(
actionButton("insertBtn", "Insert"),
actionButton("deleteBtn", "Delete"),
h4("My boxes"),
# Initial box here to start with. Not needed but it is nice to have one :)
div(id = "box-1", textInput(inputId = "box-1", label = "box-1")),
div(id = "placeholder"),
h4('Box contents'),
verbatimTextOutput("my_inputs")
)
server <- function(input, output, session) {
## keep track of elements inserted and a counter of the elements
rv <- reactiveValues(
inserted = c("box-1"),
counter = 1
)
observeEvent(input$insertBtn, {
rv$counter <- rv$counter+1
serial <- rv$counter
id <- paste0('box-', serial)
rv$inserted <- c(rv$inserted, id)
insertUI(
selector = '#placeholder',
## wrap element in a div with id for ease of removal
ui = div(id = id,
textInput(inputId = id, label = paste0("box-", serial))
)
)
})
observeEvent(input$deleteBtn, {
req(rv$counter>0)
# removes the last one
id_to_remove <- rv$inserted[length(rv$inserted)]
removeUI(
## pass it in as JQuery selector
selector = paste0('#', id_to_remove)
)
rv$inserted <- rv$inserted[-length(rv$inserted)]
rv$counter <- rv$counter - 1
})
my_inputs <- reactive({
req(rv$inserted) # need to have some inputs
l <- reactiveValuesToList(input)
# regex of the union of all inputs. Note the starting input box-1
ids_regex <- paste(c("box-1", rv$inserted), collapse = "|")
l[grepl(ids_regex, names(l))]
})
output$my_inputs <- renderPrint({
my_inputs()
})
}
shinyApp(ui, server)
Many thanks to
this post
and this
and these SO posts one, two
I am building a webstore, where the quantity of displayed products is dinamically changing, by pressing "Show more" button. Background color should be changing multiple times while scrolling down and I found this article, which solves this problem, but it has fixed page height. Is it possible to change that?
You use a parameter to control the adaption rate and set this according to your needs if you don't know the page size on forehand (because a dynamic load for instance).
cStart = [250, 195, 56] // Gold
, cEnd = [179, 217, 112] // Lime
, cDiff = [cEnd[0] - cStart[0], cEnd[1] - cStart[1], cEnd[1] - cStart[0]];
$(document).ready(function(){
$(document).scroll(function() {
var speed = 0.0005;
var p = $(this).scrollTop()* speed;
p = Math.min(1, Math.max(0, p)); // Clamp to [0, 1]
var cBg = [Math.round(cStart[0] + cDiff[0] * p), Math.round(cStart[1] + cDiff[1] * p), Math.round(cStart[2] + cDiff[2] * p)];
$("body").css('background-color', 'rgb(' + cBg.join(',') +')');
});
});