Let two renderui numeric inputs react on eachother in shiny - filter

I'm trying to create two renderUI filters that have a value dependent on each other. I have two filters: percentage and value.
Percentage should be: value/total_amount and value should be total_amount*percentage. I need this because sometimes the user wants to fill in a number it wants and sometimes it wants a percentage of the total. And I always want to show both.
For example, if the user fills in .20 in the percentage filter, I want to show 20 in the value filter. And if the user fills in 80 in the value filter, I want to show .8 in the percentage filter.
So I'm hoping these two can be combined.. I'm trying this code but it's obviously not working.
server <- function(input, output) {
total_amount<-100
output$percentage<-renderUI({
myvalue<- input$value/total_amount
if(is.null(myvalue))myvalue<-.2
# myvalue<-.2
#browser()
numericInput('percentage','percentage',value = myvalue)
})
output$value<-renderUI({
myvalue<- input$percentage*total_amount
if(is.null(myvalue))myvalue<-100
# myvalue<-100
numericInput('value','value',value = myvalue)
})
}
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
uiOutput('percentage'),
uiOutput('value')
)
# ,mainPanel(plotOutput("distPlot"))
)
)
shinyApp(ui = ui, server = server)

Just add the default value for the percentage and make sure that widget has a value.
library(shiny)
server <- function(input, output) {
total_amount <- 100
percentage <- 0.2
output$percentage <- renderUI({
if(is.null(input$value)) {
myvalue <- percentage
} else {
myvalue <- input$value/total_amount
}
numericInput('percentage', 'percentage', value = myvalue)
})
output$value <- renderUI({
if(is.null(input$percentage)) {
myvalue <- percentage*total_amount
} else {
myvalue <- input$percentage*total_amount
}
numericInput('value', 'value', value = myvalue)
})
}
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
uiOutput('percentage'),
uiOutput('value')
)
,mainPanel()
)
)
shinyApp(ui = ui, server = server)

Related

rshiny module not printing input to output

Simple reprex here, but I am trying to print the input as a small test to see if my app is working:
test_ui <- function(id) {
fluidPage(
selectInput("sel_id", "label", 1:10),
textOutput(NS(id, "sel_text"))
)
}
test_server <- function(id) {
moduleServer(
id,
function(input, output, session) {
output$sel_text <- renderText({input$sel_id})
}
)
}
demo <- function() {
ui <- fluidPage(
test_ui("x")
)
server <- function(input, output, session) {
test_server("x")
}
shinyApp(ui, server)
}
demo()
I was expecting the text to print below the input box but all I got was the select box:
I tried substituting the output line with:
output$sel_text <- renderText({"test_text"})
and it printed:
So it must be something to do with the input values. Weirdly enough in my main (more complex) app, writing the code directly into the ui/server files works, so I must be tripping up on some aspect of modules I don't understand. Would greatly appreciate if someone could point out what I am missing.
Silly me! All I forgot was the following call to NS():
selectInput(NS(id, "sel_id"), "label", 1:10)

Golang, running for range loop on channel, how to continue execution of block having received next value from channel?

I'm studying Golang and now I'm stuck with a such situation.
Let's say I have a channel on ints:
ints = make(chan int)
And I keep receiving values after some period of time. So I'm running for range loop on my channel:
for update := range ints {
if update > 10 { // let's say update == 15 for example
// Here I want to continue execution of this block, however having
// the next value of update var, even though it will be <= 10.
// lets say next value is received and update == 5.
fmt.Println(update) // So this should print "5", not "10"
continue
} else {
fmt.Println("less than 10")
continue
}
}
So basically I want this block to sleep for some time until next value is received from channel and continue execution, given that update variable now has different value.
My first thoughts were to create smth like "isNewValueReceived" bool variable and use it to continue execution where I want. However, it seems to be wrong solution, since the logic of the program might get more complex.
Please, help me to find a solution of this problem. Thank you in advance!
UPD:
hasGoneAbove := false // initially set to false as no values have been received
hasGoneAbove2 := false
hasGoneAbove3 := false
hasGoneAbove3 := false
for update := range ints {
if hasGoneAbove{
doSomeJob()
hasGoneAbove = false
hasGoneAbove2 = true
continue
}
if hasGoneAbove2{
doSomeJob2()
hasGoneAbove2 = false
hasGoneAbove3 = true
continue
}
if hasGoneAbove3{
doSomeJob3()
hasGoneAbove3 = false
continue
}
if update > 10 {
hasGoneAbove = true
} else {
fmt.Println("less than 10")
}
}
Trying to make sense of your question, you seem to want to work with a state tracking variable:
hasGoneAbove := false // initially set to false as no values have been received
for update := range ints {
if hasGoneAbove{
fmt.Println(update)
hasGoneAbove = false
}
if update > 10 {
hasGoneAbove = true
} else {
fmt.Println("less than 10")
}
}
Updated:
With this sort of holding only the last value in memory:
var lastValue int // use zero value
for update := range ints {
if lastValue > 2{
doSomeJob2()
}
if hasGoneAbove > 3{
doSomeJob3()
}
if lastValue > 10{
doSomeJob()
} else {
fmt.Println("less than 10")
}
lastValue = update
}
Note: as per the code in your question, if the LastValue is 10 then all three functions are going to execute. Depending on how compute intensive they are you might want to run them in a goroutine.

