AnnMarieW / dash-app-gallery

Dash Examples Index
https://dash-example-index.herokuapp.com/
MIT License
59 stars 24 forks source link

added timeline-gantt.py :) #121

Closed Asaf95 closed 1 year ago

Asaf95 commented 1 year ago

Hi plotly Team,

I want to add this simple app. The app lets users create timeline chart (gantt) using editable DASH DataTable. The csv file that I use if from Plorly Repo Datasets as you asked here. If you think it can help others I will be happy to contribute, if you have any changes you want me to do in the code please tell me :)

Regards, Asaf

AnnMarieW commented 1 year ago

HI @Asaf95

Thanks! I think this will be a great addition to the Example Index. :tada:

To start, can you make it so that you can run timeline-gannt.py as a stand alone app? I tried that and got a bunch of errors.

Asaf95 commented 1 year ago

Hi @AnnMarieW,

Thank you for the feedback! My bad, I had some errors, now it's working :) I'm runining the app using the requirements packages in the repo. if you get any error please tell me what is the erorr and on what environment are you running on.

timeline_gantt

AnnMarieW commented 1 year ago

Thanks for doing the update. Next step is to eliminate any runtime errors.

Currently if you enter an invalid date in Start column or something non-numeric in the Duration column you will get errors. This will be a great demo for the typing feature in the DataTable https://dash.plotly.com/datatable/typing. Try changing the columns to the following:

          columns=[
                {"id": "Task", "name": "Task"},
                {"id": "Start", "name": "Start", "type": "datetime"},
                {"id": "Duration", "name": "Duration in Days", "type": "numeric"},
                {"id": "Resource", "name": "Resource"},
            ],

If you delete all the rows, you will also get an error. What would you like to do in that case? Add a reset button to start over? Have an Add Task button? Here is an example of adding rows: https://dash-example-index.herokuapp.com/order-entry.

Note that the dcc.Store after the app.run_server has no effect and can be deleted. The graph is being updated by the data in DataTable.

Next will be style and cleanup.

Asaf95 commented 1 year ago

thank you for the feedback, I really appreciate it :) I fixed all what you told me (I hope) https://github.com/Asaf95/dash-app-gallery/blob/main/examples/timeline-gantt.py I will try tomrrow to do some formating and style on that app, BTW I getting close to the maximum of 150 lines of code... thank you again @AnnMarieW 🙏

AnnMarieW commented 1 year ago

No worries about the 150 lines - it's a guideline and we're still OK. I :heart: this example. It's so useful! I think there will be a few lines of code we can eliminate, plus comment lines don't really count :-)

The final review can be very picky - so I appreciate your patience as this moves towards the finish line :slightly_smiling_face:

AnnMarieW commented 1 year ago

The add button works nicely :confetti_ball:

I thought it would also be nice to make the table sortable so you can put a new task in a certain order rather than always being at the end. (added sort_action="native") If you would like the figure to update when the table is sorted, then it's necessary to use the derived_virtual_data prop in the callback:

derived_virtual_data (list of dicts; optional): This property represents the visible state of data across all pages after the front-end sorting and filtering as been applied.

When I ran the new version, I noticed that it still has errors if you delete all the rows. In that case, the table data is [] rather than None -- so need to check for that in the callback.

Rather than having two callbacks, - one to update the table data and one to update the figure, it's more efficient to combine them into one callback. (Less code, fewer callbacks triggered, less data going back and forth between the client and server).

Here's an updated callback:

(also changed the name of the new lines to "new_task" rather than "new_order_line")

