def violin_dict( data, data_header, group_header, colors, use_colorscale, group_stats, rugplot, sort, height, width, title, ): """ Refer to FigureFactory.create_violin() for docstring. Returns fig for violin plot without colorscale. """ # collect all group names group_name = [] for name in data[group_header]: if name not in group_name: group_name.append(name) if sort: group_name.sort() # check if all group names appear in colors dict for group in group_name: if group not in colors: raise exceptions.PlotlyError( "If colors is a dictionary, all " "the group names must appear as " "keys in colors." ) gb = data.groupby([group_header]) L = len(group_name) fig = make_subplots( rows=1, cols=L, shared_yaxes=True, horizontal_spacing=0.025, print_grid=False ) for k, gr in enumerate(group_name): vals = np.asarray(gb.get_group(gr)[data_header], np.float) plot_data, plot_xrange = violinplot(vals, fillcolor=colors[gr], rugplot=rugplot) layout = graph_objs.Layout() for item in plot_data: fig.append_trace(item, 1, k + 1) # add violin plot labels fig["layout"].update( {"xaxis{}".format(k + 1): make_XAxis(group_name[k], plot_xrange)} ) # set the sharey axis style fig["layout"].update({"yaxis{}".format(1): make_YAxis("")}) fig["layout"].update( title=title, showlegend=False, hovermode="closest", autosize=False, height=height, width=width, ) 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): """ 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) shape_template = { 'type': 'rect', 'xref': 'x', 'yref': 'y', 'opacity': 1, 'line': { 'width': 0, } } 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'] tasks[index].update(shape_template) # 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]] # add a line for hover text and autorange entry = dict(x=[tasks[index]['x0'], tasks[index]['x1']], y=[groupID, groupID], showlegend=False, name='', marker={'color': 'white'}) if "description" in tasks[index]: entry['text'] = tasks[index]['description'] del tasks[index]['description'] data.append(entry) 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(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')) layout['shapes'] = tasks fig = dict(data=data, layout=layout) return fig
def create_bullet(data, markers=None, measures=None, ranges=None, subtitles=None, titles=None, orientation="h", range_colors=("rgb(200, 200, 200)", "rgb(245, 245, 245)"), measure_colors=("rgb(31, 119, 180)", "rgb(176, 196, 221)"), horizontal_spacing=None, vertical_spacing=None, scatter_options={}, **layout_options): """ **deprecated**, use instead the plotly.graph_objects trace :class:`plotly.graph_objects.Indicator`. :param (pd.DataFrame | list | tuple) data: either a list/tuple of dictionaries or a pandas DataFrame. :param (str) markers: the column name or dictionary key for the markers in each subplot. :param (str) measures: the column name or dictionary key for the measure bars in each subplot. This bar usually represents the quantitative measure of performance, usually a list of two values [a, b] and are the blue bars in the foreground of each subplot by default. :param (str) ranges: the column name or dictionary key for the qualitative ranges of performance, usually a 3-item list [bad, okay, good]. They correspond to the grey bars in the background of each chart. :param (str) subtitles: the column name or dictionary key for the subtitle of each subplot chart. The subplots are displayed right underneath each title. :param (str) titles: the column name or dictionary key for the main label of each subplot chart. :param (bool) orientation: if 'h', the bars are placed horizontally as rows. If 'v' the bars are placed vertically in the chart. :param (list) range_colors: a tuple of two colors between which all the rectangles for the range are drawn. These rectangles are meant to be qualitative indicators against which the marker and measure bars are compared. Default=('rgb(200, 200, 200)', 'rgb(245, 245, 245)') :param (list) measure_colors: a tuple of two colors which is used to color the thin quantitative bars in the bullet chart. Default=('rgb(31, 119, 180)', 'rgb(176, 196, 221)') :param (float) horizontal_spacing: see the 'horizontal_spacing' param in plotly.tools.make_subplots. Ranges between 0 and 1. :param (float) vertical_spacing: see the 'vertical_spacing' param in plotly.tools.make_subplots. Ranges between 0 and 1. :param (dict) scatter_options: describes attributes for the scatter trace in each subplot such as name and marker size. Call help(plotly.graph_objs.Scatter) for more information on valid params. :param layout_options: describes attributes for the layout of the figure such as title, height and width. Call help(plotly.graph_objs.Layout) for more information on valid params. Example 1: Use a Dictionary >>> import plotly.figure_factory as ff >>> data = [ ... {"label": "revenue", "sublabel": "us$, in thousands", ... "range": [150, 225, 300], "performance": [220,270], "point": [250]}, ... {"label": "Profit", "sublabel": "%", "range": [20, 25, 30], ... "performance": [21, 23], "point": [26]}, ... {"label": "Order Size", "sublabel":"US$, average","range": [350, 500, 600], ... "performance": [100,320],"point": [550]}, ... {"label": "New Customers", "sublabel": "count", "range": [1400, 2000, 2500], ... "performance": [1000, 1650],"point": [2100]}, ... {"label": "Satisfaction", "sublabel": "out of 5","range": [3.5, 4.25, 5], ... "performance": [3.2, 4.7], "point": [4.4]} ... ] >>> fig = ff.create_bullet( ... data, titles='label', subtitles='sublabel', markers='point', ... measures='performance', ranges='range', orientation='h', ... title='my simple bullet chart' ... ) >>> fig.show() Example 2: Use a DataFrame with Custom Colors >>> import plotly.figure_factory as ff >>> import pandas as pd >>> data = pd.read_json('https://cdn.rawgit.com/plotly/datasets/master/BulletData.json') >>> fig = ff.create_bullet( ... data, titles='title', markers='markers', measures='measures', ... orientation='v', measure_colors=['rgb(14, 52, 75)', 'rgb(31, 141, 127)'], ... scatter_options={'marker': {'symbol': 'circle'}}, width=700) >>> fig.show() """ # validate df if not pd: raise ImportError( "'pandas' must be installed for this figure factory.") if utils.is_sequence(data): if not all(isinstance(item, dict) for item in data): raise exceptions.PlotlyError( "Every entry of the data argument list, tuple, etc must " "be a dictionary.") elif not isinstance(data, pd.DataFrame): raise exceptions.PlotlyError( "You must input a pandas DataFrame, or a list of dictionaries.") # make DataFrame from data with correct column headers col_names = ["titles", "subtitle", "markers", "measures", "ranges"] if utils.is_sequence(data): df = pd.DataFrame( [ [d[titles] for d in data] if titles else [""] * len(data), [d[subtitles] for d in data] if subtitles else [""] * len(data), [d[markers] for d in data] if markers else [[]] * len(data), [d[measures] for d in data] if measures else [[]] * len(data), [d[ranges] for d in data] if ranges else [[]] * len(data), ], index=col_names, ) elif isinstance(data, pd.DataFrame): df = pd.DataFrame( [ data[titles].tolist() if titles else [""] * len(data), data[subtitles].tolist() if subtitles else [""] * len(data), data[markers].tolist() if markers else [[]] * len(data), data[measures].tolist() if measures else [[]] * len(data), data[ranges].tolist() if ranges else [[]] * len(data), ], index=col_names, ) df = pd.DataFrame.transpose(df) # make sure ranges, measures, 'markers' are not NAN or NONE for needed_key in ["ranges", "measures", "markers"]: for idx, r in enumerate(df[needed_key]): try: r_is_nan = math.isnan(r) if r_is_nan or r is None: df[needed_key][idx] = [] except TypeError: pass # validate custom colors for colors_list in [range_colors, measure_colors]: if colors_list: if len(colors_list) != 2: raise exceptions.PlotlyError( "Both 'range_colors' or 'measure_colors' must be a list " "of two valid colors.") clrs.validate_colors(colors_list) colors_list = clrs.convert_colors_to_same_type(colors_list, "rgb")[0] # default scatter options default_scatter = { "marker": { "size": 12, "symbol": "diamond-tall", "color": "rgb(0, 0, 0)" } } if scatter_options == {}: scatter_options.update(default_scatter) else: # add default options to scatter_options if they are not present for k in default_scatter["marker"]: if k not in scatter_options["marker"]: scatter_options["marker"][k] = default_scatter["marker"][k] fig = _bullet( df, markers, measures, ranges, subtitles, titles, orientation, range_colors, measure_colors, horizontal_spacing, vertical_spacing, scatter_options, layout_options, ) return fig
def get_figure(file_owner_or_url, file_id=None, raw=False): """Returns a JSON figure representation for the specified file Plotly uniquely identifies figures with a 'file_owner'/'file_id' pair. Since each file is given a corresponding unique url, you may also simply pass a valid plotly url as the first argument. Examples: fig = get_figure('https://plot.ly/~chris/1638') fig = get_figure('chris', 1638) Note, if you're using a file_owner string as the first argument, you MUST specify a `file_id` keyword argument. Else, if you're using a url string as the first argument, you MUST NOT specify a `file_id` keyword argument, or file_id must be set to Python's None value. Positional arguments: file_owner_or_url (string) -- a valid plotly username OR a valid plotly url Keyword arguments: file_id (default=None) -- an int or string that can be converted to int if you're using a url, don't fill this in! raw (default=False) -- if true, return unicode JSON string verbatim** **by default, plotly will return a Figure object (run help(plotly .graph_objs.Figure)). This representation decodes the keys and values from unicode (if possible), removes information irrelevant to the figure representation, and converts the JSON dictionary objects to plotly `graph objects`. """ plotly_rest_url = get_config()['plotly_domain'] if file_id is None: # assume we're using a url url = file_owner_or_url if url[:len(plotly_rest_url)] != plotly_rest_url: raise exceptions.PlotlyError( "Because you didn't supply a 'file_id' in the call, " "we're assuming you're trying to snag a figure from a url. " "You supplied the url, '{0}', we expected it to start with " "'{1}'." "\nRun help on this function for more information." "".format(url, plotly_rest_url)) head = plotly_rest_url + "/~" file_owner = url.replace(head, "").split('/')[0] file_id = url.replace(head, "").split('/')[1] else: file_owner = file_owner_or_url resource = "/apigetfile/{username}/{file_id}".format(username=file_owner, file_id=file_id) credentials = get_credentials() validate_credentials(credentials) username, api_key = credentials['username'], credentials['api_key'] headers = { 'plotly-username': username, 'plotly-apikey': api_key, 'plotly-version': version.__version__, 'plotly-platform': 'python' } try: int(file_id) except ValueError: raise exceptions.PlotlyError( "The 'file_id' argument was not able to be converted into an " "integer number. Make sure that the positional 'file_id' argument " "is a number that can be converted into an integer or a string " "that can be converted into an integer.") if int(file_id) < 0: raise exceptions.PlotlyError( "The 'file_id' argument must be a non-negative number.") response = requests.get(plotly_rest_url + resource, headers=headers, verify=get_config()['plotly_ssl_verification']) if response.status_code == 200: if six.PY3: content = json.loads(response.content.decode('utf-8')) else: content = json.loads(response.content) response_payload = content['payload'] figure = response_payload['figure'] utils.decode_unicode(figure) if raw: return figure else: return tools.get_valid_graph_obj(figure, obj_type='Figure') else: try: content = json.loads(response.content) raise exceptions.PlotlyError(content) except: raise exceptions.PlotlyError( "There was an error retrieving this file")
def get(figure_or_data, format='png', width=None, height=None): """ Return a static image of the plot described by `figure`. Valid formats: 'png', 'svg', 'jpeg', 'pdf' """ # TODO: format is a built-in name... we shouldn't really use it if isinstance(figure_or_data, dict): figure = figure_or_data elif isinstance(figure_or_data, list): figure = {'data': figure_or_data} else: raise exceptions.PlotlyEmptyDataError( "`figure_or_data` must be a dict or a list.") if format not in ['png', 'svg', 'jpeg', 'pdf']: raise exceptions.PlotlyError( "Invalid format. This version of your Plotly-Python " "package currently only supports png, svg, jpeg, and pdf. " "Learn more about image exporting, and the currently " "supported file types here: " "https://plot.ly/python/static-image-export/") credentials = get_credentials() validate_credentials(credentials) username, api_key = credentials['username'], credentials['api_key'] headers = { 'Plotly-Version': version.__version__, 'Content-Type': 'application/json', 'Plotly-Client-Platform': 'python' } payload = {'figure': figure, 'format': format} if width is not None: payload['width'] = width if height is not None: payload['height'] = height url = _api_v2.api_url('images/') res = requests.post(url, data=json.dumps(payload, cls=utils.PlotlyJSONEncoder), headers=headers, verify=get_config()['plotly_ssl_verification'], auth=HTTPBasicAuth(username, api_key)) headers = res.headers if res.status_code == 200: if ('content-type' in headers and headers['content-type'] in [ 'image/png', 'image/jpeg', 'application/pdf', 'image/svg+xml' ]): return res.content elif ('content-type' in headers and 'json' in headers['content-type']): return_data = json.loads(res.content) return return_data['image'] else: try: if ('content-type' in headers and 'json' in headers['content-type']): return_data = json.loads(res.content) else: return_data = {'error': res.content} except: raise exceptions.PlotlyError("The response " "from plotly could " "not be translated.") raise exceptions.PlotlyError(return_data['error'])
def create_violin(data, data_header=None, group_header=None, colors=None, use_colorscale=False, group_stats=None, rugplot=True, sort=False, height=450, width=600, title='Violin and Rug Plot'): """ Returns figure for a violin plot :param (list|array) data: accepts either a list of numerical values, a list of dictionaries all with identical keys and at least one column of numeric values, or a pandas dataframe with at least one column of numbers. :param (str) data_header: the header of the data column to be used from an inputted pandas dataframe. Not applicable if 'data' is a list of numeric values. :param (str) group_header: applicable if grouping data by a variable. 'group_header' must be set to the name of the grouping variable. :param (str|tuple|list|dict) colors: either a plotly scale name, an rgb or hex color, a color tuple, a list of colors or a dictionary. An rgb color is of the form 'rgb(x, y, z)' where x, y and 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 valid color types as its members. :param (bool) use_colorscale: only applicable if grouping by another variable. Will implement a colorscale based on the first 2 colors of param colors. This means colors must be a list with at least 2 colors in it (Plotly colorscales are accepted since they map to a list of two rgb colors). Default = False :param (dict) group_stats: a dictioanry where each key is a unique value from the group_header column in data. Each value must be a number and will be used to color the violin plots if a colorscale is being used. :param (bool) rugplot: determines if a rugplot is draw on violin plot. Default = True :param (bool) sort: determines if violins are sorted alphabetically (True) or by input order (False). Default = False :param (float) height: the height of the violin plot. :param (float) width: the width of the violin plot. :param (str) title: the title of the violin plot. Example 1: Single Violin Plot ``` import plotly.plotly as py from plotly.figure_factory import create_violin from plotly.graph_objs import graph_objs import numpy as np from scipy import stats # create list of random values data_list = np.random.randn(100) data_list.tolist() # create violin fig fig = create_violin(data_list, colors='#604d9e') # plot py.iplot(fig, filename='Violin Plot') ``` Example 2: Multiple Violin Plots with Qualitative Coloring ``` import plotly.plotly as py from plotly.figure_factory import create_violin from plotly.graph_objs import graph_objs import numpy as np import pandas as pd from scipy import stats # create dataframe np.random.seed(619517) Nr=250 y = np.random.randn(Nr) gr = np.random.choice(list("ABCDE"), Nr) norm_params=[(0, 1.2), (0.7, 1), (-0.5, 1.4), (0.3, 1), (0.8, 0.9)] for i, letter in enumerate("ABCDE"): y[gr == letter] *=norm_params[i][1]+ norm_params[i][0] df = pd.DataFrame(dict(Score=y, Group=gr)) # create violin fig fig = create_violin(df, data_header='Score', group_header='Group', sort=True, height=600, width=1000) # plot py.iplot(fig, filename='Violin Plot with Coloring') ``` Example 3: Violin Plots with Colorscale ``` import plotly.plotly as py from plotly.figure_factory import create_violin from plotly.graph_objs import graph_objs import numpy as np import pandas as pd from scipy import stats # create dataframe np.random.seed(619517) Nr=250 y = np.random.randn(Nr) gr = np.random.choice(list("ABCDE"), Nr) norm_params=[(0, 1.2), (0.7, 1), (-0.5, 1.4), (0.3, 1), (0.8, 0.9)] for i, letter in enumerate("ABCDE"): y[gr == letter] *=norm_params[i][1]+ norm_params[i][0] df = pd.DataFrame(dict(Score=y, Group=gr)) # define header params data_header = 'Score' group_header = 'Group' # make groupby object with pandas group_stats = {} groupby_data = df.groupby([group_header]) for group in "ABCDE": data_from_group = groupby_data.get_group(group)[data_header] # take a stat of the grouped data stat = np.median(data_from_group) # add to dictionary group_stats[group] = stat # create violin fig fig = create_violin(df, data_header='Score', group_header='Group', height=600, width=1000, use_colorscale=True, group_stats=group_stats) # plot py.iplot(fig, filename='Violin Plot with Colorscale') ``` """ # Validate colors if isinstance(colors, dict): valid_colors = clrs.validate_colors_dict(colors, 'rgb') else: valid_colors = clrs.validate_colors(colors, 'rgb') # validate data and choose plot type if group_header is None: if isinstance(data, list): if len(data) <= 0: raise exceptions.PlotlyError("If data is a list, it must be " "nonempty and contain either " "numbers or dictionaries.") if not all(isinstance(element, Number) for element in data): raise exceptions.PlotlyError("If data is a list, it must " "contain only numbers.") if pd and isinstance(data, pd.core.frame.DataFrame): if data_header is None: raise exceptions.PlotlyError("data_header must be the " "column name with the " "desired numeric data for " "the violin plot.") data = data[data_header].values.tolist() # call the plotting functions plot_data, plot_xrange = violinplot(data, fillcolor=valid_colors[0], rugplot=rugplot) layout = graph_objs.Layout(title=title, autosize=False, font=graph_objs.layout.Font(size=11), height=height, showlegend=False, width=width, xaxis=make_XAxis('', plot_xrange), yaxis=make_YAxis(''), hovermode='closest') layout['yaxis'].update( dict(showline=False, showticklabels=False, ticks='')) fig = graph_objs.Figure(data=plot_data, layout=layout) return fig else: if not isinstance(data, pd.core.frame.DataFrame): raise exceptions.PlotlyError("Error. You must use a pandas " "DataFrame if you are using a " "group header.") if data_header is None: raise exceptions.PlotlyError("data_header must be the column " "name with the desired numeric " "data for the violin plot.") if use_colorscale is False: if isinstance(valid_colors, dict): # validate colors dict choice below fig = violin_dict(data, data_header, group_header, valid_colors, use_colorscale, group_stats, rugplot, sort, height, width, title) return fig else: fig = violin_no_colorscale(data, data_header, group_header, valid_colors, use_colorscale, group_stats, rugplot, sort, height, width, title) return fig else: if isinstance(valid_colors, dict): raise exceptions.PlotlyError("The colors param cannot be " "a dictionary if you are " "using a colorscale.") if len(valid_colors) < 2: raise exceptions.PlotlyError("colors must be a list with " "at least 2 colors. A " "Plotly scale is allowed.") if not isinstance(group_stats, dict): raise exceptions.PlotlyError("Your group_stats param " "must be a dictionary.") fig = violin_colorscale(data, data_header, group_header, valid_colors, use_colorscale, group_stats, rugplot, sort, height, width, title) return fig
def plot(figure_or_data, validate=True, **plot_options): """Create a unique url for this plot in Plotly and optionally open url. plot_options keyword agruments: filename (string) -- the name that will be associated with this figure fileopt ('new' | 'overwrite' | 'extend' | 'append') -- 'new' creates a 'new': create a new, unique url for this plot 'overwrite': overwrite the file associated with `filename` with this 'extend': add additional numbers (data) to existing traces 'append': add additional traces to existing data lists world_readable (default=True) -- make this figure private/public auto_open (default=True) -- Toggle browser options True: open this plot in a new browser tab False: do not open plot in the browser, but do return the unique url """ if isinstance(figure_or_data, dict): figure = figure_or_data elif isinstance(figure_or_data, list): figure = {'data': figure_or_data} else: raise exceptions.PlotlyError( "The `figure_or_data` positional argument " "must be either `dict`-like or " "`list`-like.") if validate: try: tools.validate(figure, obj_type='Figure') except exceptions.PlotlyError as err: raise exceptions.PlotlyError("Invalid 'figure_or_data' argument. " "Plotly will not be able to properly " "parse the resulting JSON. If you " "want to send this 'figure_or_data' " "to Plotly anyway (not recommended), " "you can set 'validate=False' as a " "plot option.\nHere's why you're " "seeing this error:\n\n{0}" "".format(err)) for entry in figure['data']: for key, val in list(entry.items()): try: if len(val) > 40000: msg = ("Woah there! Look at all those points! Due to " "browser limitations, Plotly has a hard time " "graphing more than 500k data points for line " "charts, or 40k points for other types of charts. " "Here are some suggestions:\n" "(1) Trying using the image API to return an image " "instead of a graph URL\n" "(2) Use matplotlib\n" "(3) See if you can create your visualization with " "fewer data points\n\n" "If the visualization you're using aggregates " "points (e.g., box plot, histogram, etc.) you can " "disregard this warning.") warnings.warn(msg) except TypeError: pass plot_options = _plot_option_logic(plot_options) res = _send_to_plotly(figure, **plot_options) if res['error'] == '': if plot_options['auto_open']: try: from webbrowser import open as wbopen wbopen(res['url']) except: # TODO: what should we except here? this is dangerous pass return res['url'] else: raise exceptions.PlotlyAccountError(res['error'])
def convert_colors_to_same_type(colors, colortype='rgb', scale=None, return_default_colors=False, num_of_defualt_colors=2): """ Converts color(s) to the specified color type Takes a single color or an iterable of colors, as well as a list of scale values, and outputs a 2-pair of the list of color(s) converted all to an rgb or tuple color type, aswell as the scale as the second element. If colors is a Plotly Scale name, then 'scale' will be forced to the scale from the respective colorscale and the colors in that colorscale will also be coverted to the selected colortype. If colors is None, then there is an option to return portion of the DEFAULT_PLOTLY_COLORS :param (str|tuple|list) colors: either a plotly scale name, an rgb or hex color, a color tuple or a list/tuple of colors :param (list) scale: see docs for validate_scale_values() :rtype (tuple) (colors_list, scale) if scale is None in the function call, then scale will remain None in the returned tuple """ #if colors_list is None: colors_list = [] if colors is None and return_default_colors is True: colors_list = DEFAULT_PLOTLY_COLORS[0:num_of_defualt_colors] if isinstance(colors, str): if colors in PLOTLY_SCALES: colors_list = colorscale_to_colors(PLOTLY_SCALES[colors]) if scale is None: scale = colorscale_to_scale(PLOTLY_SCALES[colors]) elif 'rgb' in colors or '#' in colors: colors_list = [colors] elif isinstance(colors, tuple): if isinstance(colors[0], Number): colors_list = [colors] else: colors_list = list(colors) elif isinstance(colors, list): colors_list = colors # validate scale if scale is not None: validate_scale_values(scale) if len(colors_list) != len(scale): raise exceptions.PlotlyError( 'Make sure that the length of your scale matches the length ' 'of your list of colors which is {}.'.format(len(colors_list))) # convert all colors to rgb for j, each_color in enumerate(colors_list): if '#' in each_color: each_color = color_parser(each_color, hex_to_rgb) each_color = color_parser(each_color, label_rgb) colors_list[j] = each_color elif isinstance(each_color, tuple): each_color = color_parser(each_color, convert_to_RGB_255) each_color = color_parser(each_color, label_rgb) colors_list[j] = each_color if colortype == 'rgb': return (colors_list, scale) elif colortype == 'tuple': for j, each_color in enumerate(colors_list): each_color = color_parser(each_color, unlabel_rgb) each_color = color_parser(each_color, unconvert_from_RGB_255) colors_list[j] = each_color return (colors_list, scale) else: raise exceptions.PlotlyError('You must select either rgb or tuple ' 'for your colortype variable.')
def validate_scatterplotmatrix(df, index, diag, colormap_type, **kwargs): """ Validates basic inputs for FigureFactory.create_scatterplotmatrix() :raises: (PlotlyError) If pandas is not imported :raises: (PlotlyError) If pandas dataframe is not inputted :raises: (PlotlyError) If pandas dataframe has <= 1 columns :raises: (PlotlyError) If diagonal plot choice (diag) is not one of the viable options :raises: (PlotlyError) If colormap_type is not a valid choice :raises: (PlotlyError) If kwargs contains 'size', 'color' or 'colorscale' """ if not pd: raise ImportError( "FigureFactory.scatterplotmatrix requires " "a pandas DataFrame." ) # Check if pandas dataframe if not isinstance(df, pd.core.frame.DataFrame): raise exceptions.PlotlyError( "Dataframe not inputed. Please " "use a pandas dataframe to pro" "duce a scatterplot matrix." ) # Check if dataframe is 1 column or less if len(df.columns) <= 1: raise exceptions.PlotlyError( "Dataframe has only one column. To " "use the scatterplot matrix, use at " "least 2 columns." ) # Check that diag parameter is a valid selection if diag not in DIAG_CHOICES: raise exceptions.PlotlyError( "Make sure diag is set to " "one of {}".format(DIAG_CHOICES) ) # Check that colormap_types is a valid selection if colormap_type not in VALID_COLORMAP_TYPES: raise exceptions.PlotlyError( "Must choose a valid colormap type. " "Either 'cat' or 'seq' for a cate" "gorical and sequential colormap " "respectively." ) # Check for not 'size' or 'color' in 'marker' of **kwargs if "marker" in kwargs: FORBIDDEN_PARAMS = ["size", "color", "colorscale"] if any(param in kwargs["marker"] for param in FORBIDDEN_PARAMS): raise exceptions.PlotlyError( "Your kwargs dictionary cannot " "include the 'size', 'color' or " "'colorscale' key words inside " "the marker dict since 'size' is " "already an argument of the " "scatterplot matrix function and " "both 'color' and 'colorscale " "are set internally." )
def create_choropleth(fips, values, scope=['usa'], binning_endpoints=None, colorscale=None, order=None, simplify_county=0.02, simplify_state=0.02, asp=None, show_hover=True, show_state_data=True, state_outline=None, county_outline=None, centroid_marker=None, round_legend_values=False, exponent_format=False, legend_title='', **layout_options): """ Returns figure for county choropleth. Uses data from package_data. :param (list) fips: list of FIPS values which correspond to the con catination of state and county ids. An example is '01001'. :param (list) values: list of numbers/strings which correspond to the fips list. These are the values that will determine how the counties are colored. :param (list) scope: list of states and/or states abbreviations. Fits all states in the camera tightly. Selecting ['usa'] is the equivalent of appending all 50 states into your scope list. Selecting only 'usa' does not include 'Alaska', 'Puerto Rico', 'American Samoa', 'Commonwealth of the Northern Mariana Islands', 'Guam', 'United States Virgin Islands'. These must be added manually to the list. Default = ['usa'] :param (list) binning_endpoints: ascending numbers which implicitly define real number intervals which are used as bins. The colorscale used must have the same number of colors as the number of bins and this will result in a categorical colormap. :param (list) colorscale: a list of colors with length equal to the number of categories of colors. The length must match either all unique numbers in the 'values' list or if endpoints is being used, the number of categories created by the endpoints.\n For example, if binning_endpoints = [4, 6, 8], then there are 4 bins: [-inf, 4), [4, 6), [6, 8), [8, inf) :param (list) order: a list of the unique categories (numbers/bins) in any desired order. This is helpful if you want to order string values to a chosen colorscale. :param (float) simplify_county: determines the simplification factor for the counties. The larger the number, the fewer vertices and edges each polygon has. See http://toblerity.org/shapely/manual.html#object.simplify for more information. Default = 0.02 :param (float) simplify_state: simplifies the state outline polygon. See http://toblerity.org/shapely/manual.html#object.simplify for more information. Default = 0.02 :param (float) asp: the width-to-height aspect ratio for the camera. Default = 2.5 :param (bool) show_hover: show county hover and centroid info :param (bool) show_state_data: reveals state boundary lines :param (dict) state_outline: dict of attributes of the state outline including width and color. See https://plot.ly/python/reference/#scatter-marker-line for all valid params :param (dict) county_outline: dict of attributes of the county outline including width and color. See https://plot.ly/python/reference/#scatter-marker-line for all valid params :param (dict) centroid_marker: dict of attributes of the centroid marker. The centroid markers are invisible by default and appear visible on selection. See https://plot.ly/python/reference/#scatter-marker for all valid params :param (bool) round_legend_values: automatically round the numbers that appear in the legend to the nearest integer. Default = False :param (bool) exponent_format: if set to True, puts numbers in the K, M, B number format. For example 4000.0 becomes 4.0K Default = False :param (str) legend_title: title that appears above the legend :param **layout_options: a **kwargs argument for all layout parameters Example 1: Florida ``` import plotly.plotly as py import plotly.figure_factory as ff import numpy as np import pandas as pd df_sample = pd.read_csv( 'https://raw.githubusercontent.com/plotly/datasets/master/minoritymajority.csv' ) df_sample_r = df_sample[df_sample['STNAME'] == 'Florida'] values = df_sample_r['TOT_POP'].tolist() fips = df_sample_r['FIPS'].tolist() binning_endpoints = list(np.mgrid[min(values):max(values):4j]) colorscale = ["#030512","#1d1d3b","#323268","#3d4b94","#3e6ab0", "#4989bc","#60a7c7","#85c5d3","#b7e0e4","#eafcfd"] fig = ff.create_choropleth( fips=fips, values=values, scope=['Florida'], show_state_data=True, colorscale=colorscale, binning_endpoints=binning_endpoints, round_legend_values=True, plot_bgcolor='rgb(229,229,229)', paper_bgcolor='rgb(229,229,229)', legend_title='Florida Population', county_outline={'color': 'rgb(255,255,255)', 'width': 0.5}, exponent_format=True, ) py.iplot(fig, filename='choropleth_florida') ``` Example 2: New England ``` import plotly.plotly as py import plotly.figure_factory as ff import pandas as pd NE_states = ['Connecticut', 'Maine', 'Massachusetts', 'New Hampshire', 'Rhode Island'] df_sample = pd.read_csv( 'https://raw.githubusercontent.com/plotly/datasets/master/minoritymajority.csv' ) df_sample_r = df_sample[df_sample['STNAME'].isin(NE_states)] colorscale = ['rgb(68.0, 1.0, 84.0)', 'rgb(66.0, 64.0, 134.0)', 'rgb(38.0, 130.0, 142.0)', 'rgb(63.0, 188.0, 115.0)', 'rgb(216.0, 226.0, 25.0)'] values = df_sample_r['TOT_POP'].tolist() fips = df_sample_r['FIPS'].tolist() fig = ff.create_choropleth( fips=fips, values=values, scope=NE_states, show_state_data=True ) py.iplot(fig, filename='choropleth_new_england') ``` Example 3: California and Surrounding States ``` import plotly.plotly as py import plotly.figure_factory as ff import pandas as pd df_sample = pd.read_csv( 'https://raw.githubusercontent.com/plotly/datasets/master/minoritymajority.csv' ) df_sample_r = df_sample[df_sample['STNAME'] == 'California'] values = df_sample_r['TOT_POP'].tolist() fips = df_sample_r['FIPS'].tolist() colorscale = [ 'rgb(193, 193, 193)', 'rgb(239,239,239)', 'rgb(195, 196, 222)', 'rgb(144,148,194)', 'rgb(101,104,168)', 'rgb(65, 53, 132)' ] fig = ff.create_choropleth( fips=fips, values=values, colorscale=colorscale, scope=['CA', 'AZ', 'Nevada', 'Oregon', ' Idaho'], binning_endpoints=[14348, 63983, 134827, 426762, 2081313], county_outline={'color': 'rgb(255,255,255)', 'width': 0.5}, legend_title='California Counties', title='California and Nearby States' ) py.iplot(fig, filename='choropleth_california_and_surr_states_outlines') ``` Example 4: USA ``` import plotly.plotly as py import plotly.figure_factory as ff import numpy as np import pandas as pd df_sample = pd.read_csv( 'https://raw.githubusercontent.com/plotly/datasets/master/laucnty16.csv' ) df_sample['State FIPS Code'] = df_sample['State FIPS Code'].apply( lambda x: str(x).zfill(2) ) df_sample['County FIPS Code'] = df_sample['County FIPS Code'].apply( lambda x: str(x).zfill(3) ) df_sample['FIPS'] = ( df_sample['State FIPS Code'] + df_sample['County FIPS Code'] ) binning_endpoints = list(np.linspace(1, 12, len(colorscale) - 1)) colorscale = ["#f7fbff", "#ebf3fb", "#deebf7", "#d2e3f3", "#c6dbef", "#b3d2e9", "#9ecae1", "#85bcdb", "#6baed6", "#57a0ce", "#4292c6", "#3082be", "#2171b5", "#1361a9", "#08519c", "#0b4083","#08306b"] fips = df_sample['FIPS'] values = df_sample['Unemployment Rate (%)'] fig = ff.create_choropleth( fips=fips, values=values, scope=['usa'], binning_endpoints=binning_endpoints, colorscale=colorscale, show_hover=True, centroid_marker={'opacity': 0}, asp=2.9, title='USA by Unemployment %', legend_title='Unemployment %' ) py.iplot(fig, filename='choropleth_full_usa') ``` """ # ensure optional modules imported if not gp or not shapefile or not shapely: raise ImportError( "geopandas, pyshp and shapely must be installed for this figure " "factory.\n\nRun the following commands to install the correct " "versions of the following modules:\n\n" "```\n" "pip install geopandas==0.3.0\n" "pip install pyshp==1.2.10\n" "pip install shapely==1.6.3\n" "```\n" "If you are using Windows, follow this post to properly " "install geopandas and dependencies:" "http://geoffboeing.com/2014/09/using-geopandas-windows/\n\n" "If you are using Anaconda, do not use PIP to install the " "packages above. Instead use conda to install them:\n\n" "```\n" "conda install plotly\n" "conda install geopandas\n" "```") df, df_state = _create_us_counties_df(st_to_state_name_dict, state_to_st_dict) fips_polygon_map = dict(zip(df['FIPS'].tolist(), df['geometry'].tolist())) if not state_outline: state_outline = {'color': 'rgb(240, 240, 240)', 'width': 1} if not county_outline: county_outline = {'color': 'rgb(0, 0, 0)', 'width': 0} if not centroid_marker: centroid_marker = {'size': 3, 'color': 'white', 'opacity': 1} # ensure centroid markers appear on selection if 'opacity' not in centroid_marker: centroid_marker.update({'opacity': 1}) if len(fips) != len(values): raise exceptions.PlotlyError('fips and values must be the same length') # make fips, values into lists if isinstance(fips, pd.core.series.Series): fips = fips.tolist() if isinstance(values, pd.core.series.Series): values = values.tolist() # make fips numeric fips = map(lambda x: int(x), fips) if binning_endpoints: intervals = utils.endpts_to_intervals(binning_endpoints) LEVELS = _intervals_as_labels(intervals, round_legend_values, exponent_format) else: if not order: LEVELS = sorted(list(set(values))) else: # check if order is permutation # of unique color col values same_sets = sorted(list(set(values))) == set(order) no_duplicates = not any(order.count(x) > 1 for x in order) if same_sets and no_duplicates: LEVELS = order else: raise exceptions.PlotlyError( 'if you are using a custom order of unique values from ' 'your color column, you must: have all the unique values ' 'in your order and have no duplicate items') if not colorscale: colorscale = [] viridis_colors = colors.colorscale_to_colors( colors.PLOTLY_SCALES['Viridis']) viridis_colors = colors.color_parser(viridis_colors, colors.hex_to_rgb) viridis_colors = colors.color_parser(viridis_colors, colors.label_rgb) viri_len = len(viridis_colors) + 1 viri_intervals = utils.endpts_to_intervals( list(np.linspace(0, 1, viri_len)))[1:-1] for L in np.linspace(0, 1, len(LEVELS)): for idx, inter in enumerate(viri_intervals): if L == 0: break elif inter[0] < L <= inter[1]: break intermed = ((L - viri_intervals[idx][0]) / (viri_intervals[idx][1] - viri_intervals[idx][0])) float_color = colors.find_intermediate_color(viridis_colors[idx], viridis_colors[idx], intermed, colortype='rgb') # make R,G,B into int values float_color = colors.unlabel_rgb(float_color) float_color = colors.unconvert_from_RGB_255(float_color) int_rgb = colors.convert_to_RGB_255(float_color) int_rgb = colors.label_rgb(int_rgb) colorscale.append(int_rgb) if len(colorscale) < len(LEVELS): raise exceptions.PlotlyError( "You have {} LEVELS. Your number of colors in 'colorscale' must " "be at least the number of LEVELS: {}. If you are " "using 'binning_endpoints' then 'colorscale' must have at " "least len(binning_endpoints) + 2 colors".format( len(LEVELS), min(LEVELS, LEVELS[:20]))) color_lookup = dict(zip(LEVELS, colorscale)) x_traces = dict(zip(LEVELS, [[] for i in range(len(LEVELS))])) y_traces = dict(zip(LEVELS, [[] for i in range(len(LEVELS))])) # scope if isinstance(scope, str): raise exceptions.PlotlyError("'scope' must be a list/tuple/sequence") scope_names = [] extra_states = [ 'Alaska', 'Commonwealth of the Northern Mariana Islands', 'Puerto Rico', 'Guam', 'United States Virgin Islands', 'American Samoa' ] for state in scope: if state.lower() == 'usa': scope_names = df['STATE_NAME'].unique() scope_names = list(scope_names) for ex_st in extra_states: try: scope_names.remove(ex_st) except ValueError: pass else: if state in st_to_state_name_dict.keys(): state = st_to_state_name_dict[state] scope_names.append(state) df_state = df_state[df_state['STATE_NAME'].isin(scope_names)] plot_data = [] x_centroids = [] y_centroids = [] centroid_text = [] fips_not_in_shapefile = [] if not binning_endpoints: for index, f in enumerate(fips): level = values[index] try: fips_polygon_map[f].type (x_traces, y_traces, x_centroids, y_centroids, centroid_text) = _calculations(df, fips, values, index, f, simplify_county, level, x_centroids, y_centroids, centroid_text, x_traces, y_traces, fips_polygon_map) except KeyError: fips_not_in_shapefile.append(f) else: for index, f in enumerate(fips): for j, inter in enumerate(intervals): if inter[0] < values[index] <= inter[1]: break level = LEVELS[j] try: fips_polygon_map[f].type (x_traces, y_traces, x_centroids, y_centroids, centroid_text) = _calculations(df, fips, values, index, f, simplify_county, level, x_centroids, y_centroids, centroid_text, x_traces, y_traces, fips_polygon_map) except KeyError: fips_not_in_shapefile.append(f) if len(fips_not_in_shapefile) > 0: msg = ('Unrecognized FIPS Values\n\nWhoops! It looks like you are ' 'trying to pass at least one FIPS value that is not in ' 'our shapefile of FIPS and data for the counties. Your ' 'choropleth will still show up but these counties cannot ' 'be shown.\nUnrecognized FIPS are: {}'.format( fips_not_in_shapefile)) warnings.warn(msg) x_states = [] y_states = [] for index, row in df_state.iterrows(): if df_state['geometry'][index].type == 'Polygon': x = row.geometry.simplify(simplify_state).exterior.xy[0].tolist() y = row.geometry.simplify(simplify_state).exterior.xy[1].tolist() x_states = x_states + x y_states = y_states + y elif df_state['geometry'][index].type == 'MultiPolygon': x = ([ poly.simplify(simplify_state).exterior.xy[0].tolist() for poly in df_state['geometry'][index] ]) y = ([ poly.simplify(simplify_state).exterior.xy[1].tolist() for poly in df_state['geometry'][index] ]) for segment in range(len(x)): x_states = x_states + x[segment] y_states = y_states + y[segment] x_states.append(np.nan) y_states.append(np.nan) x_states.append(np.nan) y_states.append(np.nan) for lev in LEVELS: county_data = dict( type='scatter', mode='lines', x=x_traces[lev], y=y_traces[lev], line=county_outline, fill='toself', fillcolor=color_lookup[lev], name=lev, hoverinfo='none', ) plot_data.append(county_data) if show_hover: hover_points = dict(type='scatter', showlegend=False, legendgroup='centroids', x=x_centroids, y=y_centroids, text=centroid_text, name='US Counties', mode='markers', marker={ 'color': 'white', 'opacity': 0 }, hoverinfo='text') centroids_on_select = dict(selected=dict(marker=centroid_marker), unselected=dict(marker=dict(opacity=0))) hover_points.update(centroids_on_select) plot_data.append(hover_points) if show_state_data: state_data = dict(type='scatter', legendgroup='States', line=state_outline, x=x_states, y=y_states, hoverinfo='text', showlegend=False, mode='lines') plot_data.append(state_data) DEFAULT_LAYOUT = dict(hovermode='closest', xaxis=dict(autorange=False, range=USA_XRANGE, showgrid=False, zeroline=False, fixedrange=True, showticklabels=False), yaxis=dict(autorange=False, range=USA_YRANGE, showgrid=False, zeroline=False, fixedrange=True, showticklabels=False), margin=dict(t=40, b=20, r=20, l=20), width=900, height=450, dragmode='select', legend=dict(traceorder='reversed', xanchor='right', yanchor='top', x=1, y=1), annotations=[]) fig = dict(data=plot_data, layout=DEFAULT_LAYOUT) fig['layout'].update(layout_options) fig['layout']['annotations'].append( dict(x=1, y=1.05, xref='paper', yref='paper', xanchor='right', showarrow=False, text='<b>' + legend_title + '</b>')) if len(scope) == 1 and scope[0].lower() == 'usa': xaxis_range_low = -125.0 xaxis_range_high = -55.0 yaxis_range_low = 25.0 yaxis_range_high = 49.0 else: xaxis_range_low = float('inf') xaxis_range_high = float('-inf') yaxis_range_low = float('inf') yaxis_range_high = float('-inf') for trace in fig['data']: if all(isinstance(n, Number) for n in trace['x']): calc_x_min = min(trace['x'] or [float('inf')]) calc_x_max = max(trace['x'] or [float('-inf')]) if calc_x_min < xaxis_range_low: xaxis_range_low = calc_x_min if calc_x_max > xaxis_range_high: xaxis_range_high = calc_x_max if all(isinstance(n, Number) for n in trace['y']): calc_y_min = min(trace['y'] or [float('inf')]) calc_y_max = max(trace['y'] or [float('-inf')]) if calc_y_min < yaxis_range_low: yaxis_range_low = calc_y_min if calc_y_max > yaxis_range_high: yaxis_range_high = calc_y_max # camera zoom fig['layout']['xaxis']['range'] = [xaxis_range_low, xaxis_range_high] fig['layout']['yaxis']['range'] = [yaxis_range_low, yaxis_range_high] # aspect ratio if asp is None: usa_x_range = USA_XRANGE[1] - USA_XRANGE[0] usa_y_range = USA_YRANGE[1] - USA_YRANGE[0] asp = usa_x_range / usa_y_range # based on your figure width = float(fig['layout']['xaxis']['range'][1] - fig['layout']['xaxis']['range'][0]) height = float(fig['layout']['yaxis']['range'][1] - fig['layout']['yaxis']['range'][0]) center = (sum(fig['layout']['xaxis']['range']) / 2., sum(fig['layout']['yaxis']['range']) / 2.) if height / width > (1 / asp): new_width = asp * height fig['layout']['xaxis']['range'][0] = center[0] - new_width * 0.5 fig['layout']['xaxis']['range'][1] = center[0] + new_width * 0.5 else: new_height = (1 / asp) * width fig['layout']['yaxis']['range'][0] = center[1] - new_height * 0.5 fig['layout']['yaxis']['range'][1] = center[1] + new_height * 0.5 return fig
def create_dendrogram( X, orientation="bottom", labels=None, colorscale=None, distfun=None, linkagefun=lambda x: sch.linkage(x, "complete"), hovertext=None, color_threshold=None, ): """ Function that returns a dendrogram Plotly figure object. This is a thin wrapper around scipy.cluster.hierarchy.dendrogram. See also https://dash.plot.ly/dash-bio/clustergram. :param (ndarray) X: Matrix of observations as array of arrays :param (str) orientation: 'top', 'right', 'bottom', or 'left' :param (list) labels: List of axis category labels(observation labels) :param (list) colorscale: Optional colorscale for the dendrogram tree. Requires 8 colors to be specified, the 7th of which is ignored. With scipy>=1.5.0, the 2nd, 3rd and 6th are used twice as often as the others. Given a shorter list, the missing values are replaced with defaults and with a longer list the extra values are ignored. :param (function) distfun: Function to compute the pairwise distance from the observations :param (function) linkagefun: Function to compute the linkage matrix from the pairwise distances :param (list[list]) hovertext: List of hovertext for constituent traces of dendrogram clusters :param (double) color_threshold: Value at which the separation of clusters will be made Example 1: Simple bottom oriented dendrogram >>> from plotly.figure_factory import create_dendrogram >>> import numpy as np >>> X = np.random.rand(10,10) >>> fig = create_dendrogram(X) >>> fig.show() Example 2: Dendrogram to put on the left of the heatmap >>> from plotly.figure_factory import create_dendrogram >>> import numpy as np >>> X = np.random.rand(5,5) >>> names = ['Jack', 'Oxana', 'John', 'Chelsea', 'Mark'] >>> dendro = create_dendrogram(X, orientation='right', labels=names) >>> dendro.update_layout({'width':700, 'height':500}) # doctest: +SKIP >>> dendro.show() Example 3: Dendrogram with Pandas >>> from plotly.figure_factory import create_dendrogram >>> import numpy as np >>> import pandas as pd >>> Index= ['A','B','C','D','E','F','G','H','I','J'] >>> df = pd.DataFrame(abs(np.random.randn(10, 10)), index=Index) >>> fig = create_dendrogram(df, labels=Index) >>> fig.show() """ if not scp or not scs or not sch: raise ImportError("FigureFactory.create_dendrogram requires scipy, \ scipy.spatial and scipy.hierarchy") s = X.shape if len(s) != 2: exceptions.PlotlyError("X should be 2-dimensional array.") if distfun is None: distfun = scs.distance.pdist dendrogram = _Dendrogram( X, orientation, labels, colorscale, distfun=distfun, linkagefun=linkagefun, hovertext=hovertext, color_threshold=color_threshold, ) return graph_objs.Figure(data=dendrogram.data, layout=dendrogram.layout)
def create_annotated_heatmap_of_categorical_data( data_frame=None, x=None, y=None, colorscale='Plasma', font_colors=None, showscale=False, reversescale=False, **kwargs, ): """ Function that creates annotated heatmaps for categorcal data. This function adds annotations to each cell of the heatmap. :param (data_frame) data_frame: DataFrame :param (str|series) x: Name of a column in DataFrame or Series object :param (str|series) y: Name of a column in DataFrame or Series object :param (list|str) colorscale: heatmap colorscale. :param (list) font_colors: List of two color strings: [min_text_color, max_text_color] where min_text_color is applied to annotations for heatmap values < (max_value - min_value)/2. If font_colors is not defined, the colors are defined logically as black or white depending on the heatmap's colorscale. :param (bool) showscale: Display colorscale. Default = False :param (bool) reversescale: Reverse colorscale. Default = False :param kwargs: kwargs passed through plotly.graph_objs.Heatmap. These kwargs describe other attributes about the annotated Heatmap trace such as the colorscale. For more information on valid kwargs call help(plotly.graph_objs.Heatmap) Example 1: Simple annotated heatmap of categorical data with x and y both are series objects >>> import plotly.figure_factory as ff >>> languages = pd.Series(["Germany", "Spanish", "Germany", "French", "Spanish", "French", "French", "Spanish", "Spanish", "French", "Germany"]) >>> levels = pd.Series(["A1", "B1", "A1", "A1", "B1", "C1", "B1", "A1", "C1","A1", "B1"]) >>> fig = ff.create_annotated_heatmap_of_categorical_data(data_frame=None, x=languages, y=levels) >>> fig.show() """ if type(data_frame) != pd.core.frame.DataFrame: if type(x) != pd.core.series.Series: raise exceptions.PlotlyError( "'x' must be a series object or name of a column in 'data_frame'" ) if type(y) != pd.core.series.Series: raise exceptions.PlotlyError( "'y' must be a series object or name of a column in 'data_frame'" ) else: data_frame = pd.concat([x, y], axis=1, keys=["x", "y"]) x = "x" y = "y" else: if x not in data_frame.columns: raise exceptions.PlotlyError( "Value of 'x' is not the name of a column in 'data_frame'. " "Expected one of %s but received: %s" % (str(list(data_frame.columns)), x)) if y not in data_frame.columns: raise exceptions.PlotlyError( "Value of 'y' is not the name of a column in 'data_frame'. " "Expected one of %s but received: %s" % (str(list(data_frame.columns)), y)) print(x, y) if data_frame[x].nunique() + data_frame[y].nunique() > 21: raise exceptions.PlotlyError( "Count of unique values from both `x` and `y` columns should not increase 20 but it is: %s" % (data_frame[x].nunique() + data_frame[y].nunique())) x_unique, y_unique = data_frame[x].unique().tolist(), data_frame[y].unique( ).tolist() z = [] for xs in x_unique: temp = [] for ys in y_unique: temp.append( len(data_frame[(data_frame[x] == xs) & (data_frame[y] == ys)])) z.append(temp) fig = ff.create_annotated_heatmap(z=z, x=y_unique, y=x_unique, colorscale=colorscale, font_colors=font_colors, showscale=showscale, reversescale=reversescale, **kwargs) return fig
def create_facet_grid(df, x=None, y=None, facet_row=None, facet_col=None, color_name=None, colormap=None, color_is_cat=False, facet_row_labels=None, facet_col_labels=None, height=None, width=None, trace_type="scatter", scales="fixed", dtick_x=None, dtick_y=None, show_boxes=True, ggplot2=False, binsize=1, **kwargs): """ Returns figure for facet grid; **this function is deprecated**, since plotly.express functions should be used instead, for example >>> import plotly.express as px >>> tips = px.data.tips() >>> fig = px.scatter(tips, ... x='total_bill', ... y='tip', ... facet_row='sex', ... facet_col='smoker', ... color='size') :param (pd.DataFrame) df: the dataframe of columns for the facet grid. :param (str) x: the name of the dataframe column for the x axis data. :param (str) y: the name of the dataframe column for the y axis data. :param (str) facet_row: the name of the dataframe column that is used to facet the grid into row panels. :param (str) facet_col: the name of the dataframe column that is used to facet the grid into column panels. :param (str) color_name: the name of your dataframe column that will function as the colormap variable. :param (str|list|dict) colormap: the param that determines how the color_name column colors the data. If the dataframe contains numeric data, then a dictionary of colors will group the data categorically while a Plotly Colorscale name or a custom colorscale will treat it numerically. To learn more about colors and types of colormap, run `help(plotly.colors)`. :param (bool) color_is_cat: determines whether a numerical column for the colormap will be treated as categorical (True) or sequential (False). Default = False. :param (str|dict) facet_row_labels: set to either 'name' or a dictionary of all the unique values in the faceting row mapped to some text to show up in the label annotations. If None, labeling works like usual. :param (str|dict) facet_col_labels: set to either 'name' or a dictionary of all the values in the faceting row mapped to some text to show up in the label annotations. If None, labeling works like usual. :param (int) height: the height of the facet grid figure. :param (int) width: the width of the facet grid figure. :param (str) trace_type: decides the type of plot to appear in the facet grid. The options are 'scatter', 'scattergl', 'histogram', 'bar', and 'box'. Default = 'scatter'. :param (str) scales: determines if axes have fixed ranges or not. Valid settings are 'fixed' (all axes fixed), 'free_x' (x axis free only), 'free_y' (y axis free only) or 'free' (both axes free). :param (float) dtick_x: determines the distance between each tick on the x-axis. Default is None which means dtick_x is set automatically. :param (float) dtick_y: determines the distance between each tick on the y-axis. Default is None which means dtick_y is set automatically. :param (bool) show_boxes: draws grey boxes behind the facet titles. :param (bool) ggplot2: draws the facet grid in the style of `ggplot2`. See http://ggplot2.tidyverse.org/reference/facet_grid.html for reference. Default = False :param (int) binsize: groups all data into bins of a given length. :param (dict) kwargs: a dictionary of scatterplot arguments. Examples 1: One Way Faceting >>> import plotly.figure_factory as ff >>> import pandas as pd >>> mpg = pd.read_table('https://raw.githubusercontent.com/plotly/datasets/master/mpg_2017.txt') >>> fig = ff.create_facet_grid( ... mpg, ... x='displ', ... y='cty', ... facet_col='cyl', ... ) >>> fig.show() Example 2: Two Way Faceting >>> import plotly.figure_factory as ff >>> import pandas as pd >>> mpg = pd.read_table('https://raw.githubusercontent.com/plotly/datasets/master/mpg_2017.txt') >>> fig = ff.create_facet_grid( ... mpg, ... x='displ', ... y='cty', ... facet_row='drv', ... facet_col='cyl', ... ) >>> fig.show() Example 3: Categorical Coloring >>> import plotly.figure_factory as ff >>> import pandas as pd >>> mtcars = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/mtcars.csv') >>> mtcars.cyl = mtcars.cyl.astype(str) >>> fig = ff.create_facet_grid( ... mtcars, ... x='mpg', ... y='wt', ... facet_col='cyl', ... color_name='cyl', ... color_is_cat=True, ... ) >>> fig.show() """ if not pd: raise ImportError( "'pandas' must be installed for this figure_factory.") if not isinstance(df, pd.DataFrame): raise exceptions.PlotlyError("You must input a pandas DataFrame.") # make sure all columns are of homogenous datatype utils.validate_dataframe(df) if trace_type in ["scatter", "scattergl"]: if not x or not y: raise exceptions.PlotlyError( "You need to input 'x' and 'y' if you are you are using a " "trace_type of 'scatter' or 'scattergl'.") for key in [x, y, facet_row, facet_col, color_name]: if key is not None: try: df[key] except KeyError: raise exceptions.PlotlyError( "x, y, facet_row, facet_col and color_name must be keys " "in your dataframe.") # autoscale histogram bars if trace_type not in ["scatter", "scattergl"]: scales = "free" # validate scales if scales not in ["fixed", "free_x", "free_y", "free"]: raise exceptions.PlotlyError( "'scales' must be set to 'fixed', 'free_x', 'free_y' and 'free'.") if trace_type not in VALID_TRACE_TYPES: raise exceptions.PlotlyError( "'trace_type' must be in {}".format(VALID_TRACE_TYPES)) if trace_type == "histogram": SUBPLOT_SPACING = 0.06 else: SUBPLOT_SPACING = 0.015 # seperate kwargs for marker and else if "marker" in kwargs: kwargs_marker = kwargs["marker"] else: kwargs_marker = {} marker_color = kwargs_marker.pop("color", None) kwargs.pop("marker", None) kwargs_trace = kwargs if "size" not in kwargs_marker: if ggplot2: kwargs_marker["size"] = 5 else: kwargs_marker["size"] = 8 if "opacity" not in kwargs_marker: if not ggplot2: kwargs_trace["opacity"] = 0.6 if "line" not in kwargs_marker: if not ggplot2: kwargs_marker["line"] = {"color": "darkgrey", "width": 1} else: kwargs_marker["line"] = {} # default marker size if not ggplot2: if not marker_color: marker_color = "rgb(31, 119, 180)" else: marker_color = "rgb(0, 0, 0)" num_of_rows = 1 num_of_cols = 1 flipped_rows = False flipped_cols = False if facet_row: num_of_rows = len(df[facet_row].unique()) flipped_rows = _is_flipped(num_of_rows) if isinstance(facet_row_labels, dict): for key in df[facet_row].unique(): if key not in facet_row_labels.keys(): unique_keys = df[facet_row].unique().tolist() raise exceptions.PlotlyError( CUSTOM_LABEL_ERROR.format(unique_keys)) if facet_col: num_of_cols = len(df[facet_col].unique()) flipped_cols = _is_flipped(num_of_cols) if isinstance(facet_col_labels, dict): for key in df[facet_col].unique(): if key not in facet_col_labels.keys(): unique_keys = df[facet_col].unique().tolist() raise exceptions.PlotlyError( CUSTOM_LABEL_ERROR.format(unique_keys)) show_legend = False if color_name: if isinstance(df[color_name].iloc[0], str) or color_is_cat: show_legend = True if isinstance(colormap, dict): clrs.validate_colors_dict(colormap, "rgb") for val in df[color_name].unique(): if val not in colormap.keys(): raise exceptions.PlotlyError( "If using 'colormap' as a dictionary, make sure " "all the values of the colormap column are in " "the keys of your dictionary.") else: # use default plotly colors for dictionary default_colors = clrs.DEFAULT_PLOTLY_COLORS colormap = {} j = 0 for val in df[color_name].unique(): if j >= len(default_colors): j = 0 colormap[val] = default_colors[j] j += 1 fig, annotations = _facet_grid_color_categorical( df, x, y, facet_row, facet_col, color_name, colormap, num_of_rows, num_of_cols, facet_row_labels, facet_col_labels, trace_type, flipped_rows, flipped_cols, show_boxes, SUBPLOT_SPACING, marker_color, kwargs_trace, kwargs_marker, ) elif isinstance(df[color_name].iloc[0], Number): if isinstance(colormap, dict): show_legend = True clrs.validate_colors_dict(colormap, "rgb") for val in df[color_name].unique(): if val not in colormap.keys(): raise exceptions.PlotlyError( "If using 'colormap' as a dictionary, make sure " "all the values of the colormap column are in " "the keys of your dictionary.") fig, annotations = _facet_grid_color_categorical( df, x, y, facet_row, facet_col, color_name, colormap, num_of_rows, num_of_cols, facet_row_labels, facet_col_labels, trace_type, flipped_rows, flipped_cols, show_boxes, SUBPLOT_SPACING, marker_color, kwargs_trace, kwargs_marker, ) elif isinstance(colormap, list): colorscale_list = colormap clrs.validate_colorscale(colorscale_list) fig, annotations = _facet_grid_color_numerical( df, x, y, facet_row, facet_col, color_name, colorscale_list, num_of_rows, num_of_cols, facet_row_labels, facet_col_labels, trace_type, flipped_rows, flipped_cols, show_boxes, SUBPLOT_SPACING, marker_color, kwargs_trace, kwargs_marker, ) elif isinstance(colormap, str): if colormap in clrs.PLOTLY_SCALES.keys(): colorscale_list = clrs.PLOTLY_SCALES[colormap] else: raise exceptions.PlotlyError( "If 'colormap' is a string, it must be the name " "of a Plotly Colorscale. The available colorscale " "names are {}".format(clrs.PLOTLY_SCALES.keys())) fig, annotations = _facet_grid_color_numerical( df, x, y, facet_row, facet_col, color_name, colorscale_list, num_of_rows, num_of_cols, facet_row_labels, facet_col_labels, trace_type, flipped_rows, flipped_cols, show_boxes, SUBPLOT_SPACING, marker_color, kwargs_trace, kwargs_marker, ) else: colorscale_list = clrs.PLOTLY_SCALES["Reds"] fig, annotations = _facet_grid_color_numerical( df, x, y, facet_row, facet_col, color_name, colorscale_list, num_of_rows, num_of_cols, facet_row_labels, facet_col_labels, trace_type, flipped_rows, flipped_cols, show_boxes, SUBPLOT_SPACING, marker_color, kwargs_trace, kwargs_marker, ) else: fig, annotations = _facet_grid( df, x, y, facet_row, facet_col, num_of_rows, num_of_cols, facet_row_labels, facet_col_labels, trace_type, flipped_rows, flipped_cols, show_boxes, SUBPLOT_SPACING, marker_color, kwargs_trace, kwargs_marker, ) if not height: height = max(600, 100 * num_of_rows) if not width: width = max(600, 100 * num_of_cols) fig["layout"].update(height=height, width=width, title="", paper_bgcolor="rgb(251, 251, 251)") if ggplot2: fig["layout"].update( plot_bgcolor=PLOT_BGCOLOR, paper_bgcolor="rgb(255, 255, 255)", hovermode="closest", ) # axis titles x_title_annot = _axis_title_annotation(x, "x") y_title_annot = _axis_title_annotation(y, "y") # annotations annotations.append(x_title_annot) annotations.append(y_title_annot) # legend fig["layout"]["showlegend"] = show_legend fig["layout"]["legend"]["bgcolor"] = LEGEND_COLOR fig["layout"]["legend"]["borderwidth"] = LEGEND_BORDER_WIDTH fig["layout"]["legend"]["x"] = 1.05 fig["layout"]["legend"]["y"] = 1 fig["layout"]["legend"]["yanchor"] = "top" if show_legend: fig["layout"]["showlegend"] = show_legend if ggplot2: if color_name: legend_annot = _legend_annotation(color_name) annotations.append(legend_annot) fig["layout"]["margin"]["r"] = 150 # assign annotations to figure fig["layout"]["annotations"] = annotations # add shaded boxes behind axis titles if show_boxes and ggplot2: _add_shapes_to_fig(fig, ANNOT_RECT_COLOR, flipped_rows, flipped_cols) # all xaxis and yaxis labels axis_labels = {"x": [], "y": []} for key in fig["layout"]: if "xaxis" in key: axis_labels["x"].append(key) elif "yaxis" in key: axis_labels["y"].append(key) string_number_in_data = False for var in [v for v in [x, y] if v]: if isinstance(df[var].tolist()[0], str): for item in df[var]: try: int(item) string_number_in_data = True except ValueError: pass if string_number_in_data: for x_y in axis_labels.keys(): for axis_name in axis_labels[x_y]: fig["layout"][axis_name]["type"] = "category" if scales == "fixed": fixed_axes = ["x", "y"] elif scales == "free_x": fixed_axes = ["y"] elif scales == "free_y": fixed_axes = ["x"] elif scales == "free": fixed_axes = [] # fixed ranges for x_y in fixed_axes: min_ranges = [] max_ranges = [] for trace in fig["data"]: if trace[x_y] is not None and len(trace[x_y]) > 0: min_ranges.append(min(trace[x_y])) max_ranges.append(max(trace[x_y])) while None in min_ranges: min_ranges.remove(None) while None in max_ranges: max_ranges.remove(None) min_range = min(min_ranges) max_range = max(max_ranges) range_are_numbers = isinstance(min_range, Number) and isinstance( max_range, Number) if range_are_numbers: min_range = math.floor(min_range) max_range = math.ceil(max_range) # extend widen frame by 5% on each side min_range -= 0.05 * (max_range - min_range) max_range += 0.05 * (max_range - min_range) if x_y == "x": if dtick_x: dtick = dtick_x else: dtick = math.floor( (max_range - min_range) / MAX_TICKS_PER_AXIS) elif x_y == "y": if dtick_y: dtick = dtick_y else: dtick = math.floor( (max_range - min_range) / MAX_TICKS_PER_AXIS) else: dtick = 1 for axis_title in axis_labels[x_y]: fig["layout"][axis_title]["dtick"] = dtick fig["layout"][axis_title]["ticklen"] = 0 fig["layout"][axis_title]["zeroline"] = False if ggplot2: fig["layout"][axis_title]["tickwidth"] = 1 fig["layout"][axis_title]["ticklen"] = 4 fig["layout"][axis_title]["gridwidth"] = GRID_WIDTH fig["layout"][axis_title]["gridcolor"] = GRID_COLOR fig["layout"][axis_title]["gridwidth"] = 2 fig["layout"][axis_title]["tickfont"] = { "color": TICK_COLOR, "size": 10, } # insert ranges into fig if x_y in fixed_axes: for key in fig["layout"]: if "{}axis".format(x_y) in key and range_are_numbers: fig["layout"][key]["range"] = [min_range, max_range] return fig
def __setattr__(self, key, value): raise exceptions.PlotlyError('Setting attributes on a PlotlyList is ' 'not allowed')
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 = list({chart[row][index_col] for row in range(len(tasks))}) 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_dendrogram( X, orientation="bottom", labels=None, colorscale=None, distfun=None, linkagefun=lambda x: sch.linkage(x, "complete"), hovertext=None, color_threshold=None, ): """ BETA function that returns a dendrogram Plotly figure object. :param (ndarray) X: Matrix of observations as array of arrays :param (str) orientation: 'top', 'right', 'bottom', or 'left' :param (list) labels: List of axis category labels(observation labels) :param (list) colorscale: Optional colorscale for dendrogram tree :param (function) distfun: Function to compute the pairwise distance from the observations :param (function) linkagefun: Function to compute the linkage matrix from the pairwise distances :param (list[list]) hovertext: List of hovertext for constituent traces of dendrogram clusters :param (double) color_threshold: Value at which the separation of clusters will be made Example 1: Simple bottom oriented dendrogram ``` import plotly.plotly as py from plotly.figure_factory import create_dendrogram import numpy as np X = np.random.rand(10,10) dendro = create_dendrogram(X) plot_url = py.plot(dendro, filename='simple-dendrogram') ``` Example 2: Dendrogram to put on the left of the heatmap ``` import plotly.plotly as py from plotly.figure_factory import create_dendrogram import numpy as np X = np.random.rand(5,5) names = ['Jack', 'Oxana', 'John', 'Chelsea', 'Mark'] dendro = create_dendrogram(X, orientation='right', labels=names) dendro['layout'].update({'width':700, 'height':500}) py.iplot(dendro, filename='vertical-dendrogram') ``` Example 3: Dendrogram with Pandas ``` import plotly.plotly as py from plotly.figure_factory import create_dendrogram import numpy as np import pandas as pd Index= ['A','B','C','D','E','F','G','H','I','J'] df = pd.DataFrame(abs(np.random.randn(10, 10)), index=Index) fig = create_dendrogram(df, labels=Index) url = py.plot(fig, filename='pandas-dendrogram') ``` """ if not scp or not scs or not sch: raise ImportError("FigureFactory.create_dendrogram requires scipy, \ scipy.spatial and scipy.hierarchy") s = X.shape if len(s) != 2: exceptions.PlotlyError("X should be 2-dimensional array.") if distfun is None: distfun = scs.distance.pdist dendrogram = _Dendrogram( X, orientation, labels, colorscale, distfun=distfun, linkagefun=linkagefun, hovertext=hovertext, color_threshold=color_threshold, ) return graph_objs.Figure(data=dendrogram.data, layout=dendrogram.layout)
def violin_colorscale(data, data_header, group_header, colors, use_colorscale, group_stats, rugplot, sort, height, width, title): """ Refer to FigureFactory.create_violin() for docstring. Returns fig for violin plot with colorscale. """ # collect all group names group_name = [] for name in data[group_header]: if name not in group_name: group_name.append(name) if sort: group_name.sort() # make sure all group names are keys in group_stats for group in group_name: if group not in group_stats: raise exceptions.PlotlyError("All values/groups in the index " "column must be represented " "as a key in group_stats.") gb = data.groupby([group_header]) L = len(group_name) fig = make_subplots(rows=1, cols=L, shared_yaxes=True, horizontal_spacing=0.025, print_grid=False) # prepare low and high color for colorscale lowcolor = clrs.color_parser(colors[0], clrs.unlabel_rgb) highcolor = clrs.color_parser(colors[1], clrs.unlabel_rgb) # find min and max values in group_stats group_stats_values = [] for key in group_stats: group_stats_values.append(group_stats[key]) max_value = max(group_stats_values) min_value = min(group_stats_values) for k, gr in enumerate(group_name): vals = np.asarray(gb.get_group(gr)[data_header], np.float) # find intermediate color from colorscale intermed = (group_stats[gr] - min_value) / (max_value - min_value) intermed_color = clrs.find_intermediate_color(lowcolor, highcolor, intermed) plot_data, plot_xrange = violinplot( vals, fillcolor='rgb{}'.format(intermed_color), rugplot=rugplot) layout = graph_objs.Layout() for item in plot_data: fig.append_trace(item, 1, k + 1) fig['layout'].update( {'xaxis{}'.format(k + 1): make_XAxis(group_name[k], plot_xrange)}) # add colorbar to plot trace_dummy = graph_objs.Scatter( x=[0], y=[0], mode='markers', marker=dict(size=2, cmin=min_value, cmax=max_value, colorscale=[[0, colors[0]], [1, colors[1]]], showscale=True), showlegend=False, ) fig.append_trace(trace_dummy, 1, L) # set the sharey axis style fig['layout'].update({'yaxis{}'.format(1): make_YAxis('')}) fig['layout'].update(title=title, showlegend=False, hovermode='closest', autosize=False, height=height, width=width) return fig
def map_face2color(face, colormap, scale, vmin, vmax): """ Normalize facecolor values by vmin/vmax and return rgb-color strings This function takes a tuple color along with a colormap and a minimum (vmin) and maximum (vmax) range of possible mean distances for the given parametrized surface. It returns an rgb color based on the mean distance between vmin and vmax """ if vmin >= vmax: raise exceptions.PlotlyError( "Incorrect relation between vmin " "and vmax. The vmin value cannot be " "bigger than or equal to the value " "of vmax." ) if len(colormap) == 1: # color each triangle face with the same color in colormap face_color = colormap[0] face_color = clrs.convert_to_RGB_255(face_color) face_color = clrs.label_rgb(face_color) return face_color if face == vmax: # pick last color in colormap face_color = colormap[-1] face_color = clrs.convert_to_RGB_255(face_color) face_color = clrs.label_rgb(face_color) return face_color else: if scale is None: # find the normalized distance t of a triangle face between # vmin and vmax where the distance is between 0 and 1 t = (face - vmin) / float((vmax - vmin)) low_color_index = int(t / (1.0 / (len(colormap) - 1))) face_color = clrs.find_intermediate_color( colormap[low_color_index], colormap[low_color_index + 1], t * (len(colormap) - 1) - low_color_index, ) face_color = clrs.convert_to_RGB_255(face_color) face_color = clrs.label_rgb(face_color) else: # find the face color for a non-linearly interpolated scale t = (face - vmin) / float((vmax - vmin)) low_color_index = 0 for k in range(len(scale) - 1): if scale[k] <= t < scale[k + 1]: break low_color_index += 1 low_scale_val = scale[low_color_index] high_scale_val = scale[low_color_index + 1] face_color = clrs.find_intermediate_color( colormap[low_color_index], colormap[low_color_index + 1], (t - low_scale_val) / (high_scale_val - low_scale_val), ) face_color = clrs.convert_to_RGB_255(face_color) face_color = clrs.label_rgb(face_color) return face_color
def create_scatterplotmatrix( df, index=None, endpts=None, diag="scatter", height=500, width=500, size=6, title="Scatterplot Matrix", colormap=None, colormap_type="cat", dataframe=None, headers=None, index_vals=None, **kwargs, ): """ Returns data for a scatterplot matrix; **deprecated**, use instead the plotly.graph_objects trace :class:`plotly.graph_objects.Splom`. :param (array) df: array of the data with column headers :param (str) index: name of the index column in data array :param (list|tuple) endpts: takes an increasing sequece of numbers that defines intervals on the real line. They are used to group the entries in an index of numbers into their corresponding interval and therefore can be treated as categorical data :param (str) diag: sets the chart type for the main diagonal plots. The options are 'scatter', 'histogram' and 'box'. :param (int|float) height: sets the height of the chart :param (int|float) width: sets the width of the chart :param (float) size: sets the marker size (in px) :param (str) title: the title label of the scatterplot matrix :param (str|tuple|list|dict) colormap: either a plotly scale name, an rgb or hex color, a color tuple, a list of colors or a dictionary. An rgb color is of the form 'rgb(x, y, z)' where x, y and 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 colormap is a list, it must contain valid color types as its members. If colormap is a dictionary, all the string entries in the index column must be a key in colormap. In this case, the colormap_type is forced to 'cat' or categorical :param (str) colormap_type: determines how colormap is interpreted. Valid choices are 'seq' (sequential) and 'cat' (categorical). If 'seq' is selected, only the first two colors in colormap will be considered (when colormap is a list) and the index values will be linearly interpolated between those two colors. This option is forced if all index values are numeric. If 'cat' is selected, a color from colormap will be assigned to each category from index, including the intervals if endpts is being used :param (dict) **kwargs: a dictionary of scatterplot arguments The only forbidden parameters are 'size', 'color' and 'colorscale' in 'marker' Example 1: Vanilla Scatterplot Matrix >>> from plotly.graph_objs import graph_objs >>> from plotly.figure_factory import create_scatterplotmatrix >>> import numpy as np >>> import pandas as pd >>> # Create dataframe >>> df = pd.DataFrame(np.random.randn(10, 2), ... columns=['Column 1', 'Column 2']) >>> # Create scatterplot matrix >>> fig = create_scatterplotmatrix(df) >>> fig.show() Example 2: Indexing a Column >>> from plotly.graph_objs import graph_objs >>> from plotly.figure_factory import create_scatterplotmatrix >>> import numpy as np >>> import pandas as pd >>> # Create dataframe with index >>> df = pd.DataFrame(np.random.randn(10, 2), ... columns=['A', 'B']) >>> # Add another column of strings to the dataframe >>> df['Fruit'] = pd.Series(['apple', 'apple', 'grape', 'apple', 'apple', ... 'grape', 'pear', 'pear', 'apple', 'pear']) >>> # Create scatterplot matrix >>> fig = create_scatterplotmatrix(df, index='Fruit', size=10) >>> fig.show() Example 3: Styling the Diagonal Subplots >>> from plotly.graph_objs import graph_objs >>> from plotly.figure_factory import create_scatterplotmatrix >>> import numpy as np >>> import pandas as pd >>> # Create dataframe with index >>> df = pd.DataFrame(np.random.randn(10, 4), ... columns=['A', 'B', 'C', 'D']) >>> # Add another column of strings to the dataframe >>> df['Fruit'] = pd.Series(['apple', 'apple', 'grape', 'apple', 'apple', ... 'grape', 'pear', 'pear', 'apple', 'pear']) >>> # Create scatterplot matrix >>> fig = create_scatterplotmatrix(df, diag='box', index='Fruit', height=1000, ... width=1000) >>> fig.show() Example 4: Use a Theme to Style the Subplots >>> from plotly.graph_objs import graph_objs >>> from plotly.figure_factory import create_scatterplotmatrix >>> import numpy as np >>> import pandas as pd >>> # Create dataframe with random data >>> df = pd.DataFrame(np.random.randn(100, 3), ... columns=['A', 'B', 'C']) >>> # Create scatterplot matrix using a built-in >>> # Plotly palette scale and indexing column 'A' >>> fig = create_scatterplotmatrix(df, diag='histogram', index='A', ... colormap='Blues', height=800, width=800) >>> fig.show() Example 5: Example 4 with Interval Factoring >>> from plotly.graph_objs import graph_objs >>> from plotly.figure_factory import create_scatterplotmatrix >>> import numpy as np >>> import pandas as pd >>> # Create dataframe with random data >>> df = pd.DataFrame(np.random.randn(100, 3), ... columns=['A', 'B', 'C']) >>> # Create scatterplot matrix using a list of 2 rgb tuples >>> # and endpoints at -1, 0 and 1 >>> fig = create_scatterplotmatrix(df, diag='histogram', index='A', ... colormap=['rgb(140, 255, 50)', ... 'rgb(170, 60, 115)', '#6c4774', ... (0.5, 0.1, 0.8)], ... endpts=[-1, 0, 1], height=800, width=800) >>> fig.show() Example 6: Using the colormap as a Dictionary >>> from plotly.graph_objs import graph_objs >>> from plotly.figure_factory import create_scatterplotmatrix >>> import numpy as np >>> import pandas as pd >>> import random >>> # Create dataframe with random data >>> df = pd.DataFrame(np.random.randn(100, 3), ... columns=['Column A', ... 'Column B', ... 'Column C']) >>> # Add new color column to dataframe >>> new_column = [] >>> strange_colors = ['turquoise', 'limegreen', 'goldenrod'] >>> for j in range(100): ... new_column.append(random.choice(strange_colors)) >>> df['Colors'] = pd.Series(new_column, index=df.index) >>> # Create scatterplot matrix using a dictionary of hex color values >>> # which correspond to actual color names in 'Colors' column >>> fig = create_scatterplotmatrix( ... df, diag='box', index='Colors', ... colormap= dict( ... turquoise = '#00F5FF', ... limegreen = '#32CD32', ... goldenrod = '#DAA520' ... ), ... colormap_type='cat', ... height=800, width=800 ... ) >>> fig.show() """ # TODO: protected until #282 if dataframe is None: dataframe = [] if headers is None: headers = [] if index_vals is None: index_vals = [] validate_scatterplotmatrix(df, index, diag, colormap_type, **kwargs) # Validate colormap if isinstance(colormap, dict): colormap = clrs.validate_colors_dict(colormap, "rgb") elif (isinstance(colormap, six.string_types) and "rgb" not in colormap and "#" not in colormap): if colormap not in clrs.PLOTLY_SCALES.keys(): raise exceptions.PlotlyError( "If 'colormap' is a string, it must be the name " "of a Plotly Colorscale. The available colorscale " "names are {}".format(clrs.PLOTLY_SCALES.keys())) else: # TODO change below to allow the correct Plotly colorscale colormap = clrs.colorscale_to_colors(clrs.PLOTLY_SCALES[colormap]) # keep only first and last item - fix later colormap = [colormap[0]] + [colormap[-1]] colormap = clrs.validate_colors(colormap, "rgb") else: colormap = clrs.validate_colors(colormap, "rgb") if not index: for name in df: headers.append(name) for name in headers: dataframe.append(df[name].values.tolist()) # Check for same data-type in df columns utils.validate_dataframe(dataframe) figure = scatterplot(dataframe, headers, diag, size, height, width, title, **kwargs) return figure else: # Validate index selection if index not in df: raise exceptions.PlotlyError("Make sure you set the index " "input variable to one of the " "column names of your " "dataframe.") index_vals = df[index].values.tolist() for name in df: if name != index: headers.append(name) for name in headers: dataframe.append(df[name].values.tolist()) # check for same data-type in each df column utils.validate_dataframe(dataframe) utils.validate_index(index_vals) # check if all colormap keys are in the index # if colormap is a dictionary if isinstance(colormap, dict): for key in colormap: if not all(index in colormap for index in index_vals): raise exceptions.PlotlyError("If colormap is a " "dictionary, all the " "names in the index " "must be keys.") figure = scatterplot_dict( dataframe, headers, diag, size, height, width, title, index, index_vals, endpts, colormap, colormap_type, **kwargs, ) return figure else: figure = scatterplot_theme( dataframe, headers, diag, size, height, width, title, index, index_vals, endpts, colormap, colormap_type, **kwargs, ) return figure
def create_scatterplotmatrix(df, index=None, endpts=None, diag='scatter', height=500, width=500, size=6, title='Scatterplot Matrix', colormap=None, colormap_type='cat', dataframe=None, headers=None, index_vals=None, **kwargs): """ Returns data for a scatterplot matrix. :param (array) df: array of the data with column headers :param (str) index: name of the index column in data array :param (list|tuple) endpts: takes an increasing sequece of numbers that defines intervals on the real line. They are used to group the entries in an index of numbers into their corresponding interval and therefore can be treated as categorical data :param (str) diag: sets the chart type for the main diagonal plots. The options are 'scatter', 'histogram' and 'box'. :param (int|float) height: sets the height of the chart :param (int|float) width: sets the width of the chart :param (float) size: sets the marker size (in px) :param (str) title: the title label of the scatterplot matrix :param (str|tuple|list|dict) colormap: either a plotly scale name, an rgb or hex color, a color tuple, a list of colors or a dictionary. An rgb color is of the form 'rgb(x, y, z)' where x, y and 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 colormap is a list, it must contain valid color types as its members. If colormap is a dictionary, all the string entries in the index column must be a key in colormap. In this case, the colormap_type is forced to 'cat' or categorical :param (str) colormap_type: determines how colormap is interpreted. Valid choices are 'seq' (sequential) and 'cat' (categorical). If 'seq' is selected, only the first two colors in colormap will be considered (when colormap is a list) and the index values will be linearly interpolated between those two colors. This option is forced if all index values are numeric. If 'cat' is selected, a color from colormap will be assigned to each category from index, including the intervals if endpts is being used :param (dict) **kwargs: a dictionary of scatterplot arguments The only forbidden parameters are 'size', 'color' and 'colorscale' in 'marker' Example 1: Vanilla Scatterplot Matrix ``` import plotly.plotly as py from plotly.graph_objs import graph_objs from plotly.figure_factory import create_scatterplotmatrix import numpy as np import pandas as pd # Create dataframe df = pd.DataFrame(np.random.randn(10, 2), columns=['Column 1', 'Column 2']) # Create scatterplot matrix fig = create_scatterplotmatrix(df) # Plot py.iplot(fig, filename='Vanilla Scatterplot Matrix') ``` Example 2: Indexing a Column ``` import plotly.plotly as py from plotly.graph_objs import graph_objs from plotly.figure_factory import create_scatterplotmatrix import numpy as np import pandas as pd # Create dataframe with index df = pd.DataFrame(np.random.randn(10, 2), columns=['A', 'B']) # Add another column of strings to the dataframe df['Fruit'] = pd.Series(['apple', 'apple', 'grape', 'apple', 'apple', 'grape', 'pear', 'pear', 'apple', 'pear']) # Create scatterplot matrix fig = create_scatterplotmatrix(df, index='Fruit', size=10) # Plot py.iplot(fig, filename = 'Scatterplot Matrix with Index') ``` Example 3: Styling the Diagonal Subplots ``` import plotly.plotly as py from plotly.graph_objs import graph_objs from plotly.figure_factory import create_scatterplotmatrix import numpy as np import pandas as pd # Create dataframe with index df = pd.DataFrame(np.random.randn(10, 4), columns=['A', 'B', 'C', 'D']) # Add another column of strings to the dataframe df['Fruit'] = pd.Series(['apple', 'apple', 'grape', 'apple', 'apple', 'grape', 'pear', 'pear', 'apple', 'pear']) # Create scatterplot matrix fig = create_scatterplotmatrix(df, diag='box', index='Fruit', height=1000, width=1000) # Plot py.iplot(fig, filename = 'Scatterplot Matrix - Diagonal Styling') ``` Example 4: Use a Theme to Style the Subplots ``` import plotly.plotly as py from plotly.graph_objs import graph_objs from plotly.figure_factory import create_scatterplotmatrix import numpy as np import pandas as pd # Create dataframe with random data df = pd.DataFrame(np.random.randn(100, 3), columns=['A', 'B', 'C']) # Create scatterplot matrix using a built-in # Plotly palette scale and indexing column 'A' fig = create_scatterplotmatrix(df, diag='histogram', index='A', colormap='Blues', height=800, width=800) # Plot py.iplot(fig, filename = 'Scatterplot Matrix - Colormap Theme') ``` Example 5: Example 4 with Interval Factoring ``` import plotly.plotly as py from plotly.graph_objs import graph_objs from plotly.figure_factory import create_scatterplotmatrix import numpy as np import pandas as pd # Create dataframe with random data df = pd.DataFrame(np.random.randn(100, 3), columns=['A', 'B', 'C']) # Create scatterplot matrix using a list of 2 rgb tuples # and endpoints at -1, 0 and 1 fig = create_scatterplotmatrix(df, diag='histogram', index='A', colormap=['rgb(140, 255, 50)', 'rgb(170, 60, 115)', '#6c4774', (0.5, 0.1, 0.8)], endpts=[-1, 0, 1], height=800, width=800) # Plot py.iplot(fig, filename = 'Scatterplot Matrix - Intervals') ``` Example 6: Using the colormap as a Dictionary ``` import plotly.plotly as py from plotly.graph_objs import graph_objs from plotly.figure_factory import create_scatterplotmatrix import numpy as np import pandas as pd import random # Create dataframe with random data df = pd.DataFrame(np.random.randn(100, 3), columns=['Column A', 'Column B', 'Column C']) # Add new color column to dataframe new_column = [] strange_colors = ['turquoise', 'limegreen', 'goldenrod'] for j in range(100): new_column.append(random.choice(strange_colors)) df['Colors'] = pd.Series(new_column, index=df.index) # Create scatterplot matrix using a dictionary of hex color values # which correspond to actual color names in 'Colors' column fig = create_scatterplotmatrix( df, diag='box', index='Colors', colormap= dict( turquoise = '#00F5FF', limegreen = '#32CD32', goldenrod = '#DAA520' ), colormap_type='cat', height=800, width=800 ) # Plot py.iplot(fig, filename = 'Scatterplot Matrix - colormap dictionary ') ``` """ # TODO: protected until #282 if dataframe is None: dataframe = [] if headers is None: headers = [] if index_vals is None: index_vals = [] validate_scatterplotmatrix(df, index, diag, colormap_type, **kwargs) # Validate colormap if isinstance(colormap, dict): colormap = utils.validate_colors_dict(colormap, 'rgb') else: colormap = utils.validate_colors(colormap, 'rgb') if not index: for name in df: headers.append(name) for name in headers: dataframe.append(df[name].values.tolist()) # Check for same data-type in df columns utils.validate_dataframe(dataframe) figure = scatterplot(dataframe, headers, diag, size, height, width, title, **kwargs) return figure else: # Validate index selection if index not in df: raise exceptions.PlotlyError("Make sure you set the index " "input variable to one of the " "column names of your " "dataframe.") index_vals = df[index].values.tolist() for name in df: if name != index: headers.append(name) for name in headers: dataframe.append(df[name].values.tolist()) # check for same data-type in each df column utils.validate_dataframe(dataframe) utils.validate_index(index_vals) # check if all colormap keys are in the index # if colormap is a dictionary if isinstance(colormap, dict): for key in colormap: if not all(index in colormap for index in index_vals): raise exceptions.PlotlyError("If colormap is a " "dictionary, all the " "names in the index " "must be keys.") figure = scatterplot_dict(dataframe, headers, diag, size, height, width, title, index, index_vals, endpts, colormap, colormap_type, **kwargs) return figure else: figure = scatterplot_theme(dataframe, headers, diag, size, height, width, title, index, index_vals, endpts, colormap, colormap_type, **kwargs) return figure
def get(figure_or_data, format='png', width=None, height=None): """ Return a static image of the plot described by `figure`. Valid formats: 'png', 'svg', 'jpeg', 'pdf' """ if isinstance(figure_or_data, dict): figure = figure_or_data elif isinstance(figure_or_data, list): figure = {'data': figure_or_data} if format not in ['png', 'svg', 'jpeg', 'pdf']: raise exceptions.PlotlyError( "Invalid format. " "This version of your Plotly-Python " "package currently only supports " "png, svg, jpeg, and pdf. " "Learn more about image exporting, " "and the currently supported file " "types here: " "https://plot.ly/python/static-image-export/") (username, api_key) = _validation_key_logic() headers = { 'plotly-username': username, 'plotly-apikey': api_key, 'plotly-version': version.__version__, 'plotly-platform': 'python' } payload = {'figure': figure, 'format': format} if width is not None: payload['width'] = width if height is not None: payload['height'] = height url = tools.get_config_file()['plotly_domain'] + "/apigenimage/" res = requests.post(url, data=json.dumps(payload, cls=utils._plotlyJSONEncoder), headers=headers) headers = res.headers if res.status_code == 200: if ('content-type' in headers and headers['content-type'] in [ 'image/png', 'image/jpeg', 'application/pdf', 'image/svg+xml' ]): return res.content elif ('content-type' in headers and 'json' in headers['content-type']): return_data = json.loads(res.content) return return_data['image'] else: try: if ('content-type' in headers and 'json' in headers['content-type']): return_data = json.loads(res.content) else: return_data = {'error': res.content} except: raise exceptions.PlotlyError("The response " "from plotly could " "not be translated.") raise exceptions.PlotlyError(return_data['error'])
def create_facet_grid(df, x=None, y=None, facet_row=None, facet_col=None, color_name=None, colormap=None, color_is_cat=False, facet_row_labels=None, facet_col_labels=None, height=None, width=None, trace_type='scatter', scales='fixed', dtick_x=None, dtick_y=None, show_boxes=True, ggplot2=False, binsize=1, **kwargs): """ Returns figure for facet grid. :param (pd.DataFrame) df: the dataframe of columns for the facet grid. :param (str) x: the name of the dataframe column for the x axis data. :param (str) y: the name of the dataframe column for the y axis data. :param (str) facet_row: the name of the dataframe column that is used to facet the grid into row panels. :param (str) facet_col: the name of the dataframe column that is used to facet the grid into column panels. :param (str) color_name: the name of your dataframe column that will function as the colormap variable. :param (str|list|dict) colormap: the param that determines how the color_name column colors the data. If the dataframe contains numeric data, then a dictionary of colors will group the data categorically while a Plotly Colorscale name or a custom colorscale will treat it numerically. To learn more about colors and types of colormap, run `help(plotly.colors)`. :param (bool) color_is_cat: determines whether a numerical column for the colormap will be treated as categorical (True) or sequential (False). Default = False. :param (str|dict) facet_row_labels: set to either 'name' or a dictionary of all the unique values in the faceting row mapped to some text to show up in the label annotations. If None, labeling works like usual. :param (str|dict) facet_col_labels: set to either 'name' or a dictionary of all the values in the faceting row mapped to some text to show up in the label annotations. If None, labeling works like usual. :param (int) height: the height of the facet grid figure. :param (int) width: the width of the facet grid figure. :param (str) trace_type: decides the type of plot to appear in the facet grid. The options are 'scatter', 'scattergl', 'histogram', 'bar', and 'box'. Default = 'scatter'. :param (str) scales: determines if axes have fixed ranges or not. Valid settings are 'fixed' (all axes fixed), 'free_x' (x axis free only), 'free_y' (y axis free only) or 'free' (both axes free). :param (float) dtick_x: determines the distance between each tick on the x-axis. Default is None which means dtick_x is set automatically. :param (float) dtick_y: determines the distance between each tick on the y-axis. Default is None which means dtick_y is set automatically. :param (bool) show_boxes: draws grey boxes behind the facet titles. :param (bool) ggplot2: draws the facet grid in the style of `ggplot2`. See http://ggplot2.tidyverse.org/reference/facet_grid.html for reference. Default = False :param (int) binsize: groups all data into bins of a given length. :param (dict) kwargs: a dictionary of scatterplot arguments. Examples 1: One Way Faceting ``` import plotly.plotly as py import plotly.figure_factory as ff import pandas as pd mpg = pd.read_table('https://raw.githubusercontent.com/plotly/datasets/master/mpg_2017.txt') fig = ff.create_facet_grid( mpg, x='displ', y='cty', facet_col='cyl', ) py.iplot(fig, filename='facet_grid_mpg_one_way_facet') ``` Example 2: Two Way Faceting ``` import plotly.plotly as py import plotly.figure_factory as ff import pandas as pd mpg = pd.read_table('https://raw.githubusercontent.com/plotly/datasets/master/mpg_2017.txt') fig = ff.create_facet_grid( mpg, x='displ', y='cty', facet_row='drv', facet_col='cyl', ) py.iplot(fig, filename='facet_grid_mpg_two_way_facet') ``` Example 3: Categorical Coloring ``` import plotly.plotly as py import plotly.figure_factory as ff import pandas as pd mpg = pd.read_table('https://raw.githubusercontent.com/plotly/datasets/master/mpg_2017.txt') fig = ff.create_facet_grid( mtcars, x='mpg', y='wt', facet_col='cyl', color_name='cyl', color_is_cat=True, ) py.iplot(fig, filename='facet_grid_mpg_default_colors') ``` Example 4: Sequential Coloring ``` import plotly.plotly as py import plotly.figure_factory as ff import pandas as pd tips = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/tips.csv') fig = ff.create_facet_grid( tips, x='total_bill', y='tip', facet_row='sex', facet_col='smoker', color_name='size', colormap='Viridis', ) py.iplot(fig, filename='facet_grid_tips_sequential_colors') ``` Example 5: Custom labels ``` import plotly.plotly as py import plotly.figure_factory as ff import pandas as pd mtcars = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/mtcars.csv') fig = ff.create_facet_grid( mtcars, x='wt', y='mpg', facet_col='cyl', facet_col_labels={4: "$\\alpha$", 6: '$\\beta$', 8: '$\sqrt[y]{x}$'}, ) py.iplot(fig, filename='facet_grid_mtcars_custom_labels') ``` Example 6: Other Trace Type ``` import plotly.plotly as py import plotly.figure_factory as ff import pandas as pd mtcars = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/mtcars.csv') fig = ff.create_facet_grid( mtcars, x='wt', facet_col='cyl', trace_type='histogram', ) py.iplot(fig, filename='facet_grid_mtcars_other_trace_type') ``` """ if not pd: raise exceptions.ImportError( "'pandas' must be imported for this figure_factory.") if not isinstance(df, pd.DataFrame): raise exceptions.PlotlyError("You must input a pandas DataFrame.") # make sure all columns are of homogenous datatype utils.validate_dataframe(df) if trace_type in ['scatter', 'scattergl']: if not x or not y: raise exceptions.PlotlyError( "You need to input 'x' and 'y' if you are you are using a " "trace_type of 'scatter' or 'scattergl'.") for key in [x, y, facet_row, facet_col, color_name]: if key is not None: try: df[key] except KeyError: raise exceptions.PlotlyError( "x, y, facet_row, facet_col and color_name must be keys " "in your dataframe.") # autoscale histogram bars if trace_type not in ['scatter', 'scattergl']: scales = 'free' # validate scales if scales not in ['fixed', 'free_x', 'free_y', 'free']: raise exceptions.PlotlyError( "'scales' must be set to 'fixed', 'free_x', 'free_y' and 'free'.") if trace_type not in VALID_TRACE_TYPES: raise exceptions.PlotlyError( "'trace_type' must be in {}".format(VALID_TRACE_TYPES)) if trace_type == 'histogram': SUBPLOT_SPACING = 0.06 else: SUBPLOT_SPACING = 0.015 # seperate kwargs for marker and else if 'marker' in kwargs: kwargs_marker = kwargs['marker'] else: kwargs_marker = {} marker_color = kwargs_marker.pop('color', None) kwargs.pop('marker', None) kwargs_trace = kwargs if 'size' not in kwargs_marker: if ggplot2: kwargs_marker['size'] = 5 else: kwargs_marker['size'] = 8 if 'opacity' not in kwargs_marker: if not ggplot2: kwargs_trace['opacity'] = 0.6 if 'line' not in kwargs_marker: if not ggplot2: kwargs_marker['line'] = {'color': 'darkgrey', 'width': 1} else: kwargs_marker['line'] = {} # default marker size if not ggplot2: if not marker_color: marker_color = 'rgb(31, 119, 180)' else: marker_color = 'rgb(0, 0, 0)' num_of_rows = 1 num_of_cols = 1 flipped_rows = False flipped_cols = False if facet_row: num_of_rows = len(df[facet_row].unique()) flipped_rows = _is_flipped(num_of_rows) if isinstance(facet_row_labels, dict): for key in df[facet_row].unique(): if key not in facet_row_labels.keys(): unique_keys = df[facet_row].unique().tolist() raise exceptions.PlotlyError( CUSTOM_LABEL_ERROR.format(unique_keys)) if facet_col: num_of_cols = len(df[facet_col].unique()) flipped_cols = _is_flipped(num_of_cols) if isinstance(facet_col_labels, dict): for key in df[facet_col].unique(): if key not in facet_col_labels.keys(): unique_keys = df[facet_col].unique().tolist() raise exceptions.PlotlyError( CUSTOM_LABEL_ERROR.format(unique_keys)) show_legend = False if color_name: if isinstance(df[color_name].iloc[0], str) or color_is_cat: show_legend = True if isinstance(colormap, dict): utils.validate_colors_dict(colormap, 'rgb') for val in df[color_name].unique(): if val not in colormap.keys(): raise exceptions.PlotlyError( "If using 'colormap' as a dictionary, make sure " "all the values of the colormap column are in " "the keys of your dictionary.") else: # use default plotly colors for dictionary default_colors = utils.DEFAULT_PLOTLY_COLORS colormap = {} j = 0 for val in df[color_name].unique(): if j >= len(default_colors): j = 0 colormap[val] = default_colors[j] j += 1 fig = _facet_grid_color_categorical( df, x, y, facet_row, facet_col, color_name, colormap, num_of_rows, num_of_cols, facet_row_labels, facet_col_labels, trace_type, flipped_rows, flipped_cols, show_boxes, SUBPLOT_SPACING, marker_color, kwargs_trace, kwargs_marker) elif isinstance(df[color_name].iloc[0], Number): if isinstance(colormap, dict): show_legend = True utils.validate_colors_dict(colormap, 'rgb') for val in df[color_name].unique(): if val not in colormap.keys(): raise exceptions.PlotlyError( "If using 'colormap' as a dictionary, make sure " "all the values of the colormap column are in " "the keys of your dictionary.") fig = _facet_grid_color_categorical( df, x, y, facet_row, facet_col, color_name, colormap, num_of_rows, num_of_cols, facet_row_labels, facet_col_labels, trace_type, flipped_rows, flipped_cols, show_boxes, SUBPLOT_SPACING, marker_color, kwargs_trace, kwargs_marker) elif isinstance(colormap, list): colorscale_list = colormap utils.validate_colorscale(colorscale_list) fig = _facet_grid_color_numerical( df, x, y, facet_row, facet_col, color_name, colorscale_list, num_of_rows, num_of_cols, facet_row_labels, facet_col_labels, trace_type, flipped_rows, flipped_cols, show_boxes, SUBPLOT_SPACING, marker_color, kwargs_trace, kwargs_marker) elif isinstance(colormap, str): if colormap in colors.PLOTLY_SCALES.keys(): colorscale_list = colors.PLOTLY_SCALES[colormap] else: raise exceptions.PlotlyError( "If 'colormap' is a string, it must be the name " "of a Plotly Colorscale. The available colorscale " "names are {}".format(colors.PLOTLY_SCALES.keys())) fig = _facet_grid_color_numerical( df, x, y, facet_row, facet_col, color_name, colorscale_list, num_of_rows, num_of_cols, facet_row_labels, facet_col_labels, trace_type, flipped_rows, flipped_cols, show_boxes, SUBPLOT_SPACING, marker_color, kwargs_trace, kwargs_marker) else: colorscale_list = colors.PLOTLY_SCALES['Reds'] fig = _facet_grid_color_numerical( df, x, y, facet_row, facet_col, color_name, colorscale_list, num_of_rows, num_of_cols, facet_row_labels, facet_col_labels, trace_type, flipped_rows, flipped_cols, show_boxes, SUBPLOT_SPACING, marker_color, kwargs_trace, kwargs_marker) else: fig = _facet_grid(df, x, y, facet_row, facet_col, num_of_rows, num_of_cols, facet_row_labels, facet_col_labels, trace_type, flipped_rows, flipped_cols, show_boxes, SUBPLOT_SPACING, marker_color, kwargs_trace, kwargs_marker) if not height: height = max(600, 100 * num_of_rows) if not width: width = max(600, 100 * num_of_cols) fig['layout'].update(height=height, width=width, title='', paper_bgcolor='rgb(251, 251, 251)') if ggplot2: fig['layout'].update(plot_bgcolor=PLOT_BGCOLOR, paper_bgcolor='rgb(255, 255, 255)', hovermode='closest') # axis titles x_title_annot = _axis_title_annotation(x, 'x') y_title_annot = _axis_title_annotation(y, 'y') fig['layout']['annotations'].append(x_title_annot) fig['layout']['annotations'].append(y_title_annot) # legend fig['layout']['showlegend'] = show_legend fig['layout']['legend']['bgcolor'] = LEGEND_COLOR fig['layout']['legend']['borderwidth'] = LEGEND_BORDER_WIDTH fig['layout']['legend']['x'] = 1.05 fig['layout']['legend']['y'] = 1 fig['layout']['legend']['yanchor'] = 'top' if show_legend: fig['layout']['showlegend'] = show_legend if ggplot2: if color_name: legend_annot = _legend_annotation(color_name) fig['layout']['annotations'].append(legend_annot) fig['layout']['margin']['r'] = 150 # add shaded boxes behind axis titles if show_boxes and ggplot2: _add_shapes_to_fig(fig, ANNOT_RECT_COLOR, flipped_rows, flipped_cols) # all xaxis and yaxis labels axis_labels = {'x': [], 'y': []} for key in fig['layout']: if 'xaxis' in key: axis_labels['x'].append(key) elif 'yaxis' in key: axis_labels['y'].append(key) string_number_in_data = False for var in [v for v in [x, y] if v]: if isinstance(df[var].tolist()[0], str): for item in df[var]: try: int(item) string_number_in_data = True except ValueError: pass if string_number_in_data: for x_y in axis_labels.keys(): for axis_name in axis_labels[x_y]: fig['layout'][axis_name]['type'] = 'category' if scales == 'fixed': fixed_axes = ['x', 'y'] elif scales == 'free_x': fixed_axes = ['y'] elif scales == 'free_y': fixed_axes = ['x'] elif scales == 'free': fixed_axes = [] # fixed ranges for x_y in fixed_axes: min_ranges = [] max_ranges = [] for trace in fig['data']: if trace[x_y] is not None and len(trace[x_y]) > 0: min_ranges.append(min(trace[x_y])) max_ranges.append(max(trace[x_y])) while None in min_ranges: min_ranges.remove(None) while None in max_ranges: max_ranges.remove(None) min_range = min(min_ranges) max_range = max(max_ranges) range_are_numbers = (isinstance(min_range, Number) and isinstance(max_range, Number)) if range_are_numbers: min_range = math.floor(min_range) max_range = math.ceil(max_range) # extend widen frame by 5% on each side min_range -= 0.05 * (max_range - min_range) max_range += 0.05 * (max_range - min_range) if x_y == 'x': if dtick_x: dtick = dtick_x else: dtick = math.floor( (max_range - min_range) / MAX_TICKS_PER_AXIS) elif x_y == 'y': if dtick_y: dtick = dtick_y else: dtick = math.floor( (max_range - min_range) / MAX_TICKS_PER_AXIS) else: dtick = 1 for axis_title in axis_labels[x_y]: fig['layout'][axis_title]['dtick'] = dtick fig['layout'][axis_title]['ticklen'] = 0 fig['layout'][axis_title]['zeroline'] = False if ggplot2: fig['layout'][axis_title]['tickwidth'] = 1 fig['layout'][axis_title]['ticklen'] = 4 fig['layout'][axis_title]['gridwidth'] = GRID_WIDTH fig['layout'][axis_title]['gridcolor'] = GRID_COLOR fig['layout'][axis_title]['gridwidth'] = 2 fig['layout'][axis_title]['tickfont'] = { 'color': TICK_COLOR, 'size': 10 } # insert ranges into fig if x_y in fixed_axes: for key in fig['layout']: if '{}axis'.format(x_y) in key and range_are_numbers: fig['layout'][key]['range'] = [min_range, max_range] return fig
def write(self, trace, layout=None, validate=True, reconnect_on=(200, '', 408)): """ Write to an open stream. Once you've instantiated a 'Stream' object with a 'stream_id', you can 'write' to it in real time. positional arguments: trace - A valid plotly trace object (e.g., Scatter, Heatmap, etc.). Not all keys in these are `stremable` run help(Obj) on the type of trace your trying to stream, for each valid key, if the key is streamable, it will say 'streamable = True'. Trace objects must be dictionary-like. keyword arguments: layout (default=None) - A valid Layout object Run help(plotly.graph_objs.Layout) validate (default = True) - Validate this stream before sending? This will catch local errors if set to True. Some valid keys for trace dictionaries: 'x', 'y', 'text', 'z', 'marker', 'line' Examples: >>> write(dict(x=1, y=2)) # assumes 'scatter' type >>> write(Bar(x=[1, 2, 3], y=[10, 20, 30])) >>> write(Scatter(x=1, y=2, text='scatter text')) >>> write(Scatter(x=1, y=3, marker=Marker(color='blue'))) >>> write(Heatmap(z=[[1, 2, 3], [4, 5, 6]])) The connection to plotly's servers is checked before writing and reconnected if disconnected and if the response status code is in `reconnect_on`. For more help, see: `help(plotly.plotly.Stream)` or see examples and tutorials here: http://nbviewer.ipython.org/github/plotly/python-user-guide/blob/master/s7_streaming/s7_streaming.ipynb """ stream_object = dict() stream_object.update(trace) if 'type' not in stream_object: stream_object['type'] = 'scatter' if validate: try: tools.validate(stream_object, stream_object['type']) except exceptions.PlotlyError as err: raise exceptions.PlotlyError( "Part of the data object with type, '{0}', is invalid. " "This will default to 'scatter' if you do not supply a " "'type'. If you do not want to validate your data objects " "when streaming, you can set 'validate=False' in the call " "to 'your_stream.write()'. Here's why the object is " "invalid:\n\n{1}".format(stream_object['type'], err)) try: tools.validate_stream(stream_object, stream_object['type']) except exceptions.PlotlyError as err: raise exceptions.PlotlyError( "Part of the data object with type, '{0}', cannot yet be " "streamed into Plotly. If you do not want to validate " "your data objects when streaming, you can set " "'validate=False' in the call to 'your_stream.write()'. " "Here's why the object cannot be streamed:\n\n{1}".format( stream_object['type'], err)) if layout is not None: try: tools.validate(layout, 'Layout') except exceptions.PlotlyError as err: raise exceptions.PlotlyError( "Your layout kwarg was invalid. " "Here's why:\n\n{0}".format(err)) del stream_object['type'] if layout is not None: stream_object.update(dict(layout=layout)) # TODO: allow string version of this? jdata = json.dumps(stream_object, cls=utils.PlotlyJSONEncoder) jdata += "\n" try: self._stream.write(jdata, reconnect_on=reconnect_on) except AttributeError: raise exceptions.PlotlyError( "Stream has not been opened yet, " "cannot write to a closed connection. " "Call `open()` on the stream to open the stream.")
def create_2d_density(x, y, colorscale='Earth', ncontours=20, hist_color=(0, 0, 0.5), point_color=(0, 0, 0.5), point_size=2, title='2D Density Plot', height=600, width=600): """ Returns figure for a 2D density plot :param (list|array) x: x-axis data for plot generation :param (list|array) y: y-axis data for plot generation :param (str|tuple|list) colorscale: either a plotly scale name, an rgb or hex color, a color tuple or a list or tuple 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 colormap is a list, it must contain the valid color types aforementioned as its members. :param (int) ncontours: the number of 2D contours to draw on the plot :param (str) hist_color: the color of the plotted histograms :param (str) point_color: the color of the scatter points :param (str) point_size: the color of the scatter points :param (str) title: set the title for the plot :param (float) height: the height of the chart :param (float) width: the width of the chart Example 1: Simple 2D Density Plot ``` import plotly.plotly as py from plotly.figure_factory create_2d_density import numpy as np # Make data points t = np.linspace(-1,1.2,2000) x = (t**3)+(0.3*np.random.randn(2000)) y = (t**6)+(0.3*np.random.randn(2000)) # Create a figure fig = create_2D_density(x, y) # Plot the data py.iplot(fig, filename='simple-2d-density') ``` Example 2: Using Parameters ``` import plotly.plotly as py from plotly.figure_factory create_2d_density import numpy as np # Make data points t = np.linspace(-1,1.2,2000) x = (t**3)+(0.3*np.random.randn(2000)) y = (t**6)+(0.3*np.random.randn(2000)) # Create custom colorscale colorscale = ['#7A4579', '#D56073', 'rgb(236,158,105)', (1, 1, 0.2), (0.98,0.98,0.98)] # Create a figure fig = create_2D_density( x, y, colorscale=colorscale, hist_color='rgb(255, 237, 222)', point_size=3) # Plot the data py.iplot(fig, filename='use-parameters') ``` """ # validate x and y are filled with numbers only for array in [x, y]: if not all(isinstance(element, Number) for element in array): raise exceptions.PlotlyError( "All elements of your 'x' and 'y' lists must be numbers.") # validate x and y are the same length if len(x) != len(y): raise exceptions.PlotlyError( "Both lists 'x' and 'y' must be the same length.") colorscale = clrs.validate_colors(colorscale, 'rgb') colorscale = make_linear_colorscale(colorscale) # validate hist_color and point_color hist_color = clrs.validate_colors(hist_color, 'rgb') point_color = clrs.validate_colors(point_color, 'rgb') trace1 = graph_objs.Scatter(x=x, y=y, mode='markers', name='points', marker=dict(color=point_color[0], size=point_size, opacity=0.4)) trace2 = graph_objs.Histogram2dContour(x=x, y=y, name='density', ncontours=ncontours, colorscale=colorscale, reversescale=True, showscale=False) trace3 = graph_objs.Histogram(x=x, name='x density', marker=dict(color=hist_color[0]), yaxis='y2') trace4 = graph_objs.Histogram(y=y, name='y density', marker=dict(color=hist_color[0]), xaxis='x2') data = [trace1, trace2, trace3, trace4] layout = graph_objs.Layout(showlegend=False, autosize=False, title=title, height=height, width=width, xaxis=dict(domain=[0, 0.85], showgrid=False, zeroline=False), yaxis=dict(domain=[0, 0.85], showgrid=False, zeroline=False), margin=dict(t=50), hovermode='closest', bargap=0, xaxis2=dict(domain=[0.85, 1], showgrid=False, zeroline=False), yaxis2=dict(domain=[0.85, 1], showgrid=False, zeroline=False)) fig = graph_objs.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): """ 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) shape_template = { 'type': 'rect', 'xref': 'x', 'yref': 'y', 'opacity': 1, 'line': { 'width': 0, } } # 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'] tasks[index].update(shape_template) # 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 = utils.color_parser(colors, utils.unlabel_rgb) lowcolor = colors[0] highcolor = colors[1] intermed = (chart[index][index_col]) / 100.0 intermed_color = utils.find_intermediate_color( lowcolor, highcolor, intermed) intermed_color = utils.color_parser(intermed_color, utils.label_rgb) tasks[index]['fillcolor'] = intermed_color # relabel colors with 'rgb' colors = utils.color_parser(colors, utils.label_rgb) # add a line for hover text and autorange entry = dict(x=[tasks[index]['x0'], tasks[index]['x1']], y=[groupID, groupID], name='', marker={'color': 'white'}) if "description" in tasks[index]: entry['text'] = tasks[index]['description'] del tasks[index]['description'] data.append(entry) 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 # 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'] tasks[index].update(shape_template) # 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]] # add a line for hover text and autorange entry = dict(x=[tasks[index]['x0'], tasks[index]['x1']], y=[groupID, groupID], name='', marker={'color': 'white'}) if "description" in tasks[index]: entry['text'] = tasks[index]['description'] del tasks[index]['description'] data.append(entry) 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(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')) layout['shapes'] = tasks fig = dict(data=data, layout=layout) return fig
def trisurf(x, y, z, simplices, show_colorbar, edges_color, scale, colormap=None, color_func=None, plot_edges=False, x_edge=None, y_edge=None, z_edge=None, facecolor=None): """ Refer to FigureFactory.create_trisurf() for docstring """ # numpy import check if not np: raise ImportError("FigureFactory._trisurf() requires " "numpy imported.") points3D = np.vstack((x, y, z)).T simplices = np.atleast_2d(simplices) # vertices of the surface triangles tri_vertices = points3D[simplices] # Define colors for the triangle faces if color_func is None: # mean values of z-coordinates of triangle vertices mean_dists = tri_vertices[:, :, 2].mean(-1) elif isinstance(color_func, (list, np.ndarray)): # Pre-computed list / array of values to map onto color if len(color_func) != len(simplices): raise ValueError("If color_func is a list/array, it must " "be the same length as simplices.") # convert all colors in color_func to rgb for index in range(len(color_func)): if isinstance(color_func[index], str): if '#' in color_func[index]: foo = colors.hex_to_rgb(color_func[index]) color_func[index] = colors.label_rgb(foo) if isinstance(color_func[index], tuple): foo = colors.convert_to_RGB_255(color_func[index]) color_func[index] = colors.label_rgb(foo) mean_dists = np.asarray(color_func) else: # apply user inputted function to calculate # custom coloring for triangle vertices mean_dists = [] for triangle in tri_vertices: dists = [] for vertex in triangle: dist = color_func(vertex[0], vertex[1], vertex[2]) dists.append(dist) mean_dists.append(np.mean(dists)) mean_dists = np.asarray(mean_dists) # Check if facecolors are already strings and can be skipped if isinstance(mean_dists[0], str): facecolor = mean_dists else: min_mean_dists = np.min(mean_dists) max_mean_dists = np.max(mean_dists) if facecolor is None: facecolor = [] for index in range(len(mean_dists)): color = map_face2color(mean_dists[index], colormap, scale, min_mean_dists, max_mean_dists) facecolor.append(color) # Make sure facecolor is a list so output is consistent across Pythons facecolor = np.asarray(facecolor) ii, jj, kk = simplices.T triangles = graph_objs.Mesh3d(x=x, y=y, z=z, facecolor=facecolor, i=ii, j=jj, k=kk, name='') mean_dists_are_numbers = not isinstance(mean_dists[0], str) if mean_dists_are_numbers and show_colorbar is True: # make a colorscale from the colors colorscale = colors.make_colorscale(colormap, scale) colorscale = colors.convert_colorscale_to_rgb(colorscale) colorbar = graph_objs.Scatter3d( x=x[:1], y=y[:1], z=z[:1], mode='markers', marker=dict(size=0.1, color=[min_mean_dists, max_mean_dists], colorscale=colorscale, showscale=True), hoverinfo='None', showlegend=False) # the triangle sides are not plotted if plot_edges is False: if mean_dists_are_numbers and show_colorbar is True: return graph_objs.Data([triangles, colorbar]) else: return graph_objs.Data([triangles]) # define the lists x_edge, y_edge and z_edge, of x, y, resp z # coordinates of edge end points for each triangle # None separates data corresponding to two consecutive triangles is_none = [ii is None for ii in [x_edge, y_edge, z_edge]] if any(is_none): if not all(is_none): raise ValueError("If any (x_edge, y_edge, z_edge) is None, " "all must be None") else: x_edge = [] y_edge = [] z_edge = [] # Pull indices we care about, then add a None column to separate tris ixs_triangles = [0, 1, 2, 0] pull_edges = tri_vertices[:, ixs_triangles, :] x_edge_pull = np.hstack( [pull_edges[:, :, 0], np.tile(None, [pull_edges.shape[0], 1])]) y_edge_pull = np.hstack( [pull_edges[:, :, 1], np.tile(None, [pull_edges.shape[0], 1])]) z_edge_pull = np.hstack( [pull_edges[:, :, 2], np.tile(None, [pull_edges.shape[0], 1])]) # Now unravel the edges into a 1-d vector for plotting x_edge = np.hstack([x_edge, x_edge_pull.reshape([1, -1])[0]]) y_edge = np.hstack([y_edge, y_edge_pull.reshape([1, -1])[0]]) z_edge = np.hstack([z_edge, z_edge_pull.reshape([1, -1])[0]]) if not (len(x_edge) == len(y_edge) == len(z_edge)): raise exceptions.PlotlyError("The lengths of x_edge, y_edge and " "z_edge are not the same.") # define the lines for plotting lines = graph_objs.Scatter3d(x=x_edge, y=y_edge, z=z_edge, mode='lines', line=graph_objs.Line(color=edges_color, width=1.5), showlegend=False) if mean_dists_are_numbers and show_colorbar is True: return graph_objs.Data([triangles, lines, colorbar]) else: return graph_objs.Data([triangles, lines])
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, group_tasks=False): """ 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.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) # 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.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) # 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.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) # 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.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) # 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.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) # Plot the data py.iplot(fig, filename='data with dataframe', world_readable=True) ``` """ # 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 = utils.validate_colors_dict(colors, 'rgb') else: colors = utils.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 = gantt(chart, colors, title, bar_width, showgrid_x, showgrid_y, height, width, tasks=None, task_names=None, data=None, group_tasks=group_tasks) 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) 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) 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 = list({chart[row][index_col] for row in range(len(tasks))}) 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 = list({chart[row][index_col] for row in range(len(tasks))}) 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 get_embed(file_owner_or_url, file_id=None, width="100%", height=525): """Returns HTML code to embed figure on a webpage as an <iframe> Plotly uniquely identifies figures with a 'file_owner'/'file_id' pair. Since each file is given a corresponding unique url, you may also simply pass a valid plotly url as the first argument. Note, if you're using a file_owner string as the first argument, you MUST specify a `file_id` keyword argument. Else, if you're using a url string as the first argument, you MUST NOT specify a `file_id` keyword argument, or file_id must be set to Python's None value. Positional arguments: file_owner_or_url (string) -- a valid plotly username OR a valid plotly url Keyword arguments: file_id (default=None) -- an int or string that can be converted to int if you're using a url, don't fill this in! width (default="100%") -- an int or string corresp. to width of the figure height (default="525") -- same as width but corresp. to the height of the figure """ padding = 25 plotly_rest_url = get_config_file()['plotly_domain'] if file_id is None: # assume we're using a url url = file_owner_or_url if url[:len(plotly_rest_url)] != plotly_rest_url: raise exceptions.PlotlyError( "Because you didn't supply a 'file_id' in the call, " "we're assuming you're trying to snag a figure from a url. " "You supplied the url, '{0}', we expected it to start with " "'{1}'." "\nRun help on this function for more information." "".format(url, plotly_rest_url)) head = plotly_rest_url + "/~" file_owner = url.replace(head, "").split('/')[0] file_id = url.replace(head, "").split('/')[1] else: file_owner = file_owner_or_url resource = "/apigetfile/{file_owner}/{file_id}".format( file_owner=file_owner, file_id=file_id) try: test_if_int = int(file_id) except ValueError: raise exceptions.PlotlyError( "The 'file_id' argument was not able to be converted into an " "integer number. Make sure that the positional 'file_id' argument " "is a number that can be converted into an integer or a string " "that can be converted into an integer.") if int(file_id) < 0: raise exceptions.PlotlyError( "The 'file_id' argument must be a non-negative number.") if isinstance(width, int): s = ("<iframe id=\"igraph\" scrolling=\"no\" style=\"border:none;\"" "seamless=\"seamless\" " "src=\"{plotly_rest_url}/" "~{file_owner}/{file_id}.embed" "?width={plot_width}&height={plot_height}\" " "height=\"{iframe_height}\" width=\"{iframe_width}\">" "</iframe>").format(plotly_rest_url=plotly_rest_url, file_owner=file_owner, file_id=file_id, plot_width=width - padding, plot_height=height - padding, iframe_height=height, iframe_width=width) else: s = ("<iframe id=\"igraph\" scrolling=\"no\" style=\"border:none;\"" "seamless=\"seamless\" " "src=\"{plotly_rest_url}/" "~{file_owner}/{file_id}.embed\" " "height=\"{iframe_height}\" width=\"{iframe_width}\">" "</iframe>").format(plotly_rest_url=plotly_rest_url, file_owner=file_owner, file_id=file_id, iframe_height=height, iframe_width=width) return s
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, ): """ 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) shape_template = { "type": "rect", "xref": "x", "yref": "y", "opacity": 1, "line": { "width": 0 }, } 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"] tasks[index].update(shape_template) # 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]] # add a line for hover text and autorange entry = dict( x=[tasks[index]["x0"], tasks[index]["x1"]], y=[groupID, groupID], showlegend=False, name="", marker={"color": "white"}, ) if "description" in tasks[index]: entry["text"] = tasks[index]["description"] del tasks[index]["description"] data.append(entry) 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(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", ), ) layout["shapes"] = tasks fig = graph_objs.Figure(data=data, layout=layout) return fig