Failed to update rows in "jinzhu/gorm" pkg

I need to update value of fields in multiple rows.
I'm querying to get some of the database rows, but it doesn't work.
DB.Where("is_send = ?", "0").Find(&artists)
for _, artist := range artists {
if condition {
artist.IsSend = 1
... (more updatee)
DB.Save(&artist)
}
}
Change how you range it, by referring the below example:
for _, elem := range elems {
elem = new_val // Won't work, because elem is a copy of
// the value from elems
}
for i := range elems {
elems[i] = new_val // Works, because elems[i] deferences
// the pointer to the actual value in elems
}
Read: Gotchas
Also, if you're not modifying all fields, rather than using Save you can use Update as well. Refer: GORM CRUD's Interface UPDATE

Check if every item in a struct is unchanged

I have the following package:
// Contains state read in from the command line
type State struct {
Domain string // Domain to check for
DomainList string // File location for a list of domains
OutputNormal string // File to output in normal format
OutputDomains string // File to output domains only to
Verbose bool // Verbose prints, incl. Debug information
Threads int // Number of threads to use
NoColour bool // Strip colour from output
Silent bool // Output domains only
Usage bool // Print usage information
}
func InitState() (state State) {
return State { "", "", "", "", false, 20, false, false, false }
}
func ValidateState(s *State) (result bool, error string ) {
if s.Domain == "" && s.DomainList == "" {
return false, "You must specify either a domain or list of domains to test"
}
return true, ""
}
Within ValidateState() I would like to return true if every item in State is the same as what is defined in InitState(). I can see a few ways to do this, but nothing that seems concise. I would greatly value some direction!
Struct values are comparable if all their fields are comparable (see Spec: Comparison operators). And since in your case this holds, we can take advantage of this.
In your case the simplest and most efficient way to achieve this is to save a struct value holding the initial value, and whenever you want to tell if a struct value (if any of its fields) has changed, simply compare it to the saved, initial value. This is all it takes:
var defaultState = InitState()
func isUnchanged(s State) bool {
return s == defaultState
}
Testing it:
s := InitState()
fmt.Println(isUnchanged(s))
s.Threads = 1
fmt.Println(isUnchanged(s))
Output (try it on the Go Playground):
true
false
Note that this solution will still work without any modification if you change the State type by adding / removing / renaming / rearranging fields as long as they all will still be comparable. As a counter example, if you add a field of slice type, it won't work anymore as slices are not comparable. It will result in a compile-time error. To handle such cases, reflect.DeepEqual() might be used instead of the simple == comparison operator.
Also note that you should create default values of State like this:
func NewState() State {
return State{Threads: 20}
}
You don't have to list fields whose values are the zero values of their types.

Delete first item in slice if length > 100

When the RSS feeds updates (it doesn't right now, just dummy data) the new items are appended to the "feed" slice. Over time this could mean that it contains millions of items, I don't want that.
So when there are more than 100 items in the slice it should delete items starting from the top (item 0). In this example I'm using an RSS file with ust 100 items so the sample code below should delete from the top after 50 items:
package main
import (
"fmt"
"github.com/SlyMarbo/rss"
"time"
)
var feed *rss.Feed
var directory = "./dump"
func main() {
for {
checkRSS()
// Check every minute if feed.Refresh has passed so it run's update()
time.Sleep(1 * time.Minute)
}
}
func checkRSS() (*rss.Feed, error) {
var err error
// If feed is still empty fetch it first so we can run update()
if feed == nil {
feed, err = rss.Fetch("http://cloud.dgier.nl/api.xml")
} else {
err = feed.Update()
}
length := len(feed.Items)
for key, value := range feed.Items {
fmt.Println(key, value.Title, value.Read)
if key >= 50 {
fmt.Println("Item key is > 50")
}
}
fmt.Printf("Current length: %d\n", length)
fmt.Printf("Refreshing at %s\n", feed.Refresh)
return feed, err
}
If the number of items in the feed grows over the limit, slice it:
length := len(feed.Items)
if length > limit {
feed.Items = feed.Items[length - limit:]
}
When the length is over the limit, the new length will be exactly limit.
You don't need a for loop there.
To achieve this you probably want to use subslicing. Say you want to remove x items from feed, you can simply do feed = feed[x:] which will yield all items after index x-1 and assign it back to the feed slice. If in your actual code you just want to remove the first item then it would be feed = feed[1:]

Resources