Dash Unable to Center Table Horizontally - plotly-dash

My code below reads in a small CSV file, defines the styles, and displays the output.
The H1 tag is centred, as expected.
But for some reason, my table is not centered horizontally.
What am I doing wrong?
df = pd.read_csv('myfile.csv')
app = Dash(__name__)
hdg_style = {'color': '#055d9c', 'text-align': 'center'}
tblh_style = {'backgroundColor': 'Linen', 'fontWeight': 'semi-bold'}
tbl_style = {'textAlign': 'center', 'maxWidth': '1000px', 'border': 'thin #055d9c solid'}
app.layout = html.Div([
html.H1(children="My Project", style=hdg_style),
dash_table.DataTable(
data = df.to_dict('records'),
columns = [{'id': c, 'name': c} for c in df.columns],
style_cell = {'textAlign': 'center'},
style_header = tblh_style,
style_table = tbl_style)])
if __name__ == '__main__':
app.run_server(debug=True)
I tried the CSS below to center the table horizontally, but it did not work.
style={'margin-left': 'auto', 'margin-right': 'auto'}

If you include the margin attributes in your tbl_style definition, it'll center the table - it did for me in my test case:
tbl_style = {'textAlign': 'center', 'maxWidth': '1000px', 'border': 'thin #055d9c solid', 'marginLeft': 'auto', 'marginRight': 'auto'}
I suspect your attempts with CSS modifications get caught up in the vagaries of Dash configuration of serving static css files.

app.layout = dbc.Container(). In that, you put multiple dbc.Row. Then, dbc.Col in them. In these columns you put objects (your datatable). You can then align anything you wish moving objects by defining size and offset. Check official dash bootstrap components doc for the detail

Related

How to round the borders of a card in a Dash app

