Dash Navbar with buttons/navlink to open collapse and navigate (combined) - plotly-dash

I have a Dash page consisting of:
a body with several dbc.Collapse components that contain graphs, tables, etc.
a top navbar containing several buttons which trigger (by separate callbacks):
The associated collapse group to open/close
The browser to navigate to that collapse group
dbc.NavLink(display_name, id=self.n_id, n_clicks=0, class_name=dn.dbc_menu_fs)
The callback for navigation, which is the same for all buttons in the navbar looks like this:
#app.callback(
output = Output('url', "href"),
inputs = [navigation_ids],
prevent_initial_call=True
)
def navigate(navs):
trigger = ctx.triggered_id
return '/#' + trigger[:-1] + 'CD'
The problem I have is that the section scroll below the Navbar by the height of the Navbar, as shown in the picture.
I've tried to reproduce just the navigation with Navlinks, using Navlinks with external_link on/off:
navs.append(dbc.NavLink("Overview ", href="/#Overview_CD", external_link=False))
navs.append(dbc.NavLink("Overview- ext", href="/#Overview_CD", external_link=True))
While the external_link=False works perfectly, the external_link=True shows the same navigation effect as the above callback.
I've tried using padding Divs, chaging Navbar 'sticky' and 'fixed' options, etc. but had no luck.
Any clue on how to get my callback (or a .js) reproduce the Navlink with external_link=False?
page content when navigating with callback or external_link=True

