Formatting issue with HTML template for r Shiny output table - html

I'll preface this by saying that I used to decent at HTML a couple of decades ago but I think I missed the connection with R. I'm trying to display some text and pass some variables. That is working great (I modified some basic code). However, I'm unable to change the format as everything is showing in one column instead of several. I tried a few things in vain. I have a feeling it's really basic but any help would be greatly appreciated.
Here is the HTML file :
<div class="aimm-score-table">
<ul class="aimm-score-row">
<li>Potential Score</li><li>Likelihood factor</li><li>Score</li>
</ul>
<ul class="aimm-score-row">
<li id="{{ ns('aimm_score_potential_score') }}"></li>
<li>--</li>
<li id="{{ ns('aimm_score_likelihood_factor') }}"></li>
<li>=</li>
<li id="{{ ns('aimm_score_score') }}"></li>
</ul>
<ul class="aimm-score-row">
<li>Rating</li>
<li id="{{ ns('aimm_score_rating') }}"></li>
</ul>
</div>
This is what I get :
This is what I want :

Here is a way. Of course you will have to change the CSS if you want other borders, etc.
library(htmltools)
tbl <- withTags(
table(
tbody(
tr(
td(colspan = 3, class="col3", "Potential"),
td(colspan = 3, class="col3", "Likelihood"),
td(colspan = 3, class="col3", "Ex-Ante")
),
tr(
td(),
td("88"),
td(colspan = 2, class="col2", "-"),
td("17"),
td(colspan = 2, class="col2", "="),
td("61"),
td()
),
tr(
td(colspan = 3, class="col3"),
td(colspan = 3, class="col3"),
td(colspan = 3, class="col3", "Good")
)
)
)
)
browsable(
tagList(
tags$style(
HTML(
"table {width: 400px; table-layout: fixed}",
"table, td {border: 1px solid black}",
"td {text-align: center}",
"td.col3 {width: calc(100% / 3)",
"td.col2 {width: calc(100% * 2 / 9)",
"td {width: calc(100% / 9)"
)
),
tbl
)
)

Stéphane Laurent many thanks, I integrated your code to my html template and this works like a charm.
#YBS I'm not familiar with the use of htmltable but I had to find a way to recycle variables stored under a www/ folder that are called from my ui :
htmlTemplate(
filename = "www/html/aimm_score_table.html",
ns = ns
),
and use an html table seemed the only way, I'm not used to combining different types of codes and storing stephanes as a template was the most straightforward. Thank you both!

Related

Unable to save reactive value from an html template for RShiny