I have the following code which gives me a scatter plot on a dbc.Card element within Dash. I'm trying to figure out what I need to do in order to make the corners of the card rounded.
Here's the code I have currently:
import dash
from dash import dcc
from dash import html
from dash import Input, Output
import dash_bootstrap_components as dbc
import plotly.express as px
import pandas as pd
# import the Caffeine dataset
caffeine = pd.read_csv('caffeine.csv')
# create scatter plot
scatter = px.scatter(caffeine,
x='Volume (ml)',
y='Caffeine (mg)',
color='type',
title='Volume x Caffeine',
height = 800,
hover_data=['drink'],
template='plotly_dark'
)
# layout of Dash app
pp.layout = dbc.Container([
dbc.Row(
dbc.Col(html.H1("Analysis of Caffeinated Drinks",
className='text-center mb-4',),
width=12
)
),
dbc.Row(
dbc.Col(
dbc.Card(
dbc.CardBody(
dcc.Graph(
figure=scatter
)
)
),
width={'size':10, 'offset':1}
)
)
I've tried using the answer on this stackoverflow question (How to round the corners of a card (body and image) in Bootstrap 4?) and as such I tried inserting a style={border-radius: '20px'} in a couple of different places but haven't had any luck producing a change.
Is there another method I could/should use, or else could someone please show me exactly what to do? I'm pretty new to Dash as well as html and css.
Many, many thanks in advance!
If you set the style in a CSS file, you need to use border-radius: 20px;, but if you set the style directly on the dbc.Card component, you have to set borderRadius=20.
I would suggest you add in your style.css a class called something like card-style and there, you will add all the CSS stuff
So, in your code, you will add the class in the className of the dbc.Card
app.layout = dbc.Container([
dbc.Row(
dbc.Col(html.H1("Analysis of Caffeinated Drinks",
className='text-center mb-4',),
width=12
)
),
dbc.Row(
[(dbc.Col(
dbc.Card(
dbc.CardBody(
html.Div(f"card {n}")
),
className="card-style"
),
width={'size':3, 'offset':1}
)) for n in range(8)]
)])
And in your assets/style.css you will add something like:
.card-style {
border: solid black 1px;
border-radius: 8px;
height: 120px;
}
It will help you to not repeat yourself by simply creating this kind of class for your elements.
You can check and test the HTML elements by pressing F12 and selecting what you're interested in;
The output of the code above is the above

R - combine image and table then export as PDF

I have four goals:
Connect to a Postgresql database and pull some data
Gloss up a table with some colour and formatting
Include an image (company logo) above it
Export as PDF
1 and 2 are easy enough and 4 seems possible even if not convenient, but I don't think R was designed to add and position images. I've attached some sample code of how I envision creating the table, and then a mockup of what I think the final version might look like. Can anyone advise on the best way to accomplish this?
Sample data:
data(mtcars)
df <- head(mtcars)
HTML approach: flexible and portable to other apps
library(tableHTML)
html_table <- df %>%
tableHTML(rownames = FALSE, border = 0) %>%
add_css_row(css = list(c('font-family', 'text-align'), c('sans-serif', 'center'))) %>%
add_css_header(css = list(c('background-color', 'color'), c('#173ACC', 'white')), headers = 1:ncol(df))
Grob approach: Creating a ggplot-like image. I've seen recommendations to use grid.arrange to place an image on top and export as a PDF
library(ggpubr)
tbody.style = tbody_style(color = "black",
fill = "white", hjust=1, x=0.9)
grob_table <- ggtexttable(df, rows = NULL,
theme = ttheme(
colnames.style = colnames_style(color = "white", fill = "#173ACC"),
tbody.style = tbody.style
)
)
grid.arrange(table_image)
You are almost there. You just need to import your image (could be png, jpeg or svg) then pass it to grid::rasterGrob. Use the options in rasterGrob to adjust size etc. Then pass your grob table to gridExtra::grid.arrange
logo_imported <- png::readPNG(system.file("img", "Rlogo.png", package="png"), TRUE)
lg <- grid::rasterGrob(logo_imported)
gridExtra::grid.arrange(lg, grob_table)
You can then either render this to pdf by adding it to an rmarkdown report (probably best), or you can save directly to pdf via
gridExtra::grid.arrange(lg, grob_table)
pdf(file = "My Plot.pdf",
width = 4, # The width of the plot in inches
height = 4)

A way to scroll a layout's widgets using mouse?

Can you help me on how to scroll a layout's content using mouse? Or is it possible?
I created this notification-center widget and I used wibox.layout.fixed.vertical() to act the storage of the widgets/notifications. My problem is having too many widgets will consume all the space and there will be no enough space to display the other widgets. So I've been trying to make the widget inside the wibox.layout.fixed.vertical() scrollable but I'm always reaching a dead end. I also tried the wibox.container.scroll but as the documentation says:
Please note that mouse events do not propagate to widgets inside of the scroll container.
This is the simple code I'm using:
-- Layout
local notifbox_layout = wibox.layout.fixed.vertical()
-- Add these textbox widgets to layout
-- Make this widgets scrollable if there's too many of them
notifbox_layout:insert(1, wibox.widget.textbox('String 1'))
notifbox_layout:insert(1, wibox.widget.textbox('String 2'))
notifbox_layout:insert(1, wibox.widget.textbox('String 3'))
notifbox_layout:insert(1, wibox.widget.textbox('String 4'))
notifbox_layout:insert(1, wibox.widget.textbox('String 5'))
-- Mouse event
notifbox_layout:buttons(
gears.table.join(
awful.button(
{},
4,
nil,
function()
-- some magic here to scroll up
end
),
awful.button(
{},
5,
nil,
function()
-- some magic here to scroll down
end
)
)
)
This is the notification center with no enough space to show the other widgets
Sorry if I explained this bad. I'm not really that good in english.
Nevermind. I tried Uli Schlachter's answer here. And it works perfectly. I modified it a bit and then it looks like this.
local w = wibox{ x = 100, y = 100, width = 100, height = 20, visible = true }
my_wiget = function()
return some_widget
end
local own_widget = wibox.widget.base.make_widget()
local offset_x, offset_y = -20, 0
function own_widget:layout(context, width, height)
-- No idea how to pick good widths and heights for the inner widget.
return { wibox.widget.base.place_widget_at(my_widget(), offset_x, offset_y, 200, 40) }
end
own_widget:buttons(
awful.util.table.join(
awful.button(
{},
4,
function()
if offset_y <= 490 then
offset_y = offset_y + 5
end
own_widget:emit_signal("widget::layout_changed")
end
),
awful.button(
{},
5,
function()
if offset_y >= 5 then
offset_y = offset_y - 5
end
own_widget:emit_signal("widget::layout_changed")
end
)
)
)
w:set_widget(own_widget)

Adding line breaks after image in Shiny

I'm new to HTML and am trying to create a custom landing page in Shiny.
Here's a snippet of my UI, but I cannot get additional line breaks between the image and the text. The image and the text render fine, but the breaks do not exist. I've also tried blank tags$p() to no avail.
navbarPage("",
tabPanel("Home",
tagList(
tags$img(src="test_vine.jpg", width = "100%", height = "100%", align = "left"),
tags$br(),
tags$br(),
tags$p("this is a test"))),
The fluidRow will solve this. Probably understanding the working of fluidRow would solve major alignment issues.
ui <- navbarPage("", tabsetPanel(
tabPanel("Home",
tagList(
fluidRow(tags$img(src = "image.png", width = "100%", height = "100%", align = "left")),
tags$br(),
tags$br(),
fluidRow(p("this is a test")))
## Simple way
# fluidRow(img(src = "image.png", align = "left", height = 300, width = 500)),
# br(),
# br(),
# fluidRow("this is a test")
)))

R tableHTML add_css text-align centre not working in Shiny

I'm trying to style a table in a Shiny app using the tableHTML package in R.
When I use the tableHTML() function in R it produces exactly what I want. I use the add_css_column to align the text in the column to the centre. However when I use it in a Shiny app the headers end up left aligned and the rows centre aligned. Any ideas how I can fix this?
output$viewers_website_top <- renderUI({
tableHTML(website_index, rownames = FALSE, widths=c(200,200)) %>%
add_css_column(css = list("text-align", "center"),
column_names = names(website_index))
})
This is a common issue with bootstrap 3 unfortunately. Whenever you use shiny it loads up a bootstrap 3 css (immediately) which makes it difficult to overwrite.
As for the solution to this using add_css_header would probably solve this one. add_css_header would change the th tag of the HTML table to the one you like (whereas add_css_header would change the td tags below the headers):
output$viewers_website_top <- renderUI({
tableHTML(website_index, rownames = FALSE, widths=c(200,200)) %>%
add_css_header(css = list("text-align", "center"),
headers = 1:ncol(website_index))
})
Another thing you can do is to add a separate css file with shiny::includeCSS. There is more info here and here on how to use includeCSS.
In the css file you need to write:
.table_website_index th {
text-align: center;
}
And that should do it!
P.S. table_website_index is the class the package assigns to the table which you can also change with the class argument.
P.S.2 I am the developer - thanks for using the package :)