Iotatron
Iotatron

Reputation: 73

Add hyperlinks to Gantt bars in plotly express?

I'm using a Gantt chart to show recording data from a large number of sensors in a distributed network over the course of a few years. (Some of the nodes in the network turn on or off intermittently, so this is an effective way to show the whole dataset at a glance.) I use plotly express to generate the Gantt chart from a list of filenames, so each Gantt bar corresponds to a .PNG file of a graph for a given day, and I can easily export the result as an interactive .html document.

I'd like to add a clickable link for each of the bars on the Gantt chart, so that clicking on a given bar will open the plot for the relevant day. This would make it much easier to explore the data. I can generate the links but am having trouble making it possible to open them from within the Gantt chart.

Here's my first pass at a MWE:

# WIP: Can I set up the Gantt chart so that clicking on an entry takes you to that graph?
import plotly.express as px
import pandas as pd

string1 = "<a href=https://www.nytimes.com/> link </a>"

df = pd.DataFrame([
    dict(Task="Job A", Start='2009-01-01', Finish='2009-02-28', Filename = string1), 
    dict(Task="Job B", Start='2009-03-05', Finish='2009-04-15', Filename = string1),
    dict(Task="Job C", Start='2009-02-20', Finish='2009-05-30', Filename = string1)
])

fig = px.timeline(df, x_start="Start", x_end="Finish", y="Task", text="Filename") # textposition argument not possible
fig.update_traces(textposition='outside')
fig.show()
fig.write_html("test_gantt.html", include_plotlyjs="cdn")

The output looks like this: Gantt chart with 3 notional bars, each with a blue "link" to the right. Output of the code snippet above.

The problems I'm running into with this are (a) for reasons I haven't been able to figure out, the link isn't clickable; (b) I can't click on the link in the alt text because it disappears as soon as I move my mouse; and (c) the bars on the Gantt chart I'm creating will be much smaller than these, so to be effective the link should really be associated with clicking on the bar itself.

Any tips are much appreciated.

Edit: Here is an example of what a finished Gantt chart looks like:

Gantt chart with many more small bars.

I would like to embed a link for each day's worth of data; as you can see, the bars are very small.

Upvotes: 2

Views: 895

Answers (1)

r-beginners
r-beginners

Reputation: 35155

Hyperlinks are added using the annotation function. One requirement added in the comments was that there are so many tasks on the timeline that the links are hidden and a workaround is needed. If the hyperlink string is too long, it will be covered by the task, so we changed it to 'o'. We also calculated the date that would be the center of the period in order to center it from the start and end dates. Because of the rounding down, it is not centered on all tasks. The same is true for rounding up. Also, the hyperlink color is blue by default, so you need to use a color scheme that does not include dark blue.

import plotly.express as px
import pandas as pd
import math

string1 = f"""<a href="https://www.nytimes.com/", target="_black">o</a>"""

df = pd.DataFrame([
    dict(Task="Job A", Start='2009-01-01', Finish='2009-01-04', Filename=string1),
    dict(Task="Job A", Start='2009-01-06', Finish='2009-01-09', Filename=string1),
    dict(Task="Job A", Start='2009-01-10', Finish='2009-01-15', Filename=string1),
    dict(Task="Job A", Start='2009-01-16', Finish='2009-01-19', Filename=string1),
    dict(Task="Job A", Start='2009-01-21', Finish='2009-01-25', Filename=string1),
    dict(Task="Job A", Start='2009-01-28', Finish='2009-01-31', Filename=string1),
    dict(Task="Job A", Start='2009-02-01', Finish='2009-02-08', Filename=string1),
    dict(Task="Job A", Start='2009-02-11', Finish='2009-02-15', Filename=string1),
    dict(Task="Job A", Start='2009-02-17', Finish='2009-02-20', Filename=string1),
    dict(Task="Job A", Start='2009-02-22', Finish='2009-02-24', Filename=string1),
    dict(Task="Job A", Start='2009-02-25', Finish='2009-02-28', Filename=string1),
    dict(Task="Job B", Start='2009-03-05', Finish='2009-03-15', Filename=string1),
    dict(Task="Job C", Start='2009-02-20', Finish='2009-04-30', Filename=string1)
])

fig = px.timeline(df, 
                  x_start="Start",
                  x_end="Finish",
                  y="Task",
                  color="Task",
                  color_discrete_sequence=px.colors.qualitative.Pastel)

for idx, row in df.iterrows():
    periods = pd.date_range(row["Start"],row["Finish"], freq='1D')
    center_pos = math.floor(len(periods) / 2)
    x_dates = periods[center_pos]
    fig.add_annotation(
        {
            "x": x_dates,#row["Finish"],
            "y": row["Task"],
            "text": row["Filename"],
            "align": "center",
            "showarrow":False,
        }
    )

fig.show()
fig.write_html("test_gantt.html", include_plotlyjs="cdn")

enter image description here

Upvotes: 5

Related Questions