diff --git a/plotly/tests/test_core/test_tools/test_figure_factory.py b/plotly/tests/test_core/test_tools/test_figure_factory.py index 2c5c0eda9f7..97fb061b213 100644 --- a/plotly/tests/test_core/test_tools/test_figure_factory.py +++ b/plotly/tests/test_core/test_tools/test_figure_factory.py @@ -1125,6 +1125,246 @@ def test_table_with_index(self): 'zeroline': False}}} self.assertEqual(index_table, exp_index_table) + +class TestGantt(TestCase): + + def test_validate_gantt(self): + + # validate the basic gantt inputs + + df = [{'Task': 'Job A', + 'Start': '2009-02-01', + 'Finish': '2009-08-30', + 'Complete': 'a'}] + + pattern2 = ('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.') + + self.assertRaisesRegexp(PlotlyError, pattern2, + tls.FigureFactory.create_gantt, + df, index_col='foo') + + df = 'foo' + + pattern3 = ('You must input either a dataframe or a list of ' + 'dictionaries.') + + self.assertRaisesRegexp(PlotlyError, pattern3, + tls.FigureFactory.create_gantt, df) + + df = [] + + pattern4 = ('Your list is empty. It must contain at least one ' + 'dictionary.') + + self.assertRaisesRegexp(PlotlyError, pattern4, + tls.FigureFactory.create_gantt, df) + + df = ['foo'] + + pattern5 = ('Your list must only include dictionaries.') + + self.assertRaisesRegexp(PlotlyError, pattern5, + tls.FigureFactory.create_gantt, df) + + def test_gantt_index(self): + + # validate the index used for gantt + + df = [{'Task': 'Job A', + 'Start': '2009-02-01', + 'Finish': '2009-08-30', + 'Complete': 50}] + + pattern = ('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.') + + self.assertRaisesRegexp(PlotlyError, pattern, + tls.FigureFactory.create_gantt, + df, index_col='foo') + + df = [{'Task': 'Job A', 'Start': '2009-02-01', + 'Finish': '2009-08-30', 'Complete': 'a'}, + {'Task': 'Job A', 'Start': '2009-02-01', + 'Finish': '2009-08-30', 'Complete': 50}] + + pattern2 = ('Error in indexing column. Make sure all entries of each ' + 'column are all numbers or all strings.') + + self.assertRaisesRegexp(PlotlyError, pattern2, + tls.FigureFactory.create_gantt, + df, index_col='Complete') + + def test_gantt_validate_colors(self): + + # validate the gantt colors variable + + df = [{'Task': 'Job A', 'Start': '2009-02-01', + 'Finish': '2009-08-30', 'Complete': 75, 'Resource': 'A'}, + {'Task': 'Job B', 'Start': '2009-02-01', + 'Finish': '2009-08-30', 'Complete': 50, 'Resource': 'B'}] + + pattern = ('Whoops! The elements in your rgb colors tuples cannot ' + 'exceed 255.0.') + + self.assertRaisesRegexp(PlotlyError, pattern, + tls.FigureFactory.create_gantt, df, + index_col='Complete', colors='rgb(300,1,1)') + + self.assertRaises(PlotlyError, tls.FigureFactory.create_gantt, + df, index_col='Complete', colors='foo') + + pattern2 = ('Whoops! The elements in your colors tuples cannot ' + 'exceed 1.0.') + + self.assertRaisesRegexp(PlotlyError, pattern2, + tls.FigureFactory.create_gantt, df, + index_col='Complete', colors=(2, 1, 1)) + + # verify that if colors is a dictionary, its keys span all the + # values in the index column + colors_dict = {75: 'rgb(1, 2, 3)'} + + pattern3 = ('If you are using colors as a dictionary, all of its ' + 'keys must be all the values in the index column.') + + self.assertRaisesRegexp(PlotlyError, pattern3, + tls.FigureFactory.create_gantt, df, + index_col='Complete', colors=colors_dict) + + # check: index is set if colors is a dictionary + colors_dict_good = {50: 'rgb(1, 2, 3)', 75: 'rgb(5, 10, 15)'} + + pattern4 = ('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 dictioanry.') + + self.assertRaisesRegexp(PlotlyError, pattern4, + tls.FigureFactory.create_gantt, df, + colors=colors_dict_good) + + # check: number of colors is equal to or greater than number of + # unique index string values + pattern5 = ("Error. The number of colors in 'colors' must be no less " + "than the number of unique index values in your group " + "column.") + + self.assertRaisesRegexp(PlotlyError, pattern5, + tls.FigureFactory.create_gantt, df, + index_col='Resource', + colors=['#ffffff']) + + # check: if index is numeric, colors has at least 2 colors in it + pattern6 = ("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.") + + self.assertRaisesRegexp(PlotlyError, pattern6, + tls.FigureFactory.create_gantt, df, + index_col='Complete', + colors=['#ffffff']) + + def test_gantt_all_args(self): + + # check if gantt chart matches with expected output + + df = [{'Task': 'Run', + 'Start': '2010-01-01', + 'Finish': '2011-02-02', + 'Complete': 0}, + {'Task': 'Fast', + 'Start': '2011-01-01', + 'Finish': '2012-06-05', + 'Complete': 25}] + + test_gantt_chart = tls.FigureFactory.create_gantt( + df, colors='Blues', index_col='Complete', reverse_colors=True, + title='Title', bar_width=0.5, showgrid_x=True, showgrid_y=True, + height=500, width=500 + ) + + exp_gantt_chart = { + 'data': [{'marker': {'color': 'white'}, + 'name': '', + 'x': ['2010-01-01', '2011-02-02'], + 'y': [0, 0]}, + {'marker': {'color': 'white'}, + 'name': '', + 'x': ['2011-01-01', '2012-06-05'], + 'y': [1, 1]}], + 'layout': {'height': 500, + 'hovermode': 'closest', + 'shapes': [{'fillcolor': 'rgb(220.0, 220.0, 220.0)', + 'line': {'width': 0}, + 'opacity': 1, + 'type': 'rect', + 'x0': '2010-01-01', + 'x1': '2011-02-02', + 'xref': 'x', + 'y0': -0.5, + 'y1': 0.5, + 'yref': 'y'}, + {'fillcolor': 'rgb(166.25, 167.5, 208.0)', + 'line': {'width': 0}, + 'opacity': 1, + 'type': 'rect', + 'x0': '2011-01-01', + 'x1': '2012-06-05', + 'xref': 'x', + 'y0': 0.5, + 'y1': 1.5, + 'yref': 'y'}], + 'showlegend': False, + 'title': 'Title', + 'width': 500, + 'xaxis': {'rangeselector': {'buttons': [ + {'count': 7, + 'label': '1w', + 'step': 'day', + 'stepmode': 'backward'}, + {'count': 1, + 'label': '1m', + 'step': 'month', + 'stepmode': 'backward'}, + {'count': 6, + 'label': '6m', + 'step': 'month', + 'stepmode': 'backward'}, + {'count': 1, + 'label': 'YTD', + 'step': 'year', + 'stepmode': 'todate'}, + {'count': 1, + 'label': '1y', + 'step': 'year', + 'stepmode': 'backward'}, + {'step': 'all'} + ]}, + 'showgrid': True, + 'type': 'date', + 'zeroline': False}, + 'yaxis': {'autorange': False, + 'range': [-1, 3], + 'showgrid': True, + 'ticktext': ['Run', 'Fast'], + 'tickvals': [0, 1], + 'zeroline': False}} + } + + self.assertEqual(test_gantt_chart['data'][0], + exp_gantt_chart['data'][0]) + + self.assertEqual(test_gantt_chart['data'][1], + exp_gantt_chart['data'][1]) + + self.assertEqual(test_gantt_chart['layout'], + exp_gantt_chart['layout']) + # class TestDistplot(TestCase): # def test_scipy_import_error(self): diff --git a/plotly/tests/test_optional/test_figure_factory.py b/plotly/tests/test_optional/test_figure_factory.py index ad64fa82fb3..c2a0f3da624 100644 --- a/plotly/tests/test_optional/test_figure_factory.py +++ b/plotly/tests/test_optional/test_figure_factory.py @@ -1267,6 +1267,85 @@ def test_scatter_plot_matrix_kwargs(self): exp_scatter_plot_matrix['layout']) +class TestGantt(NumpyTestUtilsMixin, TestCase): + + def test_df_dataframe(self): + + # validate dataframe has correct column names + df1 = pd.DataFrame([[2, 'Apple']], columns=['Numbers', 'Fruit']) + self.assertRaises(PlotlyError, tls.FigureFactory.create_gantt, df1) + + def test_df_dataframe_all_args(self): + + # check if gantt chart matches with expected output + + df = pd.DataFrame([['Job A', '2009-01-01', '2009-02-30'], + ['Job B', '2009-03-05', '2009-04-15']], + columns=['Task', 'Start', 'Finish']) + + test_gantt_chart = tls.FigureFactory.create_gantt(df) + + exp_gantt_chart = { + 'data': [{'marker': {'color': 'white'}, + 'name': '', + 'x': ['2009-01-01', '2009-02-30'], + 'y': [0, 0]}], + 'layout': {'height': 600, + 'hovermode': 'closest', + 'shapes': [{'opacity': 1, + 'y1': 0.2, + 'xref': 'x', + 'fillcolor': 'rgb(31.0, 119.0, 180.0)', + 'yref': 'y', + 'y0': -0.2, + 'x0': '2009-01-01', + 'x1': '2009-02-30', + 'type': 'rect', + 'line': {'width': 0}}, + {'opacity': 1, + 'y1': 1.2, + 'xref': 'x', + 'fillcolor': 'rgb(255.0, 127.0, 14.0)', + 'yref': 'y', + 'y0': 0.8, + 'x0': '2009-03-05', + 'x1': '2009-04-15', + 'type': 'rect', + 'line': {'width': 0}}], + 'showlegend': False, + 'title': 'Gantt Chart', + 'width': 900, + 'xaxis': {'rangeselector': {'buttons': [ + {'count': 7, 'label': '1w', + 'step': 'day', 'stepmode': 'backward'}, + {'count': 1, 'label': '1m', + 'step': 'month', 'stepmode': 'backward'}, + {'count': 6, 'label': '6m', + 'step': 'month', 'stepmode': 'backward'}, + {'count': 1, 'label': 'YTD', + 'step': 'year', 'stepmode': 'todate'}, + {'count': 1, 'label': '1y', + 'step': 'year', 'stepmode': 'backward'}, + {'step': 'all'} + ]}, + 'showgrid': False, + 'type': 'date', + 'zeroline': False}, + 'yaxis': {'autorange': False, + 'range': [-1, 3], + 'showgrid': False, + 'ticktext': ['Job A', 'Job B'], + 'tickvals': [0, 1], + 'zeroline': False}} + } + + self.assertEqual(test_gantt_chart['data'][0], + exp_gantt_chart['data'][0]) + + self.assert_dict_equal(test_gantt_chart['layout'], + exp_gantt_chart['layout']) + + class TestViolin(NumpyTestUtilsMixin, TestCase): def test_colors_validation(self): diff --git a/plotly/tools.py b/plotly/tools.py index 26984adbedd..c2f12bc26c5 100644 --- a/plotly/tools.py +++ b/plotly/tools.py @@ -28,6 +28,8 @@ 'rgb(227, 119, 194)', 'rgb(127, 127, 127)', 'rgb(188, 189, 34)', 'rgb(23, 190, 207)'] + +REQUIRED_GANTT_KEYS = ['Task', 'Start', 'Finish'] PLOTLY_SCALES = {'Greys': ['rgb(0,0,0)', 'rgb(255,255,255)'], 'YlGnBu': ['rgb(8,29,88)', 'rgb(255,255,217)'], 'Greens': ['rgb(0,68,27)', 'rgb(247,252,245)'], @@ -1474,6 +1476,706 @@ class FigureFactory(object): more information and examples of a specific chart type. """ + @staticmethod + def _validate_gantt(df): + """ + Validates the inputted dataframe or list + """ + if _pandas_imported 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 " + "keys".format(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.ix[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 + + @staticmethod + def _gantt(chart, colors, title, bar_width, showgrid_x, showgrid_y, + height, width, tasks=None, task_names=None, data=None): + """ + Refer to FigureFactory.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']) + tasks.append(task) + + shape_template = { + 'type': 'rect', + 'xref': 'x', + 'yref': 'y', + 'opacity': 1, + 'line': { + 'width': 0, + }, + 'yref': 'y', + } + + color_index = 0 + for index in range(len(tasks)): + tn = tasks[index]['name'] + task_names.append(tn) + del tasks[index]['name'] + tasks[index].update(shape_template) + tasks[index]['y0'] = index - bar_width + tasks[index]['y1'] = index + bar_width + + # check if colors need to be looped + if color_index >= len(colors): + color_index = 0 + tasks[index]['fillcolor'] = colors[color_index] + # Add a line for hover text and autorange + data.append( + dict( + x=[tasks[index]['x0'], tasks[index]['x1']], + y=[index, index], + name='', + marker={'color': 'white'} + ) + ) + color_index += 1 + + layout = dict( + title=title, + showlegend=False, + height=height, + width=width, + shapes=[], + hovermode='closest', + yaxis=dict( + showgrid=showgrid_y, + ticktext=task_names, + tickvals=list(range(len(tasks))), + range=[-1, len(tasks) + 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' + ) + ) + layout['shapes'] = tasks + + fig = dict(data=data, layout=layout) + return fig + + @staticmethod + 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): + """ + Refer to FigureFactory.create_gantt() for docstring + """ + from numbers import Number + 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']) + tasks.append(task) + + shape_template = { + 'type': 'rect', + 'xref': 'x', + 'yref': 'y', + 'opacity': 1, + 'line': { + 'width': 0, + }, + 'yref': 'y', + } + + # 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." + ) + for index in range(len(tasks)): + tn = tasks[index]['name'] + task_names.append(tn) + del tasks[index]['name'] + tasks[index].update(shape_template) + tasks[index]['y0'] = index - bar_width + tasks[index]['y1'] = index + bar_width + + # unlabel color + colors = FigureFactory._color_parser( + colors, FigureFactory._unlabel_rgb + ) + lowcolor = colors[0] + highcolor = colors[1] + + intermed = (chart[index][index_col])/100.0 + intermed_color = FigureFactory._find_intermediate_color( + lowcolor, highcolor, intermed + ) + intermed_color = FigureFactory._color_parser( + intermed_color, FigureFactory._label_rgb + ) + tasks[index]['fillcolor'] = intermed_color + # relabel colors with 'rgb' + colors = FigureFactory._color_parser( + colors, FigureFactory._label_rgb + ) + + # add a line for hover text and autorange + data.append( + dict( + x=[tasks[index]['x0'], tasks[index]['x1']], + y=[index, index], + name='', + marker={'color': 'white'} + ) + ) + + if show_colorbar is True: + # generate dummy data for colorscale visibility + data.append( + dict( + x=[tasks[index]['x0'], tasks[index]['x0']], + y=[index, index], + name='', + marker={'color': 'white', + '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 + + for index in range(len(tasks)): + tn = tasks[index]['name'] + task_names.append(tn) + del tasks[index]['name'] + tasks[index].update(shape_template) + tasks[index]['y0'] = index - bar_width + tasks[index]['y1'] = index + bar_width + + tasks[index]['fillcolor'] = index_vals_dict[ + chart[index][index_col] + ] + + # add a line for hover text and autorange + data.append( + dict( + x=[tasks[index]['x0'], tasks[index]['x1']], + y=[index, index], + name='', + marker={'color': 'white'} + ) + ) + + if show_colorbar is True: + # generate dummy data to generate legend + showlegend = True + for k, index_value in enumerate(index_vals): + data.append( + dict( + x=[tasks[index]['x0'], tasks[index]['x0']], + y=[k, k], + showlegend=True, + name=str(index_value), + hoverinfo='none', + marker=dict( + color=colors[k], + size=1 + ) + ) + ) + + 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(tasks))), + range=[-1, len(tasks) + 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' + ) + ) + layout['shapes'] = tasks + + fig = dict(data=data, layout=layout) + return fig + + @staticmethod + 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): + """ + 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']) + tasks.append(task) + + shape_template = { + 'type': 'rect', + 'xref': 'x', + 'yref': 'y', + 'opacity': 1, + 'line': { + 'width': 0, + }, + 'yref': 'y', + } + + 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." + ) + + for index in range(len(tasks)): + tn = tasks[index]['name'] + task_names.append(tn) + del tasks[index]['name'] + tasks[index].update(shape_template) + tasks[index]['y0'] = index - bar_width + tasks[index]['y1'] = index + bar_width + + tasks[index]['fillcolor'] = colors[chart[index][index_col]] + + # add a line for hover text and autorange + data.append( + dict( + x=[tasks[index]['x0'], tasks[index]['x1']], + y=[index, index], + name='', + marker={'color': 'white'} + ) + ) + + if show_colorbar is True: + # generate dummy data to generate legend + showlegend = True + for k, index_value in enumerate(index_vals): + data.append( + dict( + x=[tasks[index]['x0'], tasks[index]['x0']], + y=[k, k], + showlegend=True, + hoverinfo='none', + name=str(index_value), + marker=dict( + color=colors[index_value], + size=1 + ) + ) + ) + + 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(tasks))), + range=[-1, len(tasks) + 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' + ) + ) + layout['shapes'] = tasks + + fig = dict(data=data, layout=layout) + return fig + + @staticmethod + 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=900, tasks=None, + task_names=None, data=None): + """ + 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) 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 + ``` + import plotly.plotly as py + from plotly.tools import FigureFactory as FF + + # 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 = FF.create_gantt(df) + + # Plot the data + py.iplot(fig, filename='Simple Gantt Chart', world_readable=True) + ``` + + Example 2: Index by Column with Numerical Entries + ``` + import plotly.plotly as py + from plotly.tools import FigureFactory as FF + + # 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 = FF.create_gantt(df, colors='Blues', index_col='Complete', + show_colorbar=True, bar_width=0.5, + showgrid_x=True, showgrid_y=True) + + # Plot the data + py.iplot(fig, filename='Numerical Entries', world_readable=True) + ``` + + Example 3: Index by Column with String Entries + ``` + import plotly.plotly as py + from plotly.tools import FigureFactory as FF + + # 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 = FF.create_gantt(df, colors=['rgb(200, 50, 25)', + (1, 0, 1), + '#6c4774'], + index_col='Resource', + reverse_colors=True, + show_colorbar=True) + + # Plot the data + py.iplot(fig, filename='String Entries', world_readable=True) + ``` + + Example 4: Use a dictionary for colors + ``` + import plotly.plotly as py + from plotly.tools import FigureFactory as FF + + # 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 = FF.create_gantt(df, colors=colors, + index_col='Resource', + show_colorbar=True) + + # Plot the data + py.iplot(fig, filename='dictioanry colors', world_readable=True) + ``` + + Example 5: Use a pandas dataframe + ``` + import plotly.plotly as py + from plotly.tools import FigureFactory as FF + + # Make data as a dataframe + df = [{'Task': 'Run', + 'Start': '2010-01-01', + 'Finish': '2011-02-02', + 'Complete': 10}, + {'Task': 'Fast', + 'Start': '2011-01-01', + 'Finish': '2012-06-05', + 'Complete': 55}, + {'Task': 'Eat', + 'Start': '2012-01-05', + 'Finish': '2013-07-05', + 'Complete': 94}] + + # Create a figure with Plotly colorscale + fig = FF.create_gantt(df, colors='Blues', index_col='Complete', + show_colorbar=True, bar_width=0.5, + showgrid_x=True, showgrid_y=True) + + # Plot the data + py.iplot(fig, filename='data with dataframe', world_readable=True) + ``` + """ + # validate gantt input data + chart = FigureFactory._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]) + FigureFactory._validate_index(index_list) + + # Validate colors + if isinstance(colors, dict): + colors = FigureFactory._validate_colors_dict(colors, 'rgb') + else: + colors = FigureFactory._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 dictioanry." + ) + fig = FigureFactory._gantt( + chart, colors, title, bar_width, showgrid_x, showgrid_y, + height, width, tasks=None, task_names=None, data=None + ) + return fig + else: + if not isinstance(colors, dict): + fig = FigureFactory._gantt_colorscale( + chart, colors, title, index_col, show_colorbar, bar_width, + showgrid_x, showgrid_y, height, width, + tasks=None, task_names=None, data=None + ) + return fig + else: + fig = FigureFactory._gantt_dict( + chart, colors, title, index_col, show_colorbar, bar_width, + showgrid_x, showgrid_y, height, width, + tasks=None, task_names=None, data=None + ) + return fig + @staticmethod def _validate_colors(colors, colortype='tuple'): """