You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Namespacing component ID support for large or multi-page apps #637
I wanted to use a code example - loaded with tools.load_example- more than once and found I couldn't because of errors regarding the outputs of callbacks already being in use. This issue is to discuss how we should handle having an example be used more than once. We could add a random id to the outputs, or some sort of prefix like page name. Let me know what you think!
@valentijnnieman I moved this over to the dash repo because I feel like we may want a more generic solution for multi-file apps. I'm thinking about something like:
In app1.py, instead of importing app and calling app.callback, do something like:
And then it would be up to you to include section1.layout (which would have its ids modified by the scope as well) wherever you want.
That way you wouldn't need the index.py dance, app.py could be the single top-level entry point, and it pulls in sections and scopes their ids, so each sub-app wouldn't need to know anything about the ids in the others.
Reviving this issue (and taking the liberty to update the title to reflect what I think this is really about).
I've been struggling with managing even medium size multi-page Dash apps due to the restriction of component IDs needing to be unique across the entire app. I've started up a thread around this issue on the community forums and I think the discussion has shown that this is a common issue that people are coming up with workarounds for. It would be great to see Dash add support to its API to solve this problem.
I really like @alexcjohnson's sketch of a proposal. One feature that would be nice to have support for, is Sections being able to be run as standalone apps, for debugging and better code-reusability. That way a single Python file containing a section could be run as a standalone Dash app, or be a page in a multi-page app.
One feature that would be nice to have support for, is Sections being able to be run as standalone apps, for debugging and better code-reusability. That way a single Python file containing a section could be run as a standalone Dash app, or be a page in a multi-page app.
I've just added a variant of this to https://github.com/sjtrny/dash-multipage. It seems like it is a feasible extension to the existing Dash framework without changing any internals. However there might be other reasons where changing the internals would make life easier (like namespacing).
changed the title [-]Namespacing component ID support for multi-page apps [/-][+]Namespacing component ID support for large or multi-page apps [/+]on Aug 1, 2019
It may be helpful to think about this in terms of two distinct use cases:
(1) multiple independent pages
(2) composable sections that may or may not exist together on one page
For (1) a solution like @sjtrny's where each app is registered independently with Flask has a lot of advantages: simple structure, no concerns about id collisions, only load the callbacks needed on that page - making it more likely you can leave callback validation enabled. One thing you might not expect though: I think every page will still load all the component packages used by any page, because of the way we implicitly register them. So if you have big components like cytoscape or dash-bio on any page they'll load in all the pages.
So performance-wise, unless we figure out a better way to manage dependencies, it's still better to use the current recommendation where each page is actually a callback response updating a portion of the layout https://dash.plot.ly/urls - that way you also need to load all the component packages up front, but at least you don't have to reload them every time you change pages. Also this solution allows the pages to share some pieces (like navigation elements and dcc.Store components for common state) But you do need to worry about id collisions, and you can't validate callbacks.
(2) is the use case that inspired this issue - specifically in the context of dash-docs where we have multiple example "apps" on one page and id collisions are hard to avoid. But you can also imagine wanting to use the same section multiple times on one page with slightly different inputs - say you choose a list of graphs to display, with different data but all the same controls for each graph.
So I still think I like the general framework I proposed above for both of these use cases. I think making the containing app responsible for placing each section in a unique scope (note: sections should also be able to sub-scope other sections) is really the only way to manage id collisions, and it may enable us to reinstate callback validation by handling it at the section level - so when you're not displaying a section you get no errors if that section's callbacks refer to nonexistent elements.
Where I left off is thinking about how to connect data / callbacks into, out of, and between sections. Probably need to work through some specific use cases to come up with a good solution there.
Thanks for getting the discussion rolling again @alexcjohnson!
I'm also in favour of your approach sketched above. I see it working well for both scenario 1 and 2 you outlined. As I mentioned above, it would be nice to provide an affordance like @sjtrny included, whereby it's easy to run a section as a standalone app, not as the primary way of registering it scoped in a parent application, but to facilitate testing/code re-use outside of the parent app. Although I guess it's not too hard to create a Dash instance and register the section's layout with it inside a __name__ == '__main__' test.
What sort of thing do you think would be helpful in terms of concrete use-cases to drive this forward? I would be up for putting some examples together.
@ned2 examples would be very helpful - thanks! Most of the potential uses in dash-docs (which is where I personally would first use this feature) are decoupled - the Section wouldn't need any input from elsewhere in the app, nor would it provide any output to be used elsewhere. The API for something like that is easy to design. But I suspect that many if not most of the real-world applications of this will need coupling in one of those two ways, and I'd like to use these use cases to figure out what that should look like.
So for example, a Section for a detailed report in a Tab, after you've already provided input parameters and seen an overview of the output in a different tab? Or the other way, a Section for configuration settings that will be used elsewhere in the app. Or both together, like an "advanced config" tab that needs to use settings from the "basic config" part to tailor the available options, then the complete outputs are used by the rest of the app. Those are some of the scenarios that come to mind, I'd just like to make them concrete enough that we can design an effective API to support them.
making it more likely you can leave callback validation enabled
Hopefully in the future we won't even need to worry about it if someone has time to work on #519
The terminology around "Sections" is a little confusing to me. I consider a section of a website "a group of pages" e.g. the "sports section" of a news website. Whereas some of the discussion seems to indicate that a section is a collection of elements on a single page. Which one is it and if its the later perhaps a different name would be better.
I think it might be helpful to compile a list of requirements which we think Multi-Page support should cover. My list is:
Avoid the index.py and app.py juggle
Page definition is agnostic to whether it is in a multi-page app or single page app
A dash app can use a single or multiple pages
Pages can be nested or grouped (my definition of sections)
Simple routing system
No (or little) performance reduction
I'm sure I've forgotten some but I think those are a good starting point, which would be widely used by the community.
I like the idea of "sections" proposed by @alexcjohnson . Not much because of the id namespace problem (which I avoided prefixing every id with its page name), but because of a need I have right now in the app I'm developing: I want to load the callbacks of a page only when that page is actually visited and not before, and right now the only way for me to do it would be nesting all callbacks inside a function and call it on page visit, which is quite un-elegant.
I had a similar need but not for multi-page apps but for reusable components (layout+callbacks).
You can see the API use on https://github.com/sdementen/dash-extensions/tree/composed-components#composed-components.
There is a fair bit of id mangling to 1) avoid id clashing and 2) support pattern matching at all level (for callbacks outside the ComposedComponent and for callbacks registered inside the ComposedComponent).
A related issue is #1465 to allow to make this type of package available as a potential Dash extension.
@sdementen : I checked composed-components and it looks pretty cool; well documented code.
I would like to use it, but wonder: how stable is the code at this point?, especially since it's still a branch of its base repo. How would you recommend to install it? -- I didn't find this in pypi just yet. Copy source and local install, perhaps? Thanks in advance.
Activity
alexcjohnson commentedon Mar 8, 2019
@valentijnnieman I moved this over to the dash repo because I feel like we may want a more generic solution for multi-file apps. I'm thinking about something like:
In
app1.py, instead of importingappand callingapp.callback, do something like:And then the main
app.pyfile:And then it would be up to you to include
section1.layout(which would have its ids modified by the scope as well) wherever you want.That way you wouldn't need the
index.pydance,app.pycould be the single top-level entry point, and it pulls in sections and scopes their ids, so each sub-app wouldn't need to know anything about the ids in the others.[-]Using code examples more than once[/-][+]Namespacing component ID support for multi-page apps [/+]ned2 commentedon Apr 21, 2019
Reviving this issue (and taking the liberty to update the title to reflect what I think this is really about).
I've been struggling with managing even medium size multi-page Dash apps due to the restriction of component IDs needing to be unique across the entire app. I've started up a thread around this issue on the community forums and I think the discussion has shown that this is a common issue that people are coming up with workarounds for. It would be great to see Dash add support to its API to solve this problem.
I really like @alexcjohnson's sketch of a proposal. One feature that would be nice to have support for, is Sections being able to be run as standalone apps, for debugging and better code-reusability. That way a single Python file containing a section could be run as a standalone Dash app, or be a page in a multi-page app.
sjtrny commentedon Apr 21, 2019
I've just added a variant of this to https://github.com/sjtrny/dash-multipage. It seems like it is a feasible extension to the existing Dash framework without changing any internals. However there might be other reasons where changing the internals would make life easier (like namespacing).
From https://github.com/sjtrny/dash-multipage/blob/master/standalone.py
[-]Namespacing component ID support for multi-page apps [/-][+]Namespacing component ID support for large or multi-page apps [/+]alexcjohnson commentedon Aug 1, 2019
It may be helpful to think about this in terms of two distinct use cases:
(1) multiple independent pages
(2) composable sections that may or may not exist together on one page
For (1) a solution like @sjtrny's where each app is registered independently with Flask has a lot of advantages: simple structure, no concerns about id collisions, only load the callbacks needed on that page - making it more likely you can leave callback validation enabled. One thing you might not expect though: I think every page will still load all the component packages used by any page, because of the way we implicitly register them. So if you have big components like cytoscape or dash-bio on any page they'll load in all the pages.
So performance-wise, unless we figure out a better way to manage dependencies, it's still better to use the current recommendation where each page is actually a callback response updating a portion of the layout https://dash.plot.ly/urls - that way you also need to load all the component packages up front, but at least you don't have to reload them every time you change pages. Also this solution allows the pages to share some pieces (like navigation elements and
dcc.Storecomponents for common state) But you do need to worry about id collisions, and you can't validate callbacks.(2) is the use case that inspired this issue - specifically in the context of dash-docs where we have multiple example "apps" on one page and id collisions are hard to avoid. But you can also imagine wanting to use the same section multiple times on one page with slightly different inputs - say you choose a list of graphs to display, with different data but all the same controls for each graph.
So I still think I like the general framework I proposed above for both of these use cases. I think making the containing app responsible for placing each section in a unique scope (note: sections should also be able to sub-scope other sections) is really the only way to manage id collisions, and it may enable us to reinstate callback validation by handling it at the section level - so when you're not displaying a section you get no errors if that section's callbacks refer to nonexistent elements.
Where I left off is thinking about how to connect data / callbacks into, out of, and between sections. Probably need to work through some specific use cases to come up with a good solution there.
ned2 commentedon Aug 11, 2019
Thanks for getting the discussion rolling again @alexcjohnson!
I'm also in favour of your approach sketched above. I see it working well for both scenario 1 and 2 you outlined. As I mentioned above, it would be nice to provide an affordance like @sjtrny included, whereby it's easy to run a section as a standalone app, not as the primary way of registering it scoped in a parent application, but to facilitate testing/code re-use outside of the parent app. Although I guess it's not too hard to create a
Dashinstance and register the section's layout with it inside a__name__ == '__main__'test.What sort of thing do you think would be helpful in terms of concrete use-cases to drive this forward? I would be up for putting some examples together.
alexcjohnson commentedon Aug 11, 2019
@ned2 examples would be very helpful - thanks! Most of the potential uses in dash-docs (which is where I personally would first use this feature) are decoupled - the
Sectionwouldn't need any input from elsewhere in the app, nor would it provide any output to be used elsewhere. The API for something like that is easy to design. But I suspect that many if not most of the real-world applications of this will need coupling in one of those two ways, and I'd like to use these use cases to figure out what that should look like.So for example, a
Sectionfor a detailed report in aTab, after you've already provided input parameters and seen an overview of the output in a different tab? Or the other way, aSectionfor configuration settings that will be used elsewhere in the app. Or both together, like an "advanced config" tab that needs to use settings from the "basic config" part to tailor the available options, then the complete outputs are used by the rest of the app. Those are some of the scenarios that come to mind, I'd just like to make them concrete enough that we can design an effective API to support them.sjtrny commentedon Aug 19, 2019
Hopefully in the future we won't even need to worry about it if someone has time to work on #519
The terminology around "Sections" is a little confusing to me. I consider a section of a website "a group of pages" e.g. the "sports section" of a news website. Whereas some of the discussion seems to indicate that a section is a collection of elements on a single page. Which one is it and if its the later perhaps a different name would be better.
I think it might be helpful to compile a list of requirements which we think Multi-Page support should cover. My list is:
I'm sure I've forgotten some but I think those are a good starting point, which would be widely used by the community.
wtfzambo commentedon Sep 19, 2019
I like the idea of "sections" proposed by @alexcjohnson . Not much because of the id namespace problem (which I avoided prefixing every id with its page name), but because of a need I have right now in the app I'm developing: I want to load the callbacks of a page only when that page is actually visited and not before, and right now the only way for me to do it would be nesting all callbacks inside a function and call it on page visit, which is quite un-elegant.
More details here about my use case: dash forum post
sjtrny commentedon Sep 25, 2019
Just want to note that there are many people coming up with their own solution to this problem, e.g.
https://community.plot.ly/t/show-and-tell-dash-single-page-application-spa-framework/29151
and
https://community.plot.ly/t/show-and-tell-full-authentication-flow-example-dash-auth-flow/27415
including adding support for authentication. Clearly there is a large amount of interest in this area.
chriddyp commentedon Jun 22, 2020
Another approach and discussion in the community forum about encapsulating components: https://dash-building-blocks.readthedocs.io/en/latest/overview.html & https://community.plotly.com/t/object-oriented-dash-components/10809/4
sdementen commentedon Nov 25, 2020
I had a similar need but not for multi-page apps but for reusable components (layout+callbacks).
You can see the API use on https://github.com/sdementen/dash-extensions/tree/composed-components#composed-components.
There is a fair bit of id mangling to 1) avoid id clashing and 2) support pattern matching at all level (for callbacks outside the
ComposedComponentand for callbacks registered inside theComposedComponent).A related issue is #1465 to allow to make this type of package available as a potential Dash extension.
IE11 compatibility (plotly#637)
calang commentedon Jul 1, 2021
@sdementen : I checked composed-components and it looks pretty cool; well documented code.
I would like to use it, but wonder: how stable is the code at this point?, especially since it's still a branch of its base repo. How would you recommend to install it? -- I didn't find this in pypi just yet. Copy source and local install, perhaps? Thanks in advance.
sdementen commentedon Jul 1, 2021
@calang I just read https://community.plotly.com/t/modular-reusable-python-components-with-attached-callbacks/53998 and I think it would be a safer bet than using my branch
calang commentedon Jul 1, 2021
IE11 compatibility (#637)