I've never done things with dbc.NavLink like you are doing above, but I suspect you can achieve a better result using Dash pages. This is the new recommended way to build multi-page apps.
To implement a navbar that won't have the problem like I think I understand you are having with it overlaying your content, you simply define it in the app.layout alongside the dash.page_container:
app.py
navbar = dbc.Navbar(
dbc.Container(
[
# Use row and col to control vertical alignment of logo / brand
dbc.Row(
[
dbc.Col(
# Any compoents you want can go here
),
# Another column, etc.
]
),
sticky="top", # Maybe unnecessary
)
app.layout = dbc.Container(
[
navbar,
dash.page_container,
],
className="dbc",
fluid=True,
)
dash.page_container is dynamically filled based on the path from layouts defined in .py files stored in the pages directory.
Each page is registered using dash.register_page(__name__, path=<path>).
So if I want to define a home page:
pages/home.py
import dash
import dash_bootstrap_components as dbc
from dash import dcc, HTML
dash.register_page(__name__, path="/")
def layout():
return html.Div([
dbc.Container([...])
])

Related

How to load more element from web pages using BeautifulSoup and/or selenium

I would like to get each link that the each boxes contain, the page is https://www.quattroruote.it/listino/audi
In this webpage there are all the model that this brand is producing, and each model is a boxes that links to another page (the one in which I should work with).
My problem is that the initial page do not load all the boxes the first time, you have to scroll down and press the red button "Carica altri modelli" (which mean "Load other models").
Is there a way to automatically store in one variable all the links that i need? For example, the first links of the first box is "/listino/audi/a1"
Thanks in advance to anyone who try to help me!!
Not sure exactly what links you want, but you can make the requests iterating through the itemStart parameter.
import requests
from bs4 import BeautifulSoup
for i in range(1,100):
print('\t\tList start %s' %i)
url = 'https://www.quattroruote.it/listino/ricerca-more-desktop.html'
payload = {
'area': 'NEW',
'itemStart': '%s' %(i*8),
'_': '1634219611449'}
response = requests.get(url, params=payload)
soup = BeautifulSoup(response.text, 'html.parser')
links = soup.find_all('a', href=True)
for link in links:
print(link['href'])

<a> tag goes to new page, but does not go to the top of the new page

I'm working on a gatsby-react project that has multiple pages. On the header & footer there are links to other pages within my project. When I click on the link, the URL changes, the browser loads the new page and renders it normally.
The only problem is that the new page isn't loaded from the top. For example, if I'm currently viewing the bottom of the page and I click a link, then I expect to be taken to the top of the new page. What happens is I am taken to the new page, but I stay at the bottom. This image should explain what I mean.
I'm NOT using GatsbyLinks as they cause problems in the project, I use normal <a> tags for links instead.
Can I add anything to the <a> tag that can force going to the top of the page? If not then is there some other linking component I can use?
Thanks in advance!
The process of scroll restoration is handled automatically by Gatsby, however, using anchor links (<a>) for internal navigation (outside the scope of React) may lead to this kind of issue, since the data of the page it's cached but you are not using internal navigation to manage or restore it.
That said, I would suggest using the useScrollRestoration hook when needed:
import { useScrollRestoration } from "gatsby"
import countryList from "../utils/country-list"
export default function PageComponent() {
const ulScrollRestoration = useScrollRestoration(`page-component-ul-list`)
return (
<ul style={{ height: 200, overflow: `auto` }} {...ulScrollRestoration}>
{countryList.map(country => (
<li>{country}</li>
))}
</ul>
)
}
For a more global approach, you can also play with gatsby-browser.js APIs such as onRouteUpdate and shouldUpdateScroll, both triggered in each change of page (navigation):
exports.onRouteUpdate = () => {
if (typeof window !== `undefined`) { window.scrollTo(0, 0)}
}
exports.shouldUpdateScroll = args => {
return false;
};
By default, shouldUpdateScroll gets the last scrolled position, ideally, just changing and returning false it should work for your described scenario.

Get links from summary section of wikipedia page

I am trying to extract links from the summary section of a wikipedia page. I tried the below methods :
This url extracts all the links of the Deep learning page:
https://en.wikipedia.org/w/api.php?action=query&prop=links&titles=Deep%20learning
And for extracting links associated to any section I can filter based on the section id - for e.g.,
for the Definition section of same page I can use this url : https://en.wikipedia.org/w/api.php?action=parse&prop=links&page=Deep%20learning&section=1
for the Overview section of same page I can use this url : https://en.wikipedia.org/w/api.php?action=parse&prop=links&page=Deep%20learning&section=2
But I am unable to figure out how to extract only the links from summary section
I even tried using pywikibot to extract linkedpages and adjusting plnamespace variable but couldn't get links only for summary section.
You need to use https://en.wikipedia.org/w/api.php?action=parse&prop=links&page=Deep%20learning&section=0
Note that this also includes links in the
{{machine learning bar}} and {{Artificial intelligence|Approaches}} templates however (to the right of the screen).
You can use Pywikibot with the following commands
>>> import pywikibot
>>> from pwikibot import textlib
>>> site = pywikibot.Site('wikipedia:en') # create a Site object
>>> page = pywikibot.Page(site, 'Deep learning') # create a Page object
>>> sect = textlib.extract_sections(page.text, site) # divide content into sections
>>> links = sorted(link.group('title') for link in pywikibot.link_regex.finditer(sect.head))
Now links is a list containing all link titles in alphabethical order. If you prefer Page objects as result you may create them with
>>> pages = [pywikibot.Page(site, title) for title in links]
It's up to you to create a script with this code snippets.

Add external hyperlink to tabPanel or navbarMenu in r Shiny

I am trying to add external hyperlinks to the tabPabel and navbarMenu tabs/dropdowns in a navbarPage setup in Shiny (using bootstrapPage). I found multiple questions that refer to linking to another tab within a Shiny app, but I want to specifically link to another webpage without opening a new browser window.
I found the following questions that kind of get there:
How to direct to another web page after clicking tabPanel in Shiny App
Open URL by tabPanel in Shiny
The second question is what I want to do; however, when I use the following method to accomplish this, it adds a "phantom" tab:
tabPanel(a("Open Sales Gsheet", href="http://google.com", target="_blank"))
Here is some example code for the Shiny app setup that I am working with:
library(shiny); library(shinythemes)
ui <- bootstrapPage("",
navbarPage(
id = "navbar",
theme = shinytheme("yeti"),
title = a("Home", href = "https://google.com", style = "color:white;"), ## page title with hyperlink and browser tab title (works as intended)
tabPanel(title = HTML("Panel_1</a></li><li><a href='http://google.com' target='_blank'>test")), ## tabPanel hyperlink test (adds "phantom" tab)
navbarMenu(title = "Test Menu",
tabPanel(title = a("Open Sales Gsheet", href="http://google.com", target="_blank")) ## navbarMenu hyperlink test (adds "phantom" option)
)
)
)
server <- function(input, output, session) {
## empty server
}
shinyApp(ui, server)
Here is a screenshot of the "phantom" tab issue:
https://i.imgur.com/tIYbhzT.png
As you can see, both the tabPanel and navbarMenu tabs/dropdowns have additional "phantom" tabs that have been added as a result. The first question I posted above shows an answer that involves editing the html code (or the list that is produced in R)... but I cannot figure out how to do this with a tabPanel or navbarMenu object.
I just want this to look like a normal navbarPage dropdown where the tabPanel and navbarMenu selections link to an external site (in the same browser window - browseURL as an observeEvent in the server script does not work since it opens in another window). Any help would be appreciated!
It's tricky to add custom elements in a shiny navbar page but it can be done with some javascript. The following code should add your link to the dropdown menu in the navbar. Save it as a .js file in your app's base directory then include the script in your ui function.
navAppend.js in your app's base directory:
$(document).ready(function() {
$(".navbar .container-fluid .navbar-nav .dropdown .dropdown-menu").append('<li>Open Sales Gsheet</li>');
});
in your ui:
ui <- tagList(
tags$head(includeScript("navAppend.js")),
navbarPage(
id = "navbar",
theme = shinytheme("yeti"),
title = a("Home", href = "https://google.com", style = "color:white;"), ## page title with hyperlink and browser tab title (works as intended)
# nav menu the link will be added to
navbarMenu(title = "Test Menu")
)
)

How to create dynamic callback for generated component

I am able to understand how the callbacks work in the dash-table-experiment where the DataTable is part of the app.layout = Div/Html layout.
But how do I create the callback when the DataTable is generated like this and it is not part of the static layout?
def generate_table(tdf, max_rows=200):
return dt.DataTable(rows=tdf.to_dict('records'),
columns=tdf.columns,
row_selectable=True,
filterable=False,
sortable=False,
selected_row_indices=[],
id="datatable-gapminder"
)
If I say
#app.callback(
Output('datatable-gapminder', 'selected_row_indices'),
[Input('graph-gapminder', 'clickData')],
[State('datatable-gapminder', 'selected_row_indices')])
def update_selected_row_indices(clickData, selected_row_indices):
if clickData:
for point in clickData['points']:
if point['pointNumber'] in selected_row_indices:
selected_row_indices.remove(point['pointNumber'])
else:
selected_row_indices.append(point['pointNumber'])
return selected_row_indices
I get an error
Attempting to assign a callback to the
component with the id "datatable-gapminder" but no
components with id "datatable-gapminder" exist in the
app's layout.
You are getting that error because the component with id datatable-gapminder is not yet in the layout.
If you want to create callbacks for a component which is not yet in the layout, you have to suppress the callbacks exceptions.
app.config.supress_callback_exceptions = True
I think you will also need a function to serve the layout. By default, Dash apps store the app.layout in memory. If you set app.layout to a function, then you can serve a dynamic layout on every page load. See here.
def serve_layout():
layout = html.Div(
children=[
# dt.DataTable()
],
)
return layout
app.layout = serve_layout
I don't know, if that is currently at all possible with dash. However you might consider creating an empty data table component, and simply updating all it's properties in your call-back (except the id of course :)). If users are not supposed to see the empty data table on startup, you can set it as a hidden div in the beginning, and make sure it becomes visible in the callback.
If you decide to try this approach, make sure you return meaningful values each time the callback for creating the data table is called. Even if these values are empty.