@app.callback(
    Output("user-datatable", "data"),
    Output("graph", "figure"),
    Input("user-datatable", "derived_virtual_data"),
    Input("add-btn", "n_clicks"),
)
def update_table_and_figure(user_datatable: None or list, n_clicks) -> (list, dict):
    # initialize table when app starts
    if user_datatable is None:
        updated_table = get_default_csv_file()

    # if user deleted all rows, add a default row:
    elif user_datatable == []:
        updated_table = df_new_task

    # convert table data to DataFrame
    else:
        updated_table = pd.DataFrame(user_datatable)

    # add a row
    if ctx.triggered_id == "add-btn":
        updated_table = pd.concat(
            [updated_table, pd.DataFrame.from_records(df_new_task)]
        )

    updated_table = add_finish_column(updated_table)

    fig = plotly.figure_factory.create_gantt(
        updated_table,
        index_col="Resource",
        show_colorbar=True,
        group_tasks=True,
        showgrid_x=False,
        showgrid_y=True,
        bar_width=0.5,
    )

    return updated_table.to_dict("records"), fig
Asaf95 commented 1 year ago

Thank you @AnnMarieW ! I love Code Reviews :) for me it's the best way to improve so don't worry, you won't break me ;) Thanks for the code! it saved me some time for sure.

This branch contain the updated app with the change that you asked, but still I want to test it more, I will ping you here again when I will think its ready. If you have any more requirements / suggestions please tell me. Anyways, I want to add more comments and documentation brfore the PR since it's not count in the 150 lines of code 😆

AnnMarieW commented 1 year ago

don't worry, you won't break me ;)

Haha - don't be so sure :rofl: Actually, I like code reviews too.

Latest update is looking good. I really like how you broke out the table schema as a separate variable. It makes the table definition much easier to read.

Re comments, I prefer to make the code self documenting with clear code and good variable names rather than a lot of comments. But I like to save that for the last pass. No need to fix names or document code that ends up getting cut.

Can delete line 1, then instead of writing pandas.DataFrame it can be pd.DataFrame

import pandas
import pandas as pd

This won't work in production because this is a Pages app, and the title will update automatically, so this line can be deleted:

app.title = 'Time Chart App'

For style, most of the other apps in the Example Index with a DataTable just use CSS. Would you like to make this a Bootstrap app? I see you are already using Bootstrap class names here:

html.H1("Project TimeLine", className="bg-primary text-white p-1", style=APP_TOP_MARGIN),

However to make them work, you need to add a Bootstrap stylesheet:

app = Dash(__name__, external_stylesheets=[dbc.themes.SPACELAB], suppress_callback_exceptions=True)

Then you can delete the APP_TOP_MARGIN variable (which doesn't contain margin anyway) and change the line to:

html.H1("Project TimeLine", className="bg-primary text-white p-1 text-center")

You can find more info here: https://hellodash.pythonanywhere.com/adding-themes/bootstrap-utility-classes

We have a little room to add some more features. What do you think about adding the Finish date to the table? We could make that column "editable": False. (Another good example -- this came up on the forum recently) Plus we could add a light grey background color - typical of disabled features. That would be great since we don't have any conditional formatting examples in Index yet

Asaf95 commented 1 year ago

Most of the Action Items are done :) It's still in a side branch (this branch) To save you time this is a screenshot of the the app (for now). I will improve the style of the app and change some colors there.

Thank you very much! I'm learning a lot from this CR :) ProjectTimeLine

Asaf95 commented 1 year ago

Hi @AnnMarieW, I created a new PR with the updated commits. I thought I can Merge it first to my main Branch and then add the commits to this PR. But guess that or I didn't do it right or it's not woring this way :) Anyways I will close this PR and we can continue the CR at https://github.com/AnnMarieW/dash-app-gallery/pull/122 thanks!

AnnMarieW commented 1 year ago

Ok let me know when #122 is ready for review. No need to close this one yet until #122 is completed.

Asaf95 commented 1 year ago

Hi @AnnMarieW, I think it's ready for review, all Action Items are done.

Project Gantt

Coding-with-Adam commented 1 year ago

Thank you @AnnMarieW for you guidance here. And thank you @Asaf95 for working on this. This will be a very good app for Dash users.

Asaf95 commented 1 year ago

Thanks @Coding-with-Adam !! I heard about the option to contribute to this project from one of your last videos :)

AnnMarieW commented 1 year ago

Closed by merging #122