I've been struggling with this, below is a much simplified version of my issue but here is the idea : I have a table with 4 text areas using an html template. When the user types into one of the 4 text areas (he can only input text in one), a score is assigned - cell 1 =1, cell 2 = 2 etc. Pulling the string content is not a problem but I can't seem to get the score assigned to save properly I'm not sure of what I am doing wrong.
library(shiny)
ui <- fluidPage(
column(
12,
actionButton("save_project", "save")),
column(
width = 12,
h4("Assessment #1"),
htmlTemplate(
filename = "market_table.html",
indicator = "market_creation_attr_1"
)
)
)
server <- function(input, output, session) {
market_ table_1_score <- reactiveVal(NULL)
observeEvent(c(input$market_creation_attr_1_market_rating_1,input$market_creation_attr_1_market_rating_2,input$market_creation_attr_1_market_rating_3,input$market_creation_attr_1_market_rating_4), {
if (!is.na(input$market_creation_attr_1_market_rating_1)||is.null(input$market_creation_attr_1_market_rating_1)){
market_table_1_score<-1
} else if (!is.na(input$market_creation_attr_1_market_rating_2)){
market_table_1_score<-2
}else if (!is.na(input$market_creation_attr_1_market_rating_3)){
market_table_1_score<-3
}else if(!is.na(input$market_creation_attr_1_market_rating_4)){
market_table_1_score<-4
}
market_table_1_score
})
observeEvent(input$save_project, {
inputs <- reactiveValuesToList(input)
filepath <- file.path("save", paste0("input-.rds"))
saveRDS(inputs, file = filepath)
all_values <- reactiveValuesToList(values)
filepath <- file.path("save", paste0("values--.rds"))
saveRDS(all_values, file = filepath)
})
}
shinyApp(ui=ui, server=server)
And this is the template of the html table (not sure that's relevant)
<div class="market-table">
<ul class="market-header">
<li style="border-right: 1px solid black"><div>Market Typology</div></li>
<li><div>Highly Developed</div></li>
<li><div>Moderately Developed</div></li>
<li><div>Under Developed</div></li>
<li><div>Highly Under Developed</div></li>
</ul>
<ul class="market-row">
<li>INDICAOTR</li>
<li>
<textarea id="{{ paste0(indicator, '_market_rating_1')}}" rows="5" maxlength="500"></textarea>
</li>
<li>
<textarea id="{{ paste0(indicator, '_market_rating_2')}}" rows="5" maxlength="500"></textarea>
</li>
<li>
<textarea id="{{ paste0(indicator, '_market_rating_3')}}" rows="5" maxlength="500"></textarea>
</li>
<li>
<textarea id="{{ paste0(indicator, '_market_rating_4')}}" rows="5" maxlength="500"></textarea>
</li>
</ul>
</div>
Any advice is greatly appreciated!
after spending several hours on the (I'm still a beginner), I found noticed 2 major errors : 1. in my condition, it shouldn't be !is.na, rather I should have used !='' 2. and this is pretty important, I didn't create an empty object to store the reactive values...oops.
Here is a working code (see template in my original question)
library(shiny)
ui <- fluidPage(
column(
12,
actionButton("save_project", "save")),
column(
width = 12,
h4("Assessment #1"),
htmlTemplate(
filename = "market_table.html",
indicator = "market_creation_attr_1"
)
)
)
server <- function(input, output, session) {
values <- reactiveValues()
market_typology_table_1_score <- reactiveVal(NULL)
observeEvent(c(input$market_creation_attr_1_market_rating_1,input$market_creation_attr_1_market_rating_2,input$market_creation_attr_1_market_rating_3,input$market_creation_attr_1_market_rating_4), {
if (input$market_creation_attr_1_market_rating_1!=''){
market_ table_1_score<-1
} else if (input$market_creation_attr_1_market_rating_2!=''){
market_ table_1_score<-2
}else if (input$market_creation_attr_1_market_rating_3!=''){
market_ table_1_score<-3
}else if(input$market_creation_attr_1_market_rating_4!=''){
market_table_1_score<-4
}
values$market_typology_table_1_score<-isolate(market_typology_table_1_score)
})
observeEvent(input$save_project, {
inputs <- reactiveValuesToList(input)
filepath <- file.path("save", paste0("input.rds"))
saveRDS(inputs, file = filepath)
all_values <- reactiveValuesToList(values)
filepath <- file.path("save", paste0("values.rds"))
saveRDS(all_values, file = filepath)
})
}
shinyApp(ui=ui, server=server)

Typo3-Fluid doesnt render my Content Elements | Error : "Content Element with uid "189" and type "text" has no rendering definition!"

i am trying to setup a Typo3 (v.8.7.27) Homepage using Fluid and Backendlayouts.
First i created a Backendlayout (uid = 4) and also a new Template-Html (...\Resources\Private\Templates\Page\Test1). I edited my setup.typoscript for the extension and added the following Code (actuelly just the part with the 4 / 4.)
10 = FLUIDTEMPLATE
10 {
templateName = TEXT
templateName.stdWrap.cObject = CASE
templateName.stdWrap.cObject {
key.data = pagelayout
pagets__site_theme_default = TEXT
pagets__site_theme_default.value = Default
4 = TEXT
4.value = Test1
default = TEXT
default.value = Default
}
My Test1.html looked like this:
<f:layout name="Default" />
<f:section name="Main">
<main role="main">
<f:cObject typoscriptObjectPath="lib.dynamicContent" data="{pageUid: '{data.uid}', colPos: '11', wrap: '<div class=\"hero\">|</div>'}" />
</main>
</f:section>
Here is the Problem: Everything worked but it didnt render the Content - instead it "wrapped" the Error Msg: " Content Element with uid "189" and type "text" has no rendering definition!"
<div class="hero">
<p style="background-color: yellow; padding: 0.5em 1em;">
<strong>ERROR:</strong> Content Element with uid "189" and type "text" has no rendering definition!
</p>
</div>
In the Backend i added this Backendlayout to the Rootpage and created the Content Element for colPos 11 - its just a simple Text. I have problems understand what could be wrong as it correctly shows the uid of the Contentelement in the Error msg... Any idears?
Thank you for your help! And please write if you need more information
Daniel
The Import of Fluid had a syntax mistake. The Problem is fixed - thanks to #bandanh. If you have a problem like this check your TypoScript Objekt Browser and look for unexpected stuff / missing Objects.
Thank you,
Daniel

How can I render strings with certain characters as value of input tag?

I am passing an array of category names to my template and iterating through this to populate the value of checkbox elements.
<input id={{"category"|add:escaped_cat_name}} type="checkbox" name="category" value={{category_name}}>
Some of my category names contain spaces and ampersands but Django ignores these so "Fun & Gaming" becomes "Fun":
category_name: Fun & Gaming
<input id="categoryFun" type="checkbox name="category" value="Fun">
category_name: Business Expenses
<input id="categoryBusiness" type="checkbox name="category" value="Business">
In these examples, I would like the interpreted value to read the 'Fun & Gamingand 'Business Expenses
If I add a safe tag to the value it renders the value name as "Fun" & gaming, with the second part of the string still outside the value name.
I have tried writing a custom tag to deal with this behaviour but it seems as though this is Django's default and I can't figure out how to disable it.
Any help with this would be much appreciated.
This is my answer, and I know this answer will not be nice for you: you should to learn a bit more about django, and about django forms:
Handling and processing inputs by hand is an anti-pattern. The right way is to create a Form object and render the form in template.
You can learn about forms at Working with forms djag's documentation.
Let me copy here a sample for checkboxes:
from django import forms
BIRTH_YEAR_CHOICES = ('1980', '1981', '1982')
FAVORITE_COLORS_CHOICES = (
('blue', 'Blue'),
('green', 'Green'),
('black', 'Black'),
)
class SimpleForm(forms.Form):
birth_year = forms.DateField(
widget=forms.SelectDateWidget(years=BIRTH_YEAR_CHOICES))
favorite_colors = forms.MultipleChoiceField(
required=False,
widget=forms.CheckboxSelectMultiple,
choices=FAVORITE_COLORS_CHOICES,
)
So then, we do not have to re-invent the wheel and just use Forms.
For your data:
>>> FAVORITE_COLORS_CHOICES = (
... ('categoryFun', 'Fun & Gaming'),
... ('categoryBusiness', 'Business Expenses'),
... )
>>>
>>> class SimpleForm(forms.Form):
... favorite_colors = forms.MultipleChoiceField(
... required=False,
... widget=forms.CheckboxSelectMultiple,
... choices=FAVORITE_COLORS_CHOICES,
... )
...
>>> str( SimpleForm() )
'<tr><th><label>Favorite colors:</label></th>
<td>
<ul id="id_favorite_colors">
<li>
<label for="id_favorite_colors_0">
<input type="checkbox" name="favorite_colors"
value="categoryFun" id="id_favorite_colors_0" />
Fun & Gaming
</label>
</li>...'

Customizing the matrixInput function from shinyincubator to remove +/- and show column names

https://github.com/rstudio/shiny-incubator/blob/master/R/tableinput.R
Here is the link to the link to the code for the matrixInput function
of the shinyIncubator package.
I have two problems, that relate to the css/html part of the code; which is a language I have no clue off.
Here is a simple reproducible example:
server.R
shinyServer(function(input, output) {})
ui.R
library("shiny")
library("shinyIncubator")
df <- data.frame(matrix(c("0","0"), 1, 2))
colnames(df) <- c("first", "second")
shinyUI(
pageWithSidebar(
headerPanel("Matrix input problem"),
sidebarPanel(
matrixInput(inputId = 'data', label = '', data = df)
)
,
mainPanel()
)
)
I would like to change two things in the customized matrixInput function :
-Make the +/- option on the rows disappear (no possibility to add rows)
-Show the columns names of the matrix that was used as input (I saw related subjects but the solutions provided don't seem to work for me)
Can anyone with experience in said languages help out?
Hello readers of the question.
Since my need for an answer was pretty urgent, I took some time to just randomly try out things myself, laso trying to get inspired from related subjects.
I think I have a function the does the things I wanted corretly now.
I will post the code here.
Basically it is the same as the original, but there are just some things I disabled by putting them as comments as you will see.
matrixInput2 <- function(inputId, label, data) {
addResourcePath(
prefix='tableinput',
directoryPath=system.file('tableinput',
package='shinyIncubator'))
tagList(
singleton(
tags$head(
tags$link(rel = 'stylesheet',
type = 'text/css',
href = 'tableinput/tableinput.css'),
tags$script(src = 'tableinput/tableinput.js')
)
),
tags$div(
class = 'control-group tableinput-container',
tags$label(
class = "control-label",
label
#THIS seems to be responsible (atleast partially, regarding the display) for the +/- buttons
# ,
# tags$div(
# class = 'tableinput-buttons',
# tags$button(
# type = 'button', class = 'btn btn-mini tableinput-settings hide',
# tags$i(class = 'glyphicon glyphicon-cog icon-cog')
# ),
# HTML('<i class="glyphicon glyphicon-plus-sign icon-plus-sign"></i>'),
# HTML('<i class="glyphicon glyphicon-minus-sign icon-minus-sign"></i>')
# )
),
tags$table(
id = inputId,
class = 'tableinput data table table-bordered table-condensed',
tags$colgroup(
lapply(names(data), function(name) {
tags$col('data-name' = name,
'data-field' = name,
'data-type' = 'numeric')
})
)
,
tags$thead(
#Here I just put this line as a comment. Setting the class as 'hide' hid the column names. I don't know where the deal with the rownames is.
# class = 'hide',
tags$tr(
lapply(names(data), function(name) {
tags$th(name)
})
)
),
tags$tbody(
lapply(1:nrow(data), function(i) {
tags$tr(
lapply(names(data), function(name) {
tags$td(
div(tabindex=0, as.character(data[i,name]))
)
})
)
})
)
),
tags$div(
class = 'tableinput-editor modal hide fade',
tags$div(
class = 'modal-header',
HTML('<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>'),
tags$h3(label)
),
tags$div(
class = 'modal-body',
HTML('
<form class="form-horizontal">
<div class="control-group">
<label class="control-label">Rows</label>
<div class="controls">
<input type="number" class="tableinput-rowcount">
</div>
</div>
<div class="control-group">
<label class="control-label">Columns</label>
<div class="controls">
<input type="number" class="tableinput-colcount">
</div>
</div>
</form>'
)
),
tags$div(
class = 'modal-footer',
tags$a(href = '#', class = 'btn btn-primary tableinput-edit', 'OK'),
tags$a(href = '#',
class = 'btn',
'data-dismiss' = 'modal',
'aria-hidden' = 'true',
'Cancel')
)
)
)
)
}
I hope this will help some people that want to do the same thing as me.
If anyone with more experience here can do something about the rownames; it would probably be interesting. (I read in a related subject that it's a bit harder to do than for the column names as matrixInput seems to be discarding them instead of just hiding)
source: How to show/set row names to matrixInput (shinyIncubator)
The repoducible example from the question can be used to try it out.
Cheers

Embedding multiple bokeh HTML plots into flask

I've searched for the past 3 hours on the bokeh website and stack overflow but none of it is really what i was looking for.
I've generated my plots already, and have them in html files. All i want to do is embed the plots into my dashboard in a multi grid like formation in the white area in the pic below. However, adding just 2 plots cause them to overlay and be really weird.
I used the {{ include }} method to include the graphs this way:
Anyone can give me pointers on how to align them well? Ideally i want 6 small plots in that space. I didnt want to regenerate the plots everytime i loaded the dashboard so i didnt want the embed way.
Please help :( Thank you so much!
EDIT: following big's suggestion, using responsive = True works, but i am unable to control the css styling and the sizes of the charts. I suspect its to do with using the include tag. can anyone help? :)
Why you dont try to make it with the horizontal layout
horizontal-layout
Whith your way ( {% include %} ), i don't find a solution so probably sou must use the standart flask way. Python file:
#Your imports
from flask import Flask, render_template
from bokeh.embed import components
from bokeh.plotting import figure
#app.route('/')
def homepage():
title = 'home'
from bokeh.plotting import figure
#First Plot
p = figure(plot_width=400, plot_height=400, responsive = True)
p.circle([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], size=20, color="navy", alpha=0.5)
#Second Plot
p2 = figure(plot_width=400, plot_height=400,responsive = True)
p2.square([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], size=20, color="olive", alpha=0.5)
script, div = components(p)
script2, div2 = components(p)
return render_template('index.html', title = title, script = script,
div = div, script2 = script2, div2 = div2)
Your HTML file:
<!DOCTYPE html>
<html lang="en">
<head>
<link
href="http://cdn.bokeh.org/bokeh/release/bokeh-0.11.1.min.css"
rel="stylesheet" type="text/css">
<script src="http://cdn.bokeh.org/bokeh/release/bokeh-0.11.1.min.js"></script>
<meta charset="UTF-8">
<title>{{title}}</title>
</head>
<body>
<div style="width: 20%; display: inline-block;">
{{ div | safe }}
{{ script | safe }}
</div>
<div style="width: 20%; display: inline-block;">
{{ div2 | safe }}
{{ script2 | safe }}
</div>
</body>
</html>
And one other tip is to make a python file like my_plots.py
and add your plots there, and then import to you main.py it will make your code cleaner. (i dont know 100% if this will impact your speed, but i don't seen any isues until now ) For example.
my_plots.py:
from bokeh.plotting import figure
def first_plot():
p = figure(plot_width=400, plot_height=400, responsive = True)
p.circle([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], size=20, color="navy", alpha=0.5)
return p
def second_plot():
p2 = figure(plot_width=400, plot_height=400, responsive = True)
p2.square([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], size=20, color="olive", alpha=0.5)
return p2
main.py:
#app.route('/')
def homepage():
title = 'home'
#First Plot
from my_plots import first_plot
p = first_plot()
#Second Plot
from my_plots import second_plot
p2 = second_plot()
script, div = components(p)
script2, div2 = components(p)
return render_template('index.html', title = title, script = script,
div = div, script2 = script2, div2 = div2)
Hope i was helpful, Good Luck!
Updating Leo's answer as it is for the deprecated version of Bokeh.
Bokeh v3.0.1
Flask v2.2.2
Flask App
from flask import Flask, render_template
from bokeh.embed import components
from bokeh.plotting import figure
app = Flask(__name__)
#app.route('/')
def homepage():
title = 'home'
from bokeh.plotting import figure
### First Plot ###
p1 = figure(height = 400, sizing_mode = "stretch_width")
p1.circle([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], size=20, color="navy", alpha=0.5)
### Second Plot ###
p2 = figure(height = 400, sizing_mode = "stretch_width")
p2.square([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], size=20, color="olive", alpha=0.5)
script1, div1 = components(p1)
script2, div2 = components(p2)
return render_template(
'index.html',
title = title,
script = script1,
div = div1,
script2 = script2,
div2 = div2
)
if __name__ == '__main__':
app.run(debug=True)
HTML Template
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://cdnjs.cloudflare.com/ajax/libs/bokeh/3.0.1/bokeh.min.js"
integrity="sha512-p7EUyPmeDeOwHiu7fIZNboAcQLxei3sWtXoHoShWWiPNUSRng/Xs5JPcaFPRa4dKy9IuHjyIQuLE4caGCwuewA=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<title>Bokeh Charts</title>
</head>
<body>
<div style="width: 40%; display: inline-block;">
{{ div1 | safe }}
{{ script1 | safe }}
</div>
<div style="width: 40%; display: inline-block;">
{{ div2 | safe }}
{{ script2 | safe }}
</div>
</body>
</html>