Hi @AnnMarieW thank you for the welcome, itās good to be here and this is a wonderful set of tools
I have been trying to get some of these solutions working, but I am still confused and I suspect itās a conceptual misunderstanding on my part.
Within the layouts (which were written as standalone pages), I call file pre-processing functions to massage the data. After that there are multiple callbacks which rely on the output of those pre-processing function calls. I tried enclosing those function calls and callbacks into the layout function, then putting register_page using path_template with <report_id> in the layout file, and then setting the report_id as a parameter for the layout function. Then, I import the layout file in app.py, and call the layout function with the full path to the valid sub-dirs which contain the datasets as arguments in app.py.
My thinking was that by calling the layout function from app.py it would register the valid pages and then dcc.Link would link to these pages.
Using structure as described above with code like below I am getting this error:
In the callback for output(s):
xyz-results.figure
Output 0 (xyz-results.figure) is already in use.
To resolve this, set allow_duplicate=True
on
duplicate outputs, or combine the outputs into
one callback function, distinguishing the trigger
by using dash.callback_context
if necessary.
I tried setting prevent_initial_callbacks in app and also allow_duplicate=True in the callback.
Additionally, at one point I did have a page come up which had 2 links in it, but both had None for the suffix and produced duplicate callbacks errors even after above allow_duplicates etc. were set.
I donāt know if below code snippets will help (they wonāt run without my including other functions and data), but I hope it will make it more clear how Iāve set things up and where I am might be going wrong.
Just to clarify, when it comes to the āreports/<report_id>ā set in the path_template: is the reports path where my datasets would be, or my pages, something else? Iām not sure exactly what this path is referring to, only that it will end up in the URL.
I will continue working with this as it may be some simple errors here on my end, but just in case I am taking the wrong approach:
APP:
> # I'd like this to be a user selected path at some point, but for now I will just get the path to the
> # root of my current datasets:
base_path = f'{os.getcwd()}\\datasets\\'
app = Dash(__name__,
use_pages=True,
prevent_initial_callbacks="initial_duplicate")
> # Importing my layout function:
import reports.xyz_layout as xyz
> # this function gets all the sub directories of a given dir. Code from this point to 'xyz.layout(dir)' will
> # likely be simplified later, but for now I'm just trying to figure how to call the layout function
> # using the dir with the datasets:
files = pf.get_ds_files(base_path)
dir_contents = []
for sub_dir in files:
dir_contents.append(f'{base_path}{sub_dir}')
for dir in dir_contents:
if 'xyz' in dir.lower():
xyz.layout(dir)
> # My thinking was that above would grab all the applicable 'xyz' directories and register them as
> # pages. Then, dcc.Link below would link to each page in the page_container:
app.layout = html.Div([
html.Div([
html.Div(
dcc.Link(f"{page['name']} - {page['path']}", href=page["relative_path"])
) for page in dash.page_registry.values()
]),
dash.page_container,
])
if __name__ == '__main__':
app.run(debug=True)
LAYOUT:
> # Here's a simplified layout, it only has a couple components but it's enough
> # to get started:
dash.register_page(__name__, path_template="/reports/<report_id>")
def layout(report_id=None, **kwargs):
> # Below gets all files within a directory:
dataset_files = pf.get_ds_files(report_id)
> # --- Data processing execution block --- At the end of this block we have DFs and also some
> # dictionaries which are used in callbacks.
xyz_flist = pf.file_preprocess_flow_manager(dataset_files)
xyz_dfs = pf.process_xyzf_to_df(xyz_flist)
xyz_stats, xyz_stat_df = pf.get_xyz_stats(xyz_dfs)
@callback(
Output(component_id='xyz-results', component_property='figure', allow_duplicate=True),
Input(component_id='xyz-sources', component_property='value')
)
@functools.lru_cache(maxsize=32)
def update_xyz_graph(choice):
color = xyz_stat_df['metric']
n0 = [xyz_stat_df['a/a'], xyz_stat_df['a/b']]
n1 = [xyz_stat_df['b/b'], xyz_stat_df['b/a']]
choices = {'a': n0, 'b': n1}
fig = px.bar(xyz_stat_df, x='n', y=choices[choice], title='XYZ Results', color=color)
fig.update_layout(title_x=0.5)
fig.update_traces(textfont_size=12, textangle=0, textposition="outside", cliponaxis=False)
return fig
return html.Div([
html.Div([
dcc.Graph(
figure={},
id='xyz-results',
style={'width': '95vw', 'height': '50vh'},
),
dcc.RadioItems(
options=['a', 'b'],
value='a',
id='xyz-sources',
inline=True
),
]),
html.Hr(),
])
Thank you for the help, please let me know if I can clarify anything!