from __future__ import absolute_import from numbers import Number import copy from plotly import exceptions, optional_imports import plotly.colors as clrs from plotly.figure_factory import utils import plotly.graph_objects as go pd = optional_imports.get_module("pandas") REQUIRED_GANTT_KEYS = ["Task", "Start", "Finish"] def _get_corner_points(x0, y0, x1, y1): """ Returns the corner points of a scatter rectangle :param x0: x-start :param y0: y-lower :param x1: x-end :param y1: y-upper :return: ([x], [y]), tuple of lists containing the x and y values """ return ([x0, x1, x1, x0], [y0, y0, y1, y1]) def validate_gantt(df): """ Validates the inputted dataframe or list """ if pd and isinstance(df, pd.core.frame.DataFrame): # validate that df has all the required keys for key in REQUIRED_GANTT_KEYS: if key not in df: raise exceptions.PlotlyError( "The columns in your dataframe must include the " "following keys: {0}".format(", ".join(REQUIRED_GANTT_KEYS)) ) num_of_rows = len(df.index) chart = [] for index in range(num_of_rows): task_dict = {} for key in df: task_dict[key] = df.iloc[index][key] chart.append(task_dict) return chart # validate if df is a list if not isinstance(df, list): raise exceptions.PlotlyError( "You must input either a dataframe " "or a list of dictionaries." ) # validate if df is empty if len(df) <= 0: raise exceptions.PlotlyError( "Your list is empty. It must contain " "at least one dictionary." ) if not isinstance(df[0], dict): raise exceptions.PlotlyError("Your list must only " "include dictionaries.") return df def gantt( chart, colors, title, bar_width, showgrid_x, showgrid_y, height, width, tasks=None, task_names=None, data=None, group_tasks=False, show_hover_fill=True, show_colorbar=True, ): """ Refer to create_gantt() for docstring """ if tasks is None: tasks = [] if task_names is None: task_names = [] if data is None: data = [] for index in range(len(chart)): task = dict( x0=chart[index]["Start"], x1=chart[index]["Finish"], name=chart[index]["Task"], ) if "Description" in chart[index]: task["description"] = chart[index]["Description"] tasks.append(task) # create a scatter trace for every task group scatter_data_dict = dict() marker_data_dict = dict() if show_hover_fill: hoverinfo = "name" else: hoverinfo = "skip" scatter_data_template = { "x": [], "y": [], "mode": "none", "fill": "toself", "hoverinfo": hoverinfo, } marker_data_template = { "x": [], "y": [], "mode": "markers", "text": [], "marker": dict(color="", size=1, opacity=0), "name": "", "showlegend": False, } # create the list of task names for index in range(len(tasks)): tn = tasks[index]["name"] # Is added to task_names if group_tasks is set to False, # or if the option is used (True) it only adds them if the # name is not already in the list if not group_tasks or tn not in task_names: task_names.append(tn) # Guarantees that for grouped tasks the tasks that are inserted first # are shown at the top if group_tasks: task_names.reverse() color_index = 0 for index in range(len(tasks)): tn = tasks[index]["name"] del tasks[index]["name"] # If group_tasks is True, all tasks with the same name belong # to the same row. groupID = index if group_tasks: groupID = task_names.index(tn) tasks[index]["y0"] = groupID - bar_width tasks[index]["y1"] = groupID + bar_width # check if colors need to be looped if color_index >= len(colors): color_index = 0 tasks[index]["fillcolor"] = colors[color_index] color_id = tasks[index]["fillcolor"] if color_id not in scatter_data_dict: scatter_data_dict[color_id] = copy.deepcopy(scatter_data_template) scatter_data_dict[color_id]["fillcolor"] = color_id scatter_data_dict[color_id]["name"] = str(tn) scatter_data_dict[color_id]["legendgroup"] = color_id # if there are already values append the gap if len(scatter_data_dict[color_id]["x"]) > 0: # a gap on the scatterplot separates the rectangles from each other scatter_data_dict[color_id]["x"].append( scatter_data_dict[color_id]["x"][-1] ) scatter_data_dict[color_id]["y"].append(None) xs, ys = _get_corner_points( tasks[index]["x0"], tasks[index]["y0"], tasks[index]["x1"], tasks[index]["y1"], ) scatter_data_dict[color_id]["x"] += xs scatter_data_dict[color_id]["y"] += ys # append dummy markers for showing start and end of interval if color_id not in marker_data_dict: marker_data_dict[color_id] = copy.deepcopy(marker_data_template) marker_data_dict[color_id]["marker"]["color"] = color_id marker_data_dict[color_id]["legendgroup"] = color_id marker_data_dict[color_id]["x"].append(tasks[index]["x0"]) marker_data_dict[color_id]["x"].append(tasks[index]["x1"]) marker_data_dict[color_id]["y"].append(groupID) marker_data_dict[color_id]["y"].append(groupID) if "description" in tasks[index]: marker_data_dict[color_id]["text"].append(tasks[index]["description"]) marker_data_dict[color_id]["text"].append(tasks[index]["description"]) del tasks[index]["description"] else: marker_data_dict[color_id]["text"].append(None) marker_data_dict[color_id]["text"].append(None) color_index += 1 showlegend = show_colorbar layout = dict( title=title, showlegend=showlegend, height=height, width=width, shapes=[], hovermode="closest", yaxis=dict( showgrid=showgrid_y, ticktext=task_names, tickvals=list(range(len(task_names))), range=[-1, len(task_names) + 1], autorange=False, zeroline=False, ), xaxis=dict( showgrid=showgrid_x, zeroline=False, rangeselector=dict( buttons=list( [ dict(count=7, label="1w", step="day", stepmode="backward"), dict(count=1, label="1m", step="month", stepmode="backward"), dict(count=6, label="6m", step="month", stepmode="backward"), dict(count=1, label="YTD", step="year", stepmode="todate"), dict(count=1, label="1y", step="year", stepmode="backward"), dict(step="all"), ] ) ), type="date", ), ) data = [scatter_data_dict[k] for k in sorted(scatter_data_dict)] data += [marker_data_dict[k] for k in sorted(marker_data_dict)] # fig = dict( # data=data, layout=layout # ) fig = go.Figure(data=data, layout=layout) return fig def gantt_colorscale( chart, colors, title, index_col, show_colorbar, bar_width, showgrid_x, showgrid_y, height, width, tasks=None, task_names=None, data=None, group_tasks=False, show_hover_fill=True, ): """ Refer to FigureFactory.create_gantt() for docstring """ if tasks is None: tasks = [] if task_names is None: task_names = [] if data is None: data = [] showlegend = False for index in range(len(chart)): task = dict( x0=chart[index]["Start"], x1=chart[index]["Finish"], name=chart[index]["Task"], ) if "Description" in chart[index]: task["description"] = chart[index]["Description"] tasks.append(task) # create a scatter trace for every task group scatter_data_dict = dict() # create scatter traces for the start- and endpoints marker_data_dict = dict() if show_hover_fill: hoverinfo = "name" else: hoverinfo = "skip" scatter_data_template = { "x": [], "y": [], "mode": "none", "fill": "toself", "showlegend": False, "hoverinfo": hoverinfo, "legendgroup": "", } marker_data_template = { "x": [], "y": [], "mode": "markers", "text": [], "marker": dict(color="", size=1, opacity=0), "name": "", "showlegend": False, "legendgroup": "", } index_vals = [] for row in range(len(tasks)): if chart[row][index_col] not in index_vals: index_vals.append(chart[row][index_col]) index_vals.sort() # compute the color for task based on indexing column if isinstance(chart[0][index_col], Number): # check that colors has at least 2 colors if len(colors) < 2: raise exceptions.PlotlyError( "You must use at least 2 colors in 'colors' if you " "are using a colorscale. However only the first two " "colors given will be used for the lower and upper " "bounds on the colormap." ) # create the list of task names for index in range(len(tasks)): tn = tasks[index]["name"] # Is added to task_names if group_tasks is set to False, # or if the option is used (True) it only adds them if the # name is not already in the list if not group_tasks or tn not in task_names: task_names.append(tn) # Guarantees that for grouped tasks the tasks that are inserted # first are shown at the top if group_tasks: task_names.reverse() for index in range(len(tasks)): tn = tasks[index]["name"] del tasks[index]["name"] # If group_tasks is True, all tasks with the same name belong # to the same row. groupID = index if group_tasks: groupID = task_names.index(tn) tasks[index]["y0"] = groupID - bar_width tasks[index]["y1"] = groupID + bar_width # unlabel color colors = clrs.color_parser(colors, clrs.unlabel_rgb) lowcolor = colors[0] highcolor = colors[1] intermed = (chart[index][index_col]) / 100.0 intermed_color = clrs.find_intermediate_color(lowcolor, highcolor, intermed) intermed_color = clrs.color_parser(intermed_color, clrs.label_rgb) tasks[index]["fillcolor"] = intermed_color color_id = tasks[index]["fillcolor"] if color_id not in scatter_data_dict: scatter_data_dict[color_id] = copy.deepcopy(scatter_data_template) scatter_data_dict[color_id]["fillcolor"] = color_id scatter_data_dict[color_id]["name"] = str(chart[index][index_col]) scatter_data_dict[color_id]["legendgroup"] = color_id # relabel colors with 'rgb' colors = clrs.color_parser(colors, clrs.label_rgb) # if there are already values append the gap if len(scatter_data_dict[color_id]["x"]) > 0: # a gap on the scatterplot separates the rectangles from each other scatter_data_dict[color_id]["x"].append( scatter_data_dict[color_id]["x"][-1] ) scatter_data_dict[color_id]["y"].append(None) xs, ys = _get_corner_points( tasks[index]["x0"], tasks[index]["y0"], tasks[index]["x1"], tasks[index]["y1"], ) scatter_data_dict[color_id]["x"] += xs scatter_data_dict[color_id]["y"] += ys # append dummy markers for showing start and end of interval if color_id not in marker_data_dict: marker_data_dict[color_id] = copy.deepcopy(marker_data_template) marker_data_dict[color_id]["marker"]["color"] = color_id marker_data_dict[color_id]["legendgroup"] = color_id marker_data_dict[color_id]["x"].append(tasks[index]["x0"]) marker_data_dict[color_id]["x"].append(tasks[index]["x1"]) marker_data_dict[color_id]["y"].append(groupID) marker_data_dict[color_id]["y"].append(groupID) if "description" in tasks[index]: marker_data_dict[color_id]["text"].append(tasks[index]["description"]) marker_data_dict[color_id]["text"].append(tasks[index]["description"]) del tasks[index]["description"] else: marker_data_dict[color_id]["text"].append(None) marker_data_dict[color_id]["text"].append(None) # add colorbar to one of the traces randomly just for display if show_colorbar is True: k = list(marker_data_dict.keys())[0] marker_data_dict[k]["marker"].update( dict( colorscale=[[0, colors[0]], [1, colors[1]]], showscale=True, cmax=100, cmin=0, ) ) if isinstance(chart[0][index_col], str): index_vals = [] for row in range(len(tasks)): if chart[row][index_col] not in index_vals: index_vals.append(chart[row][index_col]) index_vals.sort() if len(colors) < len(index_vals): raise exceptions.PlotlyError( "Error. The number of colors in 'colors' must be no less " "than the number of unique index values in your group " "column." ) # make a dictionary assignment to each index value index_vals_dict = {} # define color index c_index = 0 for key in index_vals: if c_index > len(colors) - 1: c_index = 0 index_vals_dict[key] = colors[c_index] c_index += 1 # create the list of task names for index in range(len(tasks)): tn = tasks[index]["name"] # Is added to task_names if group_tasks is set to False, # or if the option is used (True) it only adds them if the # name is not already in the list if not group_tasks or tn not in task_names: task_names.append(tn) # Guarantees that for grouped tasks the tasks that are inserted # first are shown at the top if group_tasks: task_names.reverse() for index in range(len(tasks)): tn = tasks[index]["name"] del tasks[index]["name"] # If group_tasks is True, all tasks with the same name belong # to the same row. groupID = index if group_tasks: groupID = task_names.index(tn) tasks[index]["y0"] = groupID - bar_width tasks[index]["y1"] = groupID + bar_width tasks[index]["fillcolor"] = index_vals_dict[chart[index][index_col]] color_id = tasks[index]["fillcolor"] if color_id not in scatter_data_dict: scatter_data_dict[color_id] = copy.deepcopy(scatter_data_template) scatter_data_dict[color_id]["fillcolor"] = color_id scatter_data_dict[color_id]["legendgroup"] = color_id scatter_data_dict[color_id]["name"] = str(chart[index][index_col]) # relabel colors with 'rgb' colors = clrs.color_parser(colors, clrs.label_rgb) # if there are already values append the gap if len(scatter_data_dict[color_id]["x"]) > 0: # a gap on the scatterplot separates the rectangles from each other scatter_data_dict[color_id]["x"].append( scatter_data_dict[color_id]["x"][-1] ) scatter_data_dict[color_id]["y"].append(None) xs, ys = _get_corner_points( tasks[index]["x0"], tasks[index]["y0"], tasks[index]["x1"], tasks[index]["y1"], ) scatter_data_dict[color_id]["x"] += xs scatter_data_dict[color_id]["y"] += ys # append dummy markers for showing start and end of interval if color_id not in marker_data_dict: marker_data_dict[color_id] = copy.deepcopy(marker_data_template) marker_data_dict[color_id]["marker"]["color"] = color_id marker_data_dict[color_id]["legendgroup"] = color_id marker_data_dict[color_id]["x"].append(tasks[index]["x0"]) marker_data_dict[color_id]["x"].append(tasks[index]["x1"]) marker_data_dict[color_id]["y"].append(groupID) marker_data_dict[color_id]["y"].append(groupID) if "description" in tasks[index]: marker_data_dict[color_id]["text"].append(tasks[index]["description"]) marker_data_dict[color_id]["text"].append(tasks[index]["description"]) del tasks[index]["description"] else: marker_data_dict[color_id]["text"].append(None) marker_data_dict[color_id]["text"].append(None) if show_colorbar is True: showlegend = True for k in scatter_data_dict: scatter_data_dict[k]["showlegend"] = showlegend # add colorbar to one of the traces randomly just for display # if show_colorbar is True: # k = list(marker_data_dict.keys())[0] # marker_data_dict[k]["marker"].update( # dict( # colorscale=[[0, colors[0]], [1, colors[1]]], # showscale=True, # cmax=100, # cmin=0, # ) # ) layout = dict( title=title, showlegend=showlegend, height=height, width=width, shapes=[], hovermode="closest", yaxis=dict( showgrid=showgrid_y, ticktext=task_names, tickvals=list(range(len(task_names))), range=[-1, len(task_names) + 1], autorange=False, zeroline=False, ), xaxis=dict( showgrid=showgrid_x, zeroline=False, rangeselector=dict( buttons=list( [ dict(count=7, label="1w", step="day", stepmode="backward"), dict(count=1, label="1m", step="month", stepmode="backward"), dict(count=6, label="6m", step="month", stepmode="backward"), dict(count=1, label="YTD", step="year", stepmode="todate"), dict(count=1, label="1y", step="year", stepmode="backward"), dict(step="all"), ] ) ), type="date", ), ) data = [scatter_data_dict[k] for k in sorted(scatter_data_dict)] data += [marker_data_dict[k] for k in sorted(marker_data_dict)] # fig = dict( # data=data, layout=layout # ) fig = go.Figure(data=data, layout=layout) return fig def gantt_dict( chart, colors, title, index_col, show_colorbar, bar_width, showgrid_x, showgrid_y, height, width, tasks=None, task_names=None, data=None, group_tasks=False, show_hover_fill=True, ): """ Refer to FigureFactory.create_gantt() for docstring """ if tasks is None: tasks = [] if task_names is None: task_names = [] if data is None: data = [] showlegend = False for index in range(len(chart)): task = dict( x0=chart[index]["Start"], x1=chart[index]["Finish"], name=chart[index]["Task"], ) if "Description" in chart[index]: task["description"] = chart[index]["Description"] tasks.append(task) # create a scatter trace for every task group scatter_data_dict = dict() # create scatter traces for the start- and endpoints marker_data_dict = dict() if show_hover_fill: hoverinfo = "name" else: hoverinfo = "skip" scatter_data_template = { "x": [], "y": [], "mode": "none", "fill": "toself", "hoverinfo": hoverinfo, "legendgroup": "", } marker_data_template = { "x": [], "y": [], "mode": "markers", "text": [], "marker": dict(color="", size=1, opacity=0), "name": "", "showlegend": False, } index_vals = [] for row in range(len(tasks)): if chart[row][index_col] not in index_vals: index_vals.append(chart[row][index_col]) index_vals.sort() # verify each value in index column appears in colors dictionary for key in index_vals: if key not in colors: raise exceptions.PlotlyError( "If you are using colors as a dictionary, all of its " "keys must be all the values in the index column." ) # create the list of task names for index in range(len(tasks)): tn = tasks[index]["name"] # Is added to task_names if group_tasks is set to False, # or if the option is used (True) it only adds them if the # name is not already in the list if not group_tasks or tn not in task_names: task_names.append(tn) # Guarantees that for grouped tasks the tasks that are inserted first # are shown at the top if group_tasks: task_names.reverse() for index in range(len(tasks)): tn = tasks[index]["name"] del tasks[index]["name"] # If group_tasks is True, all tasks with the same name belong # to the same row. groupID = index if group_tasks: groupID = task_names.index(tn) tasks[index]["y0"] = groupID - bar_width tasks[index]["y1"] = groupID + bar_width tasks[index]["fillcolor"] = colors[chart[index][index_col]] color_id = tasks[index]["fillcolor"] if color_id not in scatter_data_dict: scatter_data_dict[color_id] = copy.deepcopy(scatter_data_template) scatter_data_dict[color_id]["legendgroup"] = color_id scatter_data_dict[color_id]["fillcolor"] = color_id # if there are already values append the gap if len(scatter_data_dict[color_id]["x"]) > 0: # a gap on the scatterplot separates the rectangles from each other scatter_data_dict[color_id]["x"].append( scatter_data_dict[color_id]["x"][-1] ) scatter_data_dict[color_id]["y"].append(None) xs, ys = _get_corner_points( tasks[index]["x0"], tasks[index]["y0"], tasks[index]["x1"], tasks[index]["y1"], ) scatter_data_dict[color_id]["x"] += xs scatter_data_dict[color_id]["y"] += ys # append dummy markers for showing start and end of interval if color_id not in marker_data_dict: marker_data_dict[color_id] = copy.deepcopy(marker_data_template) marker_data_dict[color_id]["marker"]["color"] = color_id marker_data_dict[color_id]["legendgroup"] = color_id marker_data_dict[color_id]["x"].append(tasks[index]["x0"]) marker_data_dict[color_id]["x"].append(tasks[index]["x1"]) marker_data_dict[color_id]["y"].append(groupID) marker_data_dict[color_id]["y"].append(groupID) if "description" in tasks[index]: marker_data_dict[color_id]["text"].append(tasks[index]["description"]) marker_data_dict[color_id]["text"].append(tasks[index]["description"]) del tasks[index]["description"] else: marker_data_dict[color_id]["text"].append(None) marker_data_dict[color_id]["text"].append(None) if show_colorbar is True: showlegend = True for index_value in index_vals: scatter_data_dict[colors[index_value]]["name"] = str(index_value) layout = dict( title=title, showlegend=showlegend, height=height, width=width, shapes=[], hovermode="closest", yaxis=dict( showgrid=showgrid_y, ticktext=task_names, tickvals=list(range(len(task_names))), range=[-1, len(task_names) + 1], autorange=False, zeroline=False, ), xaxis=dict( showgrid=showgrid_x, zeroline=False, rangeselector=dict( buttons=list( [ dict(count=7, label="1w", step="day", stepmode="backward"), dict(count=1, label="1m", step="month", stepmode="backward"), dict(count=6, label="6m", step="month", stepmode="backward"), dict(count=1, label="YTD", step="year", stepmode="todate"), dict(count=1, label="1y", step="year", stepmode="backward"), dict(step="all"), ] ) ), type="date", ), ) data = [scatter_data_dict[k] for k in sorted(scatter_data_dict)] data += [marker_data_dict[k] for k in sorted(marker_data_dict)] # fig = dict( # data=data, layout=layout # ) fig = go.Figure(data=data, layout=layout) return fig def create_gantt( df, colors=None, index_col=None, show_colorbar=False, reverse_colors=False, title="Gantt Chart", bar_width=0.2, showgrid_x=False, showgrid_y=False, height=600, width=None, tasks=None, task_names=None, data=None, group_tasks=False, show_hover_fill=True, ): """ Returns figure for a gantt chart :param (array|list) df: input data for gantt chart. Must be either a a dataframe or a list. If dataframe, the columns must include 'Task', 'Start' and 'Finish'. Other columns can be included and used for indexing. If a list, its elements must be dictionaries with the same required column headers: 'Task', 'Start' and 'Finish'. :param (str|list|dict|tuple) colors: either a plotly scale name, an rgb or hex color, a color tuple or a list of colors. An rgb color is of the form 'rgb(x, y, z)' where x, y, z belong to the interval [0, 255] and a color tuple is a tuple of the form (a, b, c) where a, b and c belong to [0, 1]. If colors is a list, it must contain the valid color types aforementioned as its members. If a dictionary, all values of the indexing column must be keys in colors. :param (str|float) index_col: the column header (if df is a data frame) that will function as the indexing column. If df is a list, index_col must be one of the keys in all the items of df. :param (bool) show_colorbar: determines if colorbar will be visible. Only applies if values in the index column are numeric. :param (bool) show_hover_fill: enables/disables the hovertext for the filled area of the chart. :param (bool) reverse_colors: reverses the order of selected colors :param (str) title: the title of the chart :param (float) bar_width: the width of the horizontal bars in the plot :param (bool) showgrid_x: show/hide the x-axis grid :param (bool) showgrid_y: show/hide the y-axis grid :param (float) height: the height of the chart :param (float) width: the width of the chart Example 1: Simple Gantt Chart >>> from plotly.figure_factory import create_gantt >>> # Make data for chart >>> df = [dict(Task="Job A", Start='2009-01-01', Finish='2009-02-30'), ... dict(Task="Job B", Start='2009-03-05', Finish='2009-04-15'), ... dict(Task="Job C", Start='2009-02-20', Finish='2009-05-30')] >>> # Create a figure >>> fig = create_gantt(df) >>> fig.show() Example 2: Index by Column with Numerical Entries >>> from plotly.figure_factory import create_gantt >>> # Make data for chart >>> df = [dict(Task="Job A", Start='2009-01-01', ... Finish='2009-02-30', Complete=10), ... dict(Task="Job B", Start='2009-03-05', ... Finish='2009-04-15', Complete=60), ... dict(Task="Job C", Start='2009-02-20', ... Finish='2009-05-30', Complete=95)] >>> # Create a figure with Plotly colorscale >>> fig = create_gantt(df, colors='Blues', index_col='Complete', ... show_colorbar=True, bar_width=0.5, ... showgrid_x=True, showgrid_y=True) >>> fig.show() Example 3: Index by Column with String Entries >>> from plotly.figure_factory import create_gantt >>> # Make data for chart >>> df = [dict(Task="Job A", Start='2009-01-01', ... Finish='2009-02-30', Resource='Apple'), ... dict(Task="Job B", Start='2009-03-05', ... Finish='2009-04-15', Resource='Grape'), ... dict(Task="Job C", Start='2009-02-20', ... Finish='2009-05-30', Resource='Banana')] >>> # Create a figure with Plotly colorscale >>> fig = create_gantt(df, colors=['rgb(200, 50, 25)', (1, 0, 1), '#6c4774'], ... index_col='Resource', reverse_colors=True, ... show_colorbar=True) >>> fig.show() Example 4: Use a dictionary for colors >>> from plotly.figure_factory import create_gantt >>> # Make data for chart >>> df = [dict(Task="Job A", Start='2009-01-01', ... Finish='2009-02-30', Resource='Apple'), ... dict(Task="Job B", Start='2009-03-05', ... Finish='2009-04-15', Resource='Grape'), ... dict(Task="Job C", Start='2009-02-20', ... Finish='2009-05-30', Resource='Banana')] >>> # Make a dictionary of colors >>> colors = {'Apple': 'rgb(255, 0, 0)', ... 'Grape': 'rgb(170, 14, 200)', ... 'Banana': (1, 1, 0.2)} >>> # Create a figure with Plotly colorscale >>> fig = create_gantt(df, colors=colors, index_col='Resource', ... show_colorbar=True) >>> fig.show() Example 5: Use a pandas dataframe >>> from plotly.figure_factory import create_gantt >>> import pandas as pd >>> # Make data as a dataframe >>> df = pd.DataFrame([['Run', '2010-01-01', '2011-02-02', 10], ... ['Fast', '2011-01-01', '2012-06-05', 55], ... ['Eat', '2012-01-05', '2013-07-05', 94]], ... columns=['Task', 'Start', 'Finish', 'Complete']) >>> # Create a figure with Plotly colorscale >>> fig = create_gantt(df, colors='Blues', index_col='Complete', ... show_colorbar=True, bar_width=0.5, ... showgrid_x=True, showgrid_y=True) >>> fig.show() """ # validate gantt input data chart = validate_gantt(df) if index_col: if index_col not in chart[0]: raise exceptions.PlotlyError( "In order to use an indexing column and assign colors to " "the values of the index, you must choose an actual " "column name in the dataframe or key if a list of " "dictionaries is being used." ) # validate gantt index column index_list = [] for dictionary in chart: index_list.append(dictionary[index_col]) utils.validate_index(index_list) # Validate colors if isinstance(colors, dict): colors = clrs.validate_colors_dict(colors, "rgb") else: colors = clrs.validate_colors(colors, "rgb") if reverse_colors is True: colors.reverse() if not index_col: if isinstance(colors, dict): raise exceptions.PlotlyError( "Error. You have set colors to a dictionary but have not " "picked an index. An index is required if you are " "assigning colors to particular values in a dictionary." ) fig = gantt( chart, colors, title, bar_width, showgrid_x, showgrid_y, height, width, tasks=None, task_names=None, data=None, group_tasks=group_tasks, show_hover_fill=show_hover_fill, show_colorbar=show_colorbar, ) return fig else: if not isinstance(colors, dict): fig = gantt_colorscale( chart, colors, title, index_col, show_colorbar, bar_width, showgrid_x, showgrid_y, height, width, tasks=None, task_names=None, data=None, group_tasks=group_tasks, show_hover_fill=show_hover_fill, ) return fig else: fig = gantt_dict( chart, colors, title, index_col, show_colorbar, bar_width, showgrid_x, showgrid_y, height, width, tasks=None, task_names=None, data=None, group_tasks=group_tasks, show_hover_fill=show_hover_fill, ) return fig