From d32d85668818b25cd511dcb35e870070cd18dce3 Mon Sep 17 00:00:00 2001 From: Emily KL <4672118+emilykl@users.noreply.github.com> Date: Thu, 18 Jun 2026 13:18:45 -0400 Subject: [PATCH 1/8] remove deprecated Figure Factory functions --- plotly/figure_factory/README.md | 17 +- plotly/figure_factory/_2d_density.py | 155 --- plotly/figure_factory/__init__.py | 34 +- plotly/figure_factory/_annotated_heatmap.py | 307 ----- plotly/figure_factory/_bullet.py | 366 ------ plotly/figure_factory/_candlestick.py | 277 ----- plotly/figure_factory/_county_choropleth.py | 1013 ---------------- plotly/figure_factory/_distplot.py | 441 ------- plotly/figure_factory/_facet_grid.py | 1195 ------------------- plotly/figure_factory/_gantt.py | 1035 ---------------- plotly/figure_factory/_hexbin_map.py | 15 - plotly/figure_factory/_ohlc.py | 295 ----- plotly/figure_factory/_scatterplot.py | 1135 ------------------ plotly/figure_factory/_violin.py | 704 ----------- plotly/tools.py | 71 -- 15 files changed, 6 insertions(+), 7054 deletions(-) delete mode 100644 plotly/figure_factory/_2d_density.py delete mode 100644 plotly/figure_factory/_annotated_heatmap.py delete mode 100644 plotly/figure_factory/_bullet.py delete mode 100644 plotly/figure_factory/_candlestick.py delete mode 100644 plotly/figure_factory/_county_choropleth.py delete mode 100644 plotly/figure_factory/_distplot.py delete mode 100644 plotly/figure_factory/_facet_grid.py delete mode 100644 plotly/figure_factory/_gantt.py delete mode 100644 plotly/figure_factory/_ohlc.py delete mode 100644 plotly/figure_factory/_scatterplot.py delete mode 100644 plotly/figure_factory/_violin.py diff --git a/plotly/figure_factory/README.md b/plotly/figure_factory/README.md index 435fedb2fb6..ec1824b5458 100644 --- a/plotly/figure_factory/README.md +++ b/plotly/figure_factory/README.md @@ -68,9 +68,9 @@ The inside of the `__init__.py` looks like: # Require that numpy exists for figure_factory import numpy -from plotly.figure_factory._2d_density import create_2d_density -from plotly.figure_factory._annotated_heatmap import create_annotated_heatmap -from plotly.figure_factory._candlestick import create_candlestick +from plotly.figure_factory._dendrogram import create_dendrogram +from plotly.figure_factory._quiver import create_quiver +from plotly.figure_factory._streamline import create_streamline ... ``` @@ -166,17 +166,10 @@ Go check out your newly pushed branch at https://github.com/plotly/plotly.py. If ### Table of Current Figure Factories | Name | Documentation | In GitHub | | ----------------- | ----------------------------------------- | ------------- | -| 2D Density | https://plot.ly/python/density-plots/ |https://github.com/plotly/plotly.py/blob/master/plotly/figure_factory/_2d_density.py| -| Annotated Heatmap | https://plot.ly/python/annotated_heatmap/ |https://github.com/plotly/plotly.py/blob/master/plotly/figure_factory/_annotated_heatmap.py| -| Candlestick | https://plot.ly/python/candlestick-charts/|https://github.com/plotly/plotly.py/blob/master/plotly/figure_factory/_candlestick.py| | Dendrogram | https://plot.ly/python/dendrogram/ |https://github.com/plotly/plotly.py/blob/master/plotly/figure_factory/_dendrogram.py| -| Distplot | https://plot.ly/python/distplot/ |https://github.com/plotly/plotly.py/blob/master/plotly/figure_factory/_distplot.py| -| Facet Grid | https://plot.ly/python/facet-plots/ |https://github.com/plotly/plotly.py/blob/master/plotly/figure_factory/_facet_grid.py| -| Gantt | https://plot.ly/python/gantt/ |https://github.com/plotly/plotly.py/blob/master/plotly/figure_factory/_gantt.py| -| Ohlc | https://plot.ly/python/ohlc-charts/ |https://github.com/plotly/plotly.py/blob/master/plotly/figure_factory/_ohlc.py| +| Hexbin Map | https://plot.ly/python/hexbin-mapbox/ |https://github.com/plotly/plotly.py/blob/master/plotly/figure_factory/_hexbin_map.py| | Quiver | https://plot.ly/python/quiver-plots/ |https://github.com/plotly/plotly.py/blob/master/plotly/figure_factory/_quiver.py| -| Scatterplot Matrix| https://plot.ly/python/scatterplot-matrix/|https://github.com/plotly/plotly.py/blob/master/plotly/figure_factory/_scatterplot.py| | Streamline | https://plot.ly/python/streamline-plots/ |https://github.com/plotly/plotly.py/blob/master/plotly/figure_factory/_streamline.py| | Table | https://plot.ly/python/table/ |https://github.com/plotly/plotly.py/blob/master/plotly/figure_factory/_table.py| +| Ternary Contour | https://plot.ly/python/ternary-contour/ |https://github.com/plotly/plotly.py/blob/master/plotly/figure_factory/_ternary_contour.py| | Trisurf | https://plot.ly/python/trisurf/ |https://github.com/plotly/plotly.py/blob/master/plotly/figure_factory/_trisurf.py| -| Violin | https://plot.ly/python/violin-plot/ |https://github.com/plotly/plotly.py/blob/master/plotly/figure_factory/_violin.py| diff --git a/plotly/figure_factory/_2d_density.py b/plotly/figure_factory/_2d_density.py deleted file mode 100644 index 3094d0bcad0..00000000000 --- a/plotly/figure_factory/_2d_density.py +++ /dev/null @@ -1,155 +0,0 @@ -from numbers import Number - -import plotly.exceptions - -import plotly.colors as clrs -from plotly.graph_objs import graph_objs - - -def make_linear_colorscale(colors): - """ - Makes a list of colors into a colorscale-acceptable form - - For documentation regarding to the form of the output, see - https://plot.ly/python/reference/#mesh3d-colorscale - """ - scale = 1.0 / (len(colors) - 1) - return [[i * scale, color] for i, color in enumerate(colors)] - - -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, -): - """ - **deprecated**, use instead - :func:`plotly.express.density_heatmap`. - - :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 - - Examples - -------- - - Example 1: Simple 2D Density Plot - - >>> from plotly.figure_factory import 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 - >>> fig.show() - - Example 2: Using Parameters - - >>> from plotly.figure_factory import 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 - >>> fig.show() - """ - - # 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 plotly.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 plotly.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 diff --git a/plotly/figure_factory/__init__.py b/plotly/figure_factory/__init__.py index c0ded37ca28..6342345a91f 100644 --- a/plotly/figure_factory/__init__.py +++ b/plotly/figure_factory/__init__.py @@ -11,39 +11,19 @@ ) -from plotly.figure_factory._2d_density import create_2d_density -from plotly.figure_factory._annotated_heatmap import create_annotated_heatmap -from plotly.figure_factory._bullet import create_bullet -from plotly.figure_factory._candlestick import create_candlestick from plotly.figure_factory._dendrogram import create_dendrogram -from plotly.figure_factory._distplot import create_distplot -from plotly.figure_factory._facet_grid import create_facet_grid -from plotly.figure_factory._gantt import create_gantt -from plotly.figure_factory._ohlc import create_ohlc from plotly.figure_factory._quiver import create_quiver -from plotly.figure_factory._scatterplot import create_scatterplotmatrix from plotly.figure_factory._streamline import create_streamline from plotly.figure_factory._table import create_table from plotly.figure_factory._trisurf import create_trisurf -from plotly.figure_factory._violin import create_violin if optional_imports.get_module("pandas") is not None: - from plotly.figure_factory._county_choropleth import create_choropleth - from plotly.figure_factory._hexbin_map import ( - create_hexbin_map, - create_hexbin_mapbox, - ) + from plotly.figure_factory._hexbin_map import create_hexbin_map else: - def create_choropleth(*args, **kwargs): - raise ImportError("Please install pandas to use `create_choropleth`") - def create_hexbin_map(*args, **kwargs): raise ImportError("Please install pandas to use `create_hexbin_map`") - def create_hexbin_mapbox(*args, **kwargs): - raise ImportError("Please install pandas to use `create_hexbin_mapbox`") - if optional_imports.get_module("skimage") is not None: from plotly.figure_factory._ternary_contour import create_ternary_contour @@ -54,23 +34,11 @@ def create_ternary_contour(*args, **kwargs): __all__ = [ - "create_2d_density", - "create_annotated_heatmap", - "create_bullet", - "create_candlestick", - "create_choropleth", "create_dendrogram", - "create_distplot", - "create_facet_grid", - "create_gantt", "create_hexbin_map", - "create_hexbin_mapbox", - "create_ohlc", "create_quiver", - "create_scatterplotmatrix", "create_streamline", "create_table", "create_ternary_contour", "create_trisurf", - "create_violin", ] diff --git a/plotly/figure_factory/_annotated_heatmap.py b/plotly/figure_factory/_annotated_heatmap.py deleted file mode 100644 index 5da24ae5bc3..00000000000 --- a/plotly/figure_factory/_annotated_heatmap.py +++ /dev/null @@ -1,307 +0,0 @@ -import plotly.colors as clrs -from plotly import exceptions, optional_imports -from plotly.figure_factory import utils -from plotly.graph_objs import graph_objs -from plotly.validator_cache import ValidatorCache - -# Optional imports, may be None for users that only use our core functionality. -np = optional_imports.get_module("numpy") - - -def validate_annotated_heatmap(z, x, y, annotation_text): - """ - Annotated-heatmap-specific validations - - Check that if a text matrix is supplied, it has the same - dimensions as the z matrix. - - See FigureFactory.create_annotated_heatmap() for params - - :raises: (PlotlyError) If z and text matrices do not have the same - dimensions. - """ - if annotation_text is not None and isinstance(annotation_text, list): - utils.validate_equal_length(z, annotation_text) - for lst in range(len(z)): - if len(z[lst]) != len(annotation_text[lst]): - raise exceptions.PlotlyError( - "z and text should have the same dimensions" - ) - - if x: - if len(x) != len(z[0]): - raise exceptions.PlotlyError( - "oops, the x list that you " - "provided does not match the " - "width of your z matrix " - ) - - if y: - if len(y) != len(z): - raise exceptions.PlotlyError( - "oops, the y list that you " - "provided does not match the " - "length of your z matrix " - ) - - -def create_annotated_heatmap( - z, - x=None, - y=None, - annotation_text=None, - colorscale="Plasma", - font_colors=None, - showscale=False, - reversescale=False, - **kwargs, -): - """ - **deprecated**, use instead - :func:`plotly.express.imshow`. - - Function that creates annotated heatmaps - - This function adds annotations to each cell of the heatmap. - - :param (list[list]|ndarray) z: z matrix to create heatmap. - :param (list) x: x axis labels. - :param (list) y: y axis labels. - :param (list[list]|ndarray) annotation_text: Text strings for - annotations. Should have the same dimensions as the z matrix. If no - text is added, the values of the z matrix are annotated. Default = - z matrix values. - :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 with default configuration - - >>> import plotly.figure_factory as ff - - >>> z = [[0.300000, 0.00000, 0.65, 0.300000], - ... [1, 0.100005, 0.45, 0.4300], - ... [0.300000, 0.00000, 0.65, 0.300000], - ... [1, 0.100005, 0.45, 0.00000]] - - >>> fig = ff.create_annotated_heatmap(z) - >>> fig.show() - """ - - # Avoiding mutables in the call signature - font_colors = font_colors if font_colors is not None else [] - validate_annotated_heatmap(z, x, y, annotation_text) - - # validate colorscale - colorscale_validator = ValidatorCache.get_validator("heatmap", "colorscale") - colorscale = colorscale_validator.validate_coerce(colorscale) - - annotations = _AnnotatedHeatmap( - z, x, y, annotation_text, colorscale, font_colors, reversescale, **kwargs - ).make_annotations() - - if x or y: - trace = dict( - type="heatmap", - z=z, - x=x, - y=y, - colorscale=colorscale, - showscale=showscale, - reversescale=reversescale, - **kwargs, - ) - layout = dict( - annotations=annotations, - xaxis=dict(ticks="", dtick=1, side="top", gridcolor="rgb(0, 0, 0)"), - yaxis=dict(ticks="", dtick=1, ticksuffix=" "), - ) - else: - trace = dict( - type="heatmap", - z=z, - colorscale=colorscale, - showscale=showscale, - reversescale=reversescale, - **kwargs, - ) - layout = dict( - annotations=annotations, - xaxis=dict( - ticks="", side="top", gridcolor="rgb(0, 0, 0)", showticklabels=False - ), - yaxis=dict(ticks="", ticksuffix=" ", showticklabels=False), - ) - - data = [trace] - - return graph_objs.Figure(data=data, layout=layout) - - -def to_rgb_color_list(color_str, default): - color_str = color_str.strip() - if color_str.startswith("rgb"): - return [int(v) for v in color_str.strip("rgba()").split(",")] - elif color_str.startswith("#"): - return clrs.hex_to_rgb(color_str) - else: - return default - - -def should_use_black_text(background_color): - return ( - background_color[0] * 0.299 - + background_color[1] * 0.587 - + background_color[2] * 0.114 - ) > 186 - - -class _AnnotatedHeatmap(object): - """ - Refer to TraceFactory.create_annotated_heatmap() for docstring - """ - - def __init__( - self, z, x, y, annotation_text, colorscale, font_colors, reversescale, **kwargs - ): - self.z = z - if x: - self.x = x - else: - self.x = range(len(z[0])) - if y: - self.y = y - else: - self.y = range(len(z)) - if annotation_text is not None: - self.annotation_text = annotation_text - else: - self.annotation_text = self.z - self.colorscale = colorscale - self.reversescale = reversescale - self.font_colors = font_colors - - if np and isinstance(self.z, np.ndarray): - self.zmin = np.amin(self.z) - self.zmax = np.amax(self.z) - else: - self.zmin = min([v for row in self.z for v in row]) - self.zmax = max([v for row in self.z for v in row]) - - if kwargs.get("zmin", None) is not None: - self.zmin = kwargs["zmin"] - if kwargs.get("zmax", None) is not None: - self.zmax = kwargs["zmax"] - - self.zmid = (self.zmax + self.zmin) / 2 - - if kwargs.get("zmid", None) is not None: - self.zmid = kwargs["zmid"] - - def get_text_color(self): - """ - Get font color for annotations. - - The annotated heatmap can feature two text colors: min_text_color and - max_text_color. The min_text_color is applied to annotations for - heatmap values < (max_value - min_value)/2. The user can define these - two colors. Otherwise the colors are defined logically as black or - white depending on the heatmap's colorscale. - - :rtype (string, string) min_text_color, max_text_color: text - color for annotations for heatmap values < - (max_value - min_value)/2 and text color for annotations for - heatmap values >= (max_value - min_value)/2 - """ - # Plotly colorscales ranging from a lighter shade to a darker shade - colorscales = [ - "Greys", - "Greens", - "Blues", - "YIGnBu", - "YIOrRd", - "RdBu", - "Picnic", - "Jet", - "Hot", - "Blackbody", - "Earth", - "Electric", - "Viridis", - "Cividis", - ] - # Plotly colorscales ranging from a darker shade to a lighter shade - colorscales_reverse = ["Reds"] - - white = "#FFFFFF" - black = "#000000" - if self.font_colors: - min_text_color = self.font_colors[0] - max_text_color = self.font_colors[-1] - elif self.colorscale in colorscales and self.reversescale: - min_text_color = black - max_text_color = white - elif self.colorscale in colorscales: - min_text_color = white - max_text_color = black - elif self.colorscale in colorscales_reverse and self.reversescale: - min_text_color = white - max_text_color = black - elif self.colorscale in colorscales_reverse: - min_text_color = black - max_text_color = white - elif isinstance(self.colorscale, list): - min_col = to_rgb_color_list(self.colorscale[0][1], [255, 255, 255]) - max_col = to_rgb_color_list(self.colorscale[-1][1], [255, 255, 255]) - - # swap min/max colors if reverse scale - if self.reversescale: - min_col, max_col = max_col, min_col - - if should_use_black_text(min_col): - min_text_color = black - else: - min_text_color = white - - if should_use_black_text(max_col): - max_text_color = black - else: - max_text_color = white - else: - min_text_color = black - max_text_color = black - return min_text_color, max_text_color - - def make_annotations(self): - """ - Get annotations for each cell of the heatmap with graph_objs.Annotation - - :rtype (list[dict]) annotations: list of annotations for each cell of - the heatmap - """ - min_text_color, max_text_color = _AnnotatedHeatmap.get_text_color(self) - annotations = [] - for n, row in enumerate(self.z): - for m, val in enumerate(row): - font_color = min_text_color if val < self.zmid else max_text_color - annotations.append( - graph_objs.layout.Annotation( - text=str(self.annotation_text[n][m]), - x=self.x[m], - y=self.y[n], - xref="x1", - yref="y1", - font=dict(color=font_color), - showarrow=False, - ) - ) - return annotations diff --git a/plotly/figure_factory/_bullet.py b/plotly/figure_factory/_bullet.py deleted file mode 100644 index ce51e9360c8..00000000000 --- a/plotly/figure_factory/_bullet.py +++ /dev/null @@ -1,366 +0,0 @@ -import math - -from plotly import exceptions, optional_imports -import plotly.colors as clrs -from plotly.figure_factory import utils - -import plotly -import plotly.graph_objs as go - -pd = optional_imports.get_module("pandas") - - -def _bullet( - df, - markers, - measures, - ranges, - subtitles, - titles, - orientation, - range_colors, - measure_colors, - horizontal_spacing, - vertical_spacing, - scatter_options, - layout_options, -): - num_of_lanes = len(df) - num_of_rows = num_of_lanes if orientation == "h" else 1 - num_of_cols = 1 if orientation == "h" else num_of_lanes - if not horizontal_spacing: - horizontal_spacing = 1.0 / num_of_lanes - if not vertical_spacing: - vertical_spacing = 1.0 / num_of_lanes - fig = plotly.subplots.make_subplots( - num_of_rows, - num_of_cols, - print_grid=False, - horizontal_spacing=horizontal_spacing, - vertical_spacing=vertical_spacing, - ) - - # layout - fig["layout"].update( - dict(shapes=[]), - title="Bullet Chart", - height=600, - width=1000, - showlegend=False, - barmode="stack", - annotations=[], - margin=dict(l=120 if orientation == "h" else 80), - ) - - # update layout - fig["layout"].update(layout_options) - - if orientation == "h": - width_axis = "yaxis" - length_axis = "xaxis" - else: - width_axis = "xaxis" - length_axis = "yaxis" - - for key in fig["layout"]: - if "xaxis" in key or "yaxis" in key: - fig["layout"][key]["showgrid"] = False - fig["layout"][key]["zeroline"] = False - if length_axis in key: - fig["layout"][key]["tickwidth"] = 1 - if width_axis in key: - fig["layout"][key]["showticklabels"] = False - fig["layout"][key]["range"] = [0, 1] - - # narrow domain if 1 bar - if num_of_lanes <= 1: - fig["layout"][width_axis + "1"]["domain"] = [0.4, 0.6] - - if not range_colors: - range_colors = ["rgb(200, 200, 200)", "rgb(245, 245, 245)"] - if not measure_colors: - measure_colors = ["rgb(31, 119, 180)", "rgb(176, 196, 221)"] - - for row in range(num_of_lanes): - # ranges bars - for idx in range(len(df.iloc[row]["ranges"])): - inter_colors = clrs.n_colors( - range_colors[0], range_colors[1], len(df.iloc[row]["ranges"]), "rgb" - ) - x = ( - [sorted(df.iloc[row]["ranges"])[-1 - idx]] - if orientation == "h" - else [0] - ) - y = ( - [0] - if orientation == "h" - else [sorted(df.iloc[row]["ranges"])[-1 - idx]] - ) - bar = go.Bar( - x=x, - y=y, - marker=dict(color=inter_colors[-1 - idx]), - name="ranges", - hoverinfo="x" if orientation == "h" else "y", - orientation=orientation, - width=2, - base=0, - xaxis="x{}".format(row + 1), - yaxis="y{}".format(row + 1), - ) - fig.add_trace(bar) - - # measures bars - for idx in range(len(df.iloc[row]["measures"])): - inter_colors = clrs.n_colors( - measure_colors[0], - measure_colors[1], - len(df.iloc[row]["measures"]), - "rgb", - ) - x = ( - [sorted(df.iloc[row]["measures"])[-1 - idx]] - if orientation == "h" - else [0.5] - ) - y = ( - [0.5] - if orientation == "h" - else [sorted(df.iloc[row]["measures"])[-1 - idx]] - ) - bar = go.Bar( - x=x, - y=y, - marker=dict(color=inter_colors[-1 - idx]), - name="measures", - hoverinfo="x" if orientation == "h" else "y", - orientation=orientation, - width=0.4, - base=0, - xaxis="x{}".format(row + 1), - yaxis="y{}".format(row + 1), - ) - fig.add_trace(bar) - - # markers - x = df.iloc[row]["markers"] if orientation == "h" else [0.5] - y = [0.5] if orientation == "h" else df.iloc[row]["markers"] - markers = go.Scatter( - x=x, - y=y, - name="markers", - hoverinfo="x" if orientation == "h" else "y", - xaxis="x{}".format(row + 1), - yaxis="y{}".format(row + 1), - **scatter_options, - ) - - fig.add_trace(markers) - - # titles and subtitles - title = df.iloc[row]["titles"] - if "subtitles" in df: - subtitle = "
{}".format(df.iloc[row]["subtitles"]) - else: - subtitle = "" - label = "{}".format(title) + subtitle - annot = utils.annotation_dict_for_label( - label, - (num_of_lanes - row if orientation == "h" else row + 1), - num_of_lanes, - vertical_spacing if orientation == "h" else horizontal_spacing, - "row" if orientation == "h" else "col", - True if orientation == "h" else False, - False, - ) - fig["layout"]["annotations"] += (annot,) - - 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 diff --git a/plotly/figure_factory/_candlestick.py b/plotly/figure_factory/_candlestick.py deleted file mode 100644 index 572ccfe142f..00000000000 --- a/plotly/figure_factory/_candlestick.py +++ /dev/null @@ -1,277 +0,0 @@ -from plotly.figure_factory import utils -from plotly.figure_factory._ohlc import ( - _DEFAULT_INCREASING_COLOR, - _DEFAULT_DECREASING_COLOR, - validate_ohlc, -) -from plotly.graph_objs import graph_objs - - -def make_increasing_candle(open, high, low, close, dates, **kwargs): - """ - Makes boxplot trace for increasing candlesticks - - _make_increasing_candle() and _make_decreasing_candle separate the - increasing traces from the decreasing traces so kwargs (such as - color) can be passed separately to increasing or decreasing traces - when direction is set to 'increasing' or 'decreasing' in - FigureFactory.create_candlestick() - - :param (list) open: opening values - :param (list) high: high values - :param (list) low: low values - :param (list) close: closing values - :param (list) dates: list of datetime objects. Default: None - :param kwargs: kwargs to be passed to increasing trace via - plotly.graph_objs.Scatter. - - :rtype (list) candle_incr_data: list of the box trace for - increasing candlesticks. - """ - increase_x, increase_y = _Candlestick( - open, high, low, close, dates, **kwargs - ).get_candle_increase() - - if "line" in kwargs: - kwargs.setdefault("fillcolor", kwargs["line"]["color"]) - else: - kwargs.setdefault("fillcolor", _DEFAULT_INCREASING_COLOR) - if "name" in kwargs: - kwargs.setdefault("showlegend", True) - else: - kwargs.setdefault("showlegend", False) - kwargs.setdefault("name", "Increasing") - kwargs.setdefault("line", dict(color=_DEFAULT_INCREASING_COLOR)) - - candle_incr_data = dict( - type="box", - x=increase_x, - y=increase_y, - whiskerwidth=0, - boxpoints=False, - **kwargs, - ) - - return [candle_incr_data] - - -def make_decreasing_candle(open, high, low, close, dates, **kwargs): - """ - Makes boxplot trace for decreasing candlesticks - - :param (list) open: opening values - :param (list) high: high values - :param (list) low: low values - :param (list) close: closing values - :param (list) dates: list of datetime objects. Default: None - :param kwargs: kwargs to be passed to decreasing trace via - plotly.graph_objs.Scatter. - - :rtype (list) candle_decr_data: list of the box trace for - decreasing candlesticks. - """ - - decrease_x, decrease_y = _Candlestick( - open, high, low, close, dates, **kwargs - ).get_candle_decrease() - - if "line" in kwargs: - kwargs.setdefault("fillcolor", kwargs["line"]["color"]) - else: - kwargs.setdefault("fillcolor", _DEFAULT_DECREASING_COLOR) - kwargs.setdefault("showlegend", False) - kwargs.setdefault("line", dict(color=_DEFAULT_DECREASING_COLOR)) - kwargs.setdefault("name", "Decreasing") - - candle_decr_data = dict( - type="box", - x=decrease_x, - y=decrease_y, - whiskerwidth=0, - boxpoints=False, - **kwargs, - ) - - return [candle_decr_data] - - -def create_candlestick(open, high, low, close, dates=None, direction="both", **kwargs): - """ - **deprecated**, use instead the plotly.graph_objects trace - :class:`plotly.graph_objects.Candlestick` - - :param (list) open: opening values - :param (list) high: high values - :param (list) low: low values - :param (list) close: closing values - :param (list) dates: list of datetime objects. Default: None - :param (string) direction: direction can be 'increasing', 'decreasing', - or 'both'. When the direction is 'increasing', the returned figure - consists of all candlesticks where the close value is greater than - the corresponding open value, and when the direction is - 'decreasing', the returned figure consists of all candlesticks - where the close value is less than or equal to the corresponding - open value. When the direction is 'both', both increasing and - decreasing candlesticks are returned. Default: 'both' - :param kwargs: kwargs passed through plotly.graph_objs.Scatter. - These kwargs describe other attributes about the ohlc Scatter trace - such as the color or the legend name. For more information on valid - kwargs call help(plotly.graph_objs.Scatter) - - :rtype (dict): returns a representation of candlestick chart figure. - - Example 1: Simple candlestick chart from a Pandas DataFrame - - >>> from plotly.figure_factory import create_candlestick - >>> from datetime import datetime - >>> import pandas as pd - - >>> df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv') - >>> fig = create_candlestick(df['AAPL.Open'], df['AAPL.High'], df['AAPL.Low'], df['AAPL.Close'], - ... dates=df.index) - >>> fig.show() - - Example 2: Customize the candlestick colors - - >>> from plotly.figure_factory import create_candlestick - >>> from plotly.graph_objs import Line, Marker - >>> from datetime import datetime - - >>> import pandas as pd - >>> df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv') - - >>> # Make increasing candlesticks and customize their color and name - >>> fig_increasing = create_candlestick(df['AAPL.Open'], df['AAPL.High'], df['AAPL.Low'], df['AAPL.Close'], - ... dates=df.index, - ... direction='increasing', name='AAPL', - ... marker=Marker(color='rgb(150, 200, 250)'), - ... line=Line(color='rgb(150, 200, 250)')) - - >>> # Make decreasing candlesticks and customize their color and name - >>> fig_decreasing = create_candlestick(df['AAPL.Open'], df['AAPL.High'], df['AAPL.Low'], df['AAPL.Close'], - ... dates=df.index, - ... direction='decreasing', - ... marker=Marker(color='rgb(128, 128, 128)'), - ... line=Line(color='rgb(128, 128, 128)')) - - >>> # Initialize the figure - >>> fig = fig_increasing - - >>> # Add decreasing data with .extend() - >>> fig.add_trace(fig_decreasing['data']) # doctest: +SKIP - >>> fig.show() - - Example 3: Candlestick chart with datetime objects - - >>> from plotly.figure_factory import create_candlestick - - >>> from datetime import datetime - - >>> # Add data - >>> open_data = [33.0, 33.3, 33.5, 33.0, 34.1] - >>> high_data = [33.1, 33.3, 33.6, 33.2, 34.8] - >>> low_data = [32.7, 32.7, 32.8, 32.6, 32.8] - >>> close_data = [33.0, 32.9, 33.3, 33.1, 33.1] - >>> dates = [datetime(year=2013, month=10, day=10), - ... datetime(year=2013, month=11, day=10), - ... datetime(year=2013, month=12, day=10), - ... datetime(year=2014, month=1, day=10), - ... datetime(year=2014, month=2, day=10)] - - >>> # Create ohlc - >>> fig = create_candlestick(open_data, high_data, - ... low_data, close_data, dates=dates) - >>> fig.show() - """ - if dates is not None: - utils.validate_equal_length(open, high, low, close, dates) - else: - utils.validate_equal_length(open, high, low, close) - validate_ohlc(open, high, low, close, direction, **kwargs) - - if direction == "increasing": - candle_incr_data = make_increasing_candle( - open, high, low, close, dates, **kwargs - ) - data = candle_incr_data - elif direction == "decreasing": - candle_decr_data = make_decreasing_candle( - open, high, low, close, dates, **kwargs - ) - data = candle_decr_data - else: - candle_incr_data = make_increasing_candle( - open, high, low, close, dates, **kwargs - ) - candle_decr_data = make_decreasing_candle( - open, high, low, close, dates, **kwargs - ) - data = candle_incr_data + candle_decr_data - - layout = graph_objs.Layout() - return graph_objs.Figure(data=data, layout=layout) - - -class _Candlestick(object): - """ - Refer to FigureFactory.create_candlestick() for docstring. - """ - - def __init__(self, open, high, low, close, dates, **kwargs): - self.open = open - self.high = high - self.low = low - self.close = close - if dates is not None: - self.x = dates - else: - self.x = [x for x in range(len(self.open))] - self.get_candle_increase() - - def get_candle_increase(self): - """ - Separate increasing data from decreasing data. - - The data is increasing when close value > open value - and decreasing when the close value <= open value. - """ - increase_y = [] - increase_x = [] - for index in range(len(self.open)): - if self.close[index] > self.open[index]: - increase_y.append(self.low[index]) - increase_y.append(self.open[index]) - increase_y.append(self.close[index]) - increase_y.append(self.close[index]) - increase_y.append(self.close[index]) - increase_y.append(self.high[index]) - increase_x.append(self.x[index]) - - increase_x = [[x, x, x, x, x, x] for x in increase_x] - increase_x = utils.flatten(increase_x) - - return increase_x, increase_y - - def get_candle_decrease(self): - """ - Separate increasing data from decreasing data. - - The data is increasing when close value > open value - and decreasing when the close value <= open value. - """ - decrease_y = [] - decrease_x = [] - for index in range(len(self.open)): - if self.close[index] <= self.open[index]: - decrease_y.append(self.low[index]) - decrease_y.append(self.open[index]) - decrease_y.append(self.close[index]) - decrease_y.append(self.close[index]) - decrease_y.append(self.close[index]) - decrease_y.append(self.high[index]) - decrease_x.append(self.x[index]) - - decrease_x = [[x, x, x, x, x, x] for x in decrease_x] - decrease_x = utils.flatten(decrease_x) - - return decrease_x, decrease_y diff --git a/plotly/figure_factory/_county_choropleth.py b/plotly/figure_factory/_county_choropleth.py deleted file mode 100644 index 7b397e7c531..00000000000 --- a/plotly/figure_factory/_county_choropleth.py +++ /dev/null @@ -1,1013 +0,0 @@ -import io -import numpy as np -import os -import pandas as pd -import warnings - -from math import log, floor -from numbers import Number - -from plotly import optional_imports -import plotly.colors as clrs -from plotly.figure_factory import utils -from plotly.exceptions import PlotlyError -import plotly.graph_objs as go - -pd.options.mode.chained_assignment = None - -shapely = optional_imports.get_module("shapely") -shapefile = optional_imports.get_module("shapefile") -gp = optional_imports.get_module("geopandas") -_plotly_geo = optional_imports.get_module("_plotly_geo") - - -def _create_us_counties_df(st_to_state_name_dict, state_to_st_dict): - # URLS - abs_dir_path = os.path.realpath(_plotly_geo.__file__) - - abs_plotly_geo_path = os.path.dirname(abs_dir_path) - - abs_package_data_dir_path = os.path.join(abs_plotly_geo_path, "package_data") - - shape_pre2010 = "gz_2010_us_050_00_500k.shp" - shape_pre2010 = os.path.join(abs_package_data_dir_path, shape_pre2010) - - df_shape_pre2010 = gp.read_file(shape_pre2010) - df_shape_pre2010["FIPS"] = df_shape_pre2010["STATE"] + df_shape_pre2010["COUNTY"] - df_shape_pre2010["FIPS"] = pd.to_numeric(df_shape_pre2010["FIPS"]) - - states_path = "cb_2016_us_state_500k.shp" - states_path = os.path.join(abs_package_data_dir_path, states_path) - - df_state = gp.read_file(states_path) - df_state = df_state[["STATEFP", "NAME", "geometry"]] - df_state = df_state.rename(columns={"NAME": "STATE_NAME"}) - - filenames = [ - "cb_2016_us_county_500k.dbf", - "cb_2016_us_county_500k.shp", - "cb_2016_us_county_500k.shx", - ] - - for j in range(len(filenames)): - filenames[j] = os.path.join(abs_package_data_dir_path, filenames[j]) - - dbf = io.open(filenames[0], "rb") - shp = io.open(filenames[1], "rb") - shx = io.open(filenames[2], "rb") - - r = shapefile.Reader(shp=shp, shx=shx, dbf=dbf) - - attributes, geometry = [], [] - field_names = [field[0] for field in r.fields[1:]] - for row in r.shapeRecords(): - geometry.append(shapely.geometry.shape(row.shape.__geo_interface__)) - attributes.append(dict(zip(field_names, row.record))) - - gdf = gp.GeoDataFrame(data=attributes, geometry=geometry) - - gdf["FIPS"] = gdf["STATEFP"] + gdf["COUNTYFP"] - gdf["FIPS"] = pd.to_numeric(gdf["FIPS"]) - - # add missing counties - f = 46113 - singlerow = pd.DataFrame( - [ - [ - st_to_state_name_dict["SD"], - "SD", - df_shape_pre2010[df_shape_pre2010["FIPS"] == f]["geometry"].iloc[0], - df_shape_pre2010[df_shape_pre2010["FIPS"] == f]["FIPS"].iloc[0], - "46", - "Shannon", - ] - ], - columns=["State", "ST", "geometry", "FIPS", "STATEFP", "NAME"], - index=[max(gdf.index) + 1], - ) - gdf = pd.concat([gdf, singlerow], sort=True) - - f = 51515 - singlerow = pd.DataFrame( - [ - [ - st_to_state_name_dict["VA"], - "VA", - df_shape_pre2010[df_shape_pre2010["FIPS"] == f]["geometry"].iloc[0], - df_shape_pre2010[df_shape_pre2010["FIPS"] == f]["FIPS"].iloc[0], - "51", - "Bedford City", - ] - ], - columns=["State", "ST", "geometry", "FIPS", "STATEFP", "NAME"], - index=[max(gdf.index) + 1], - ) - gdf = pd.concat([gdf, singlerow], sort=True) - - f = 2270 - singlerow = pd.DataFrame( - [ - [ - st_to_state_name_dict["AK"], - "AK", - df_shape_pre2010[df_shape_pre2010["FIPS"] == f]["geometry"].iloc[0], - df_shape_pre2010[df_shape_pre2010["FIPS"] == f]["FIPS"].iloc[0], - "02", - "Wade Hampton", - ] - ], - columns=["State", "ST", "geometry", "FIPS", "STATEFP", "NAME"], - index=[max(gdf.index) + 1], - ) - gdf = pd.concat([gdf, singlerow], sort=True) - - row_2198 = gdf[gdf["FIPS"] == 2198] - row_2198.index = [max(gdf.index) + 1] - row_2198.loc[row_2198.index[0], "FIPS"] = 2201 - row_2198.loc[row_2198.index[0], "STATEFP"] = "02" - gdf = pd.concat([gdf, row_2198], sort=True) - - row_2105 = gdf[gdf["FIPS"] == 2105] - row_2105.index = [max(gdf.index) + 1] - row_2105.loc[row_2105.index[0], "FIPS"] = 2232 - row_2105.loc[row_2105.index[0], "STATEFP"] = "02" - gdf = pd.concat([gdf, row_2105], sort=True) - gdf = gdf.rename(columns={"NAME": "COUNTY_NAME"}) - - gdf_reduced = gdf[["FIPS", "STATEFP", "COUNTY_NAME", "geometry"]] - gdf_statefp = gdf_reduced.merge(df_state[["STATEFP", "STATE_NAME"]], on="STATEFP") - - ST = [] - for n in gdf_statefp["STATE_NAME"]: - ST.append(state_to_st_dict[n]) - - gdf_statefp["ST"] = ST - return gdf_statefp, df_state - - -st_to_state_name_dict = { - "AK": "Alaska", - "AL": "Alabama", - "AR": "Arkansas", - "AZ": "Arizona", - "CA": "California", - "CO": "Colorado", - "CT": "Connecticut", - "DC": "District of Columbia", - "DE": "Delaware", - "FL": "Florida", - "GA": "Georgia", - "HI": "Hawaii", - "IA": "Iowa", - "ID": "Idaho", - "IL": "Illinois", - "IN": "Indiana", - "KS": "Kansas", - "KY": "Kentucky", - "LA": "Louisiana", - "MA": "Massachusetts", - "MD": "Maryland", - "ME": "Maine", - "MI": "Michigan", - "MN": "Minnesota", - "MO": "Missouri", - "MS": "Mississippi", - "MT": "Montana", - "NC": "North Carolina", - "ND": "North Dakota", - "NE": "Nebraska", - "NH": "New Hampshire", - "NJ": "New Jersey", - "NM": "New Mexico", - "NV": "Nevada", - "NY": "New York", - "OH": "Ohio", - "OK": "Oklahoma", - "OR": "Oregon", - "PA": "Pennsylvania", - "RI": "Rhode Island", - "SC": "South Carolina", - "SD": "South Dakota", - "TN": "Tennessee", - "TX": "Texas", - "UT": "Utah", - "VA": "Virginia", - "VT": "Vermont", - "WA": "Washington", - "WI": "Wisconsin", - "WV": "West Virginia", - "WY": "Wyoming", -} - -state_to_st_dict = { - "Alabama": "AL", - "Alaska": "AK", - "American Samoa": "AS", - "Arizona": "AZ", - "Arkansas": "AR", - "California": "CA", - "Colorado": "CO", - "Commonwealth of the Northern Mariana Islands": "MP", - "Connecticut": "CT", - "Delaware": "DE", - "District of Columbia": "DC", - "Florida": "FL", - "Georgia": "GA", - "Guam": "GU", - "Hawaii": "HI", - "Idaho": "ID", - "Illinois": "IL", - "Indiana": "IN", - "Iowa": "IA", - "Kansas": "KS", - "Kentucky": "KY", - "Louisiana": "LA", - "Maine": "ME", - "Maryland": "MD", - "Massachusetts": "MA", - "Michigan": "MI", - "Minnesota": "MN", - "Mississippi": "MS", - "Missouri": "MO", - "Montana": "MT", - "Nebraska": "NE", - "Nevada": "NV", - "New Hampshire": "NH", - "New Jersey": "NJ", - "New Mexico": "NM", - "New York": "NY", - "North Carolina": "NC", - "North Dakota": "ND", - "Ohio": "OH", - "Oklahoma": "OK", - "Oregon": "OR", - "Pennsylvania": "PA", - "Puerto Rico": "", - "Rhode Island": "RI", - "South Carolina": "SC", - "South Dakota": "SD", - "Tennessee": "TN", - "Texas": "TX", - "United States Virgin Islands": "VI", - "Utah": "UT", - "Vermont": "VT", - "Virginia": "VA", - "Washington": "WA", - "West Virginia": "WV", - "Wisconsin": "WI", - "Wyoming": "WY", -} - -USA_XRANGE = [-125.0, -65.0] -USA_YRANGE = [25.0, 49.0] - - -def _human_format(number): - units = ["", "K", "M", "G", "T", "P"] - k = 1000.0 - magnitude = int(floor(log(number, k))) - return "%.2f%s" % (number / k**magnitude, units[magnitude]) - - -def _intervals_as_labels(array_of_intervals, round_legend_values, exponent_format): - """ - Transform an number interval to a clean string for legend - - Example: [-inf, 30] to '< 30' - """ - infs = [float("-inf"), float("inf")] - string_intervals = [] - for interval in array_of_intervals: - # round to 2nd decimal place - if round_legend_values: - rnd_interval = [ - (int(interval[i]) if interval[i] not in infs else interval[i]) - for i in range(2) - ] - else: - rnd_interval = [round(interval[0], 2), round(interval[1], 2)] - - num0 = rnd_interval[0] - num1 = rnd_interval[1] - if exponent_format: - if num0 not in infs: - num0 = _human_format(num0) - if num1 not in infs: - num1 = _human_format(num1) - else: - if num0 not in infs: - num0 = "{:,}".format(num0) - if num1 not in infs: - num1 = "{:,}".format(num1) - - if num0 == float("-inf"): - as_str = "< {}".format(num1) - elif num1 == float("inf"): - as_str = "> {}".format(num0) - else: - as_str = "{} - {}".format(num0, num1) - string_intervals.append(as_str) - return string_intervals - - -def _calculations( - df, - fips, - values, - index, - f, - simplify_county, - level, - x_centroids, - y_centroids, - centroid_text, - x_traces, - y_traces, - fips_polygon_map, -): - # 0-pad FIPS code to ensure exactly 5 digits - padded_f = str(f).zfill(5) - if fips_polygon_map[f].type == "Polygon": - x = fips_polygon_map[f].simplify(simplify_county).exterior.xy[0].tolist() - y = fips_polygon_map[f].simplify(simplify_county).exterior.xy[1].tolist() - - x_c, y_c = fips_polygon_map[f].centroid.xy - county_name_str = str(df[df["FIPS"] == f]["COUNTY_NAME"].iloc[0]) - state_name_str = str(df[df["FIPS"] == f]["STATE_NAME"].iloc[0]) - - t_c = ( - "County: " - + county_name_str - + "
" - + "State: " - + state_name_str - + "
" - + "FIPS: " - + padded_f - + "
Value: " - + str(values[index]) - ) - - x_centroids.append(x_c[0]) - y_centroids.append(y_c[0]) - centroid_text.append(t_c) - - x_traces[level] = x_traces[level] + x + [np.nan] - y_traces[level] = y_traces[level] + y + [np.nan] - elif fips_polygon_map[f].type == "MultiPolygon": - x = [ - poly.simplify(simplify_county).exterior.xy[0].tolist() - for poly in fips_polygon_map[f].geoms - ] - y = [ - poly.simplify(simplify_county).exterior.xy[1].tolist() - for poly in fips_polygon_map[f].geoms - ] - - x_c = [poly.centroid.xy[0].tolist() for poly in fips_polygon_map[f].geoms] - y_c = [poly.centroid.xy[1].tolist() for poly in fips_polygon_map[f].geoms] - - county_name_str = str(df[df["FIPS"] == f]["COUNTY_NAME"].iloc[0]) - state_name_str = str(df[df["FIPS"] == f]["STATE_NAME"].iloc[0]) - text = ( - "County: " - + county_name_str - + "
" - + "State: " - + state_name_str - + "
" - + "FIPS: " - + padded_f - + "
Value: " - + str(values[index]) - ) - t_c = [text for poly in fips_polygon_map[f].geoms] - x_centroids = x_c + x_centroids - y_centroids = y_c + y_centroids - centroid_text = t_c + centroid_text - for x_y_idx in range(len(x)): - x_traces[level] = x_traces[level] + x[x_y_idx] + [np.nan] - y_traces[level] = y_traces[level] + y[x_y_idx] + [np.nan] - - return x_traces, y_traces, x_centroids, y_centroids, centroid_text - - -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, -): - """ - **deprecated**, use instead - :func:`plotly.express.choropleth` with custom GeoJSON. - - This function also requires `shapely`, `geopandas` and `plotly-geo` to be installed. - - 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, - ) - - Example 2: New England:: - - 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 - ) - fig.show() - - Example 3: California and Surrounding States:: - - 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' - ) - fig.show() - - Example 4: USA:: - - 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 %' - ) - fig.show() - """ - # ensure optional modules imported - if not _plotly_geo: - raise ValueError( - """ -The create_choropleth figure factory requires the plotly-geo package. -Install using pip with: - -$ pip install plotly-geo - -Or, install using conda with - -$ conda install -c plotly plotly-geo -""" - ) - - 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 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 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 = clrs.colorscale_to_colors(clrs.PLOTLY_SCALES["Viridis"]) - viridis_colors = clrs.color_parser(viridis_colors, clrs.hex_to_rgb) - viridis_colors = clrs.color_parser(viridis_colors, clrs.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 = clrs.find_intermediate_color( - viridis_colors[idx], viridis_colors[idx], intermed, colortype="rgb" - ) - - # make R,G,B into int values - float_color = clrs.unlabel_rgb(float_color) - float_color = clrs.unconvert_from_RGB_255(float_color) - int_rgb = clrs.convert_to_RGB_255(float_color) - int_rgb = clrs.label_rgb(int_rgb) - - colorscale.append(int_rgb) - - if len(colorscale) < len(LEVELS): - raise 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 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].geoms - ] - y = [ - poly.simplify(simplify_state).exterior.xy[1].tolist() - for poly in df_state["geometry"][index].geoms - ] - 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="" + legend_title + "", - ) - ) - - 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.0, - sum(fig["layout"]["yaxis"]["range"]) / 2.0, - ) - - 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 go.Figure(fig) diff --git a/plotly/figure_factory/_distplot.py b/plotly/figure_factory/_distplot.py deleted file mode 100644 index 73f66096456..00000000000 --- a/plotly/figure_factory/_distplot.py +++ /dev/null @@ -1,441 +0,0 @@ -from plotly import exceptions, optional_imports -from plotly.figure_factory import utils -from plotly.graph_objs import graph_objs - -# Optional imports, may be None for users that only use our core functionality. -np = optional_imports.get_module("numpy") -pd = optional_imports.get_module("pandas") -scipy = optional_imports.get_module("scipy") -scipy_stats = optional_imports.get_module("scipy.stats") - - -DEFAULT_HISTNORM = "probability density" -ALTERNATIVE_HISTNORM = "probability" - - -def validate_distplot(hist_data, curve_type): - """ - Distplot-specific validations - - :raises: (PlotlyError) If hist_data is not a list of lists - :raises: (PlotlyError) If curve_type is not valid (i.e. not 'kde' or - 'normal'). - """ - hist_data_types = (list,) - if np: - hist_data_types += (np.ndarray,) - if pd: - hist_data_types += (pd.core.series.Series,) - - if not isinstance(hist_data[0], hist_data_types): - raise exceptions.PlotlyError( - "Oops, this function was written " - "to handle multiple datasets, if " - "you want to plot just one, make " - "sure your hist_data variable is " - "still a list of lists, i.e. x = " - "[1, 2, 3] -> x = [[1, 2, 3]]" - ) - - curve_opts = ("kde", "normal") - if curve_type not in curve_opts: - raise exceptions.PlotlyError("curve_type must be defined as 'kde' or 'normal'") - - if not scipy: - raise ImportError("FigureFactory.create_distplot requires scipy") - - -def create_distplot( - hist_data, - group_labels, - bin_size=1.0, - curve_type="kde", - colors=None, - rug_text=None, - histnorm=DEFAULT_HISTNORM, - show_hist=True, - show_curve=True, - show_rug=True, -): - """ - Function that creates a distplot similar to seaborn.distplot; - **this function is deprecated**, use instead :mod:`plotly.express` - functions, for example - - >>> import plotly.express as px - >>> tips = px.data.tips() - >>> fig = px.histogram(tips, x="total_bill", y="tip", color="sex", marginal="rug", - ... hover_data=tips.columns) - >>> fig.show() - - - The distplot can be composed of all or any combination of the following - 3 components: (1) histogram, (2) curve: (a) kernel density estimation - or (b) normal curve, and (3) rug plot. Additionally, multiple distplots - (from multiple datasets) can be created in the same plot. - - :param (list[list]) hist_data: Use list of lists to plot multiple data - sets on the same plot. - :param (list[str]) group_labels: Names for each data set. - :param (list[float]|float) bin_size: Size of histogram bins. - Default = 1. - :param (str) curve_type: 'kde' or 'normal'. Default = 'kde' - :param (str) histnorm: 'probability density' or 'probability' - Default = 'probability density' - :param (bool) show_hist: Add histogram to distplot? Default = True - :param (bool) show_curve: Add curve to distplot? Default = True - :param (bool) show_rug: Add rug to distplot? Default = True - :param (list[str]) colors: Colors for traces. - :param (list[list]) rug_text: Hovertext values for rug_plot, - :return (dict): Representation of a distplot figure. - - Example 1: Simple distplot of 1 data set - - >>> from plotly.figure_factory import create_distplot - - >>> hist_data = [[1.1, 1.1, 2.5, 3.0, 3.5, - ... 3.5, 4.1, 4.4, 4.5, 4.5, - ... 5.0, 5.0, 5.2, 5.5, 5.5, - ... 5.5, 5.5, 5.5, 6.1, 7.0]] - >>> group_labels = ['distplot example'] - >>> fig = create_distplot(hist_data, group_labels) - >>> fig.show() - - - Example 2: Two data sets and added rug text - - >>> from plotly.figure_factory import create_distplot - >>> # Add histogram data - >>> hist1_x = [0.8, 1.2, 0.2, 0.6, 1.6, - ... -0.9, -0.07, 1.95, 0.9, -0.2, - ... -0.5, 0.3, 0.4, -0.37, 0.6] - >>> hist2_x = [0.8, 1.5, 1.5, 0.6, 0.59, - ... 1.0, 0.8, 1.7, 0.5, 0.8, - ... -0.3, 1.2, 0.56, 0.3, 2.2] - - >>> # Group data together - >>> hist_data = [hist1_x, hist2_x] - - >>> group_labels = ['2012', '2013'] - - >>> # Add text - >>> rug_text_1 = ['a1', 'b1', 'c1', 'd1', 'e1', - ... 'f1', 'g1', 'h1', 'i1', 'j1', - ... 'k1', 'l1', 'm1', 'n1', 'o1'] - - >>> rug_text_2 = ['a2', 'b2', 'c2', 'd2', 'e2', - ... 'f2', 'g2', 'h2', 'i2', 'j2', - ... 'k2', 'l2', 'm2', 'n2', 'o2'] - - >>> # Group text together - >>> rug_text_all = [rug_text_1, rug_text_2] - - >>> # Create distplot - >>> fig = create_distplot( - ... hist_data, group_labels, rug_text=rug_text_all, bin_size=.2) - - >>> # Add title - >>> fig.update_layout(title='Dist Plot') # doctest: +SKIP - >>> fig.show() - - - Example 3: Plot with normal curve and hide rug plot - - >>> from plotly.figure_factory import create_distplot - >>> import numpy as np - - >>> x1 = np.random.randn(190) - >>> x2 = np.random.randn(200)+1 - >>> x3 = np.random.randn(200)-1 - >>> x4 = np.random.randn(210)+2 - - >>> hist_data = [x1, x2, x3, x4] - >>> group_labels = ['2012', '2013', '2014', '2015'] - - >>> fig = create_distplot( - ... hist_data, group_labels, curve_type='normal', - ... show_rug=False, bin_size=.4) - - - Example 4: Distplot with Pandas - - >>> from plotly.figure_factory import create_distplot - >>> import numpy as np - >>> import pandas as pd - - >>> df = pd.DataFrame({'2012': np.random.randn(200), - ... '2013': np.random.randn(200)+1}) - >>> fig = create_distplot([df[c] for c in df.columns], df.columns) - >>> fig.show() - """ - if colors is None: - colors = [] - if rug_text is None: - rug_text = [] - - validate_distplot(hist_data, curve_type) - utils.validate_equal_length(hist_data, group_labels) - - if isinstance(bin_size, (float, int)): - bin_size = [bin_size] * len(hist_data) - - data = [] - if show_hist: - hist = _Distplot( - hist_data, - histnorm, - group_labels, - bin_size, - curve_type, - colors, - rug_text, - show_hist, - show_curve, - ).make_hist() - - data.append(hist) - - if show_curve: - if curve_type == "normal": - curve = _Distplot( - hist_data, - histnorm, - group_labels, - bin_size, - curve_type, - colors, - rug_text, - show_hist, - show_curve, - ).make_normal() - else: - curve = _Distplot( - hist_data, - histnorm, - group_labels, - bin_size, - curve_type, - colors, - rug_text, - show_hist, - show_curve, - ).make_kde() - - data.append(curve) - - if show_rug: - rug = _Distplot( - hist_data, - histnorm, - group_labels, - bin_size, - curve_type, - colors, - rug_text, - show_hist, - show_curve, - ).make_rug() - - data.append(rug) - layout = graph_objs.Layout( - barmode="overlay", - hovermode="closest", - legend=dict(traceorder="reversed"), - xaxis1=dict(domain=[0.0, 1.0], anchor="y2", zeroline=False), - yaxis1=dict(domain=[0.35, 1], anchor="free", position=0.0), - yaxis2=dict(domain=[0, 0.25], anchor="x1", dtick=1, showticklabels=False), - ) - else: - layout = graph_objs.Layout( - barmode="overlay", - hovermode="closest", - legend=dict(traceorder="reversed"), - xaxis1=dict(domain=[0.0, 1.0], anchor="y2", zeroline=False), - yaxis1=dict(domain=[0.0, 1], anchor="free", position=0.0), - ) - - data = sum(data, []) - return graph_objs.Figure(data=data, layout=layout) - - -class _Distplot(object): - """ - Refer to TraceFactory.create_distplot() for docstring - """ - - def __init__( - self, - hist_data, - histnorm, - group_labels, - bin_size, - curve_type, - colors, - rug_text, - show_hist, - show_curve, - ): - self.hist_data = hist_data - self.histnorm = histnorm - self.group_labels = group_labels - self.bin_size = bin_size - self.show_hist = show_hist - self.show_curve = show_curve - self.trace_number = len(hist_data) - if rug_text: - self.rug_text = rug_text - else: - self.rug_text = [None] * self.trace_number - - self.start = [] - self.end = [] - if colors: - self.colors = colors - else: - self.colors = [ - "rgb(31, 119, 180)", - "rgb(255, 127, 14)", - "rgb(44, 160, 44)", - "rgb(214, 39, 40)", - "rgb(148, 103, 189)", - "rgb(140, 86, 75)", - "rgb(227, 119, 194)", - "rgb(127, 127, 127)", - "rgb(188, 189, 34)", - "rgb(23, 190, 207)", - ] - self.curve_x = [None] * self.trace_number - self.curve_y = [None] * self.trace_number - - for trace in self.hist_data: - self.start.append(min(trace) * 1.0) - self.end.append(max(trace) * 1.0) - - def make_hist(self): - """ - Makes the histogram(s) for FigureFactory.create_distplot(). - - :rtype (list) hist: list of histogram representations - """ - hist = [None] * self.trace_number - - for index in range(self.trace_number): - hist[index] = dict( - type="histogram", - x=self.hist_data[index], - xaxis="x1", - yaxis="y1", - histnorm=self.histnorm, - name=self.group_labels[index], - legendgroup=self.group_labels[index], - marker=dict(color=self.colors[index % len(self.colors)]), - autobinx=False, - xbins=dict( - start=self.start[index], - end=self.end[index], - size=self.bin_size[index], - ), - opacity=0.7, - ) - return hist - - def make_kde(self): - """ - Makes the kernel density estimation(s) for create_distplot(). - - This is called when curve_type = 'kde' in create_distplot(). - - :rtype (list) curve: list of kde representations - """ - curve = [None] * self.trace_number - for index in range(self.trace_number): - self.curve_x[index] = [ - self.start[index] + x * (self.end[index] - self.start[index]) / 500 - for x in range(500) - ] - self.curve_y[index] = scipy_stats.gaussian_kde(self.hist_data[index])( - self.curve_x[index] - ) - - if self.histnorm == ALTERNATIVE_HISTNORM: - self.curve_y[index] *= self.bin_size[index] - - for index in range(self.trace_number): - curve[index] = dict( - type="scatter", - x=self.curve_x[index], - y=self.curve_y[index], - xaxis="x1", - yaxis="y1", - mode="lines", - name=self.group_labels[index], - legendgroup=self.group_labels[index], - showlegend=False if self.show_hist else True, - marker=dict(color=self.colors[index % len(self.colors)]), - ) - return curve - - def make_normal(self): - """ - Makes the normal curve(s) for create_distplot(). - - This is called when curve_type = 'normal' in create_distplot(). - - :rtype (list) curve: list of normal curve representations - """ - curve = [None] * self.trace_number - mean = [None] * self.trace_number - sd = [None] * self.trace_number - - for index in range(self.trace_number): - mean[index], sd[index] = scipy_stats.norm.fit(self.hist_data[index]) - self.curve_x[index] = [ - self.start[index] + x * (self.end[index] - self.start[index]) / 500 - for x in range(500) - ] - self.curve_y[index] = scipy_stats.norm.pdf( - self.curve_x[index], loc=mean[index], scale=sd[index] - ) - - if self.histnorm == ALTERNATIVE_HISTNORM: - self.curve_y[index] *= self.bin_size[index] - - for index in range(self.trace_number): - curve[index] = dict( - type="scatter", - x=self.curve_x[index], - y=self.curve_y[index], - xaxis="x1", - yaxis="y1", - mode="lines", - name=self.group_labels[index], - legendgroup=self.group_labels[index], - showlegend=False if self.show_hist else True, - marker=dict(color=self.colors[index % len(self.colors)]), - ) - return curve - - def make_rug(self): - """ - Makes the rug plot(s) for create_distplot(). - - :rtype (list) rug: list of rug plot representations - """ - rug = [None] * self.trace_number - for index in range(self.trace_number): - rug[index] = dict( - type="scatter", - x=self.hist_data[index], - y=([self.group_labels[index]] * len(self.hist_data[index])), - xaxis="x1", - yaxis="y2", - mode="markers", - name=self.group_labels[index], - legendgroup=self.group_labels[index], - showlegend=(False if self.show_hist or self.show_curve else True), - text=self.rug_text[index], - marker=dict( - color=self.colors[index % len(self.colors)], symbol="line-ns-open" - ), - ) - return rug diff --git a/plotly/figure_factory/_facet_grid.py b/plotly/figure_factory/_facet_grid.py deleted file mode 100644 index 3dc62ebe2ee..00000000000 --- a/plotly/figure_factory/_facet_grid.py +++ /dev/null @@ -1,1195 +0,0 @@ -from plotly import exceptions, optional_imports -import plotly.colors as clrs -from plotly.figure_factory import utils -from plotly.subplots import make_subplots - -import math -from numbers import Number - -pd = optional_imports.get_module("pandas") - -TICK_COLOR = "#969696" -AXIS_TITLE_COLOR = "#0f0f0f" -AXIS_TITLE_SIZE = 12 -GRID_COLOR = "#ffffff" -LEGEND_COLOR = "#efefef" -PLOT_BGCOLOR = "#ededed" -ANNOT_RECT_COLOR = "#d0d0d0" -LEGEND_BORDER_WIDTH = 1 -LEGEND_ANNOT_X = 1.05 -LEGEND_ANNOT_Y = 0.5 -MAX_TICKS_PER_AXIS = 5 -THRES_FOR_FLIPPED_FACET_TITLES = 10 -GRID_WIDTH = 1 - -VALID_TRACE_TYPES = ["scatter", "scattergl", "histogram", "bar", "box"] - -CUSTOM_LABEL_ERROR = ( - "If you are using a dictionary for custom labels for the facet row/col, " - "make sure each key in that column of the dataframe is in your facet " - "labels. The keys you need are {}" -) - - -def _is_flipped(num): - if num >= THRES_FOR_FLIPPED_FACET_TITLES: - flipped = True - else: - flipped = False - return flipped - - -def _return_label(original_label, facet_labels, facet_var): - if isinstance(facet_labels, dict): - label = facet_labels[original_label] - elif isinstance(facet_labels, str): - label = "{}: {}".format(facet_var, original_label) - else: - label = original_label - return label - - -def _legend_annotation(color_name): - legend_title = dict( - textangle=0, - xanchor="left", - yanchor="middle", - x=LEGEND_ANNOT_X, - y=1.03, - showarrow=False, - xref="paper", - yref="paper", - text="factor({})".format(color_name), - font=dict(size=13, color="#000000"), - ) - return legend_title - - -def _annotation_dict( - text, lane, num_of_lanes, SUBPLOT_SPACING, row_col="col", flipped=True -): - temp = (1 - (num_of_lanes - 1) * SUBPLOT_SPACING) / (num_of_lanes) - if not flipped: - xanchor = "center" - yanchor = "middle" - if row_col == "col": - x = (lane - 1) * (temp + SUBPLOT_SPACING) + 0.5 * temp - y = 1.03 - textangle = 0 - elif row_col == "row": - y = (lane - 1) * (temp + SUBPLOT_SPACING) + 0.5 * temp - x = 1.03 - textangle = 90 - else: - if row_col == "col": - xanchor = "center" - yanchor = "bottom" - x = (lane - 1) * (temp + SUBPLOT_SPACING) + 0.5 * temp - y = 1.0 - textangle = 270 - elif row_col == "row": - xanchor = "left" - yanchor = "middle" - y = (lane - 1) * (temp + SUBPLOT_SPACING) + 0.5 * temp - x = 1.0 - textangle = 0 - - annotation_dict = dict( - textangle=textangle, - xanchor=xanchor, - yanchor=yanchor, - x=x, - y=y, - showarrow=False, - xref="paper", - yref="paper", - text=str(text), - font=dict(size=13, color=AXIS_TITLE_COLOR), - ) - return annotation_dict - - -def _axis_title_annotation(text, x_or_y_axis): - if x_or_y_axis == "x": - x_pos = 0.5 - y_pos = -0.1 - textangle = 0 - elif x_or_y_axis == "y": - x_pos = -0.1 - y_pos = 0.5 - textangle = 270 - - if not text: - text = "" - - annot = { - "font": {"color": "#000000", "size": AXIS_TITLE_SIZE}, - "showarrow": False, - "text": text, - "textangle": textangle, - "x": x_pos, - "xanchor": "center", - "xref": "paper", - "y": y_pos, - "yanchor": "middle", - "yref": "paper", - } - return annot - - -def _add_shapes_to_fig(fig, annot_rect_color, flipped_rows=False, flipped_cols=False): - shapes_list = [] - for key in fig["layout"].to_plotly_json().keys(): - if "axis" in key and fig["layout"][key]["domain"] != [0.0, 1.0]: - shape = { - "fillcolor": annot_rect_color, - "layer": "below", - "line": {"color": annot_rect_color, "width": 1}, - "type": "rect", - "xref": "paper", - "yref": "paper", - } - - if "xaxis" in key: - shape["x0"] = fig["layout"][key]["domain"][0] - shape["x1"] = fig["layout"][key]["domain"][1] - shape["y0"] = 1.005 - shape["y1"] = 1.05 - - if flipped_cols: - shape["y1"] += 0.5 - shapes_list.append(shape) - - elif "yaxis" in key: - shape["x0"] = 1.005 - shape["x1"] = 1.05 - shape["y0"] = fig["layout"][key]["domain"][0] - shape["y1"] = fig["layout"][key]["domain"][1] - - if flipped_rows: - shape["x1"] += 1 - shapes_list.append(shape) - - fig["layout"]["shapes"] = shapes_list - - -def _make_trace_for_scatter(trace, trace_type, color, **kwargs_marker): - if trace_type in ["scatter", "scattergl"]: - trace["mode"] = "markers" - trace["marker"] = dict(color=color, **kwargs_marker) - return trace - - -def _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, -): - fig = make_subplots( - rows=num_of_rows, - cols=num_of_cols, - shared_xaxes=True, - shared_yaxes=True, - horizontal_spacing=SUBPLOT_SPACING, - vertical_spacing=SUBPLOT_SPACING, - print_grid=False, - ) - - annotations = [] - if not facet_row and not facet_col: - color_groups = list(df.groupby(color_name)) - for group in color_groups: - trace = dict( - type=trace_type, - name=group[0], - marker=dict(color=colormap[group[0]]), - **kwargs_trace, - ) - if x: - trace["x"] = group[1][x] - if y: - trace["y"] = group[1][y] - trace = _make_trace_for_scatter( - trace, trace_type, colormap[group[0]], **kwargs_marker - ) - - fig.append_trace(trace, 1, 1) - - elif (facet_row and not facet_col) or (not facet_row and facet_col): - groups_by_facet = list(df.groupby(facet_row if facet_row else facet_col)) - for j, group in enumerate(groups_by_facet): - for color_val in df[color_name].unique(): - data_by_color = group[1][group[1][color_name] == color_val] - trace = dict( - type=trace_type, - name=color_val, - marker=dict(color=colormap[color_val]), - **kwargs_trace, - ) - if x: - trace["x"] = data_by_color[x] - if y: - trace["y"] = data_by_color[y] - trace = _make_trace_for_scatter( - trace, trace_type, colormap[color_val], **kwargs_marker - ) - - fig.append_trace( - trace, j + 1 if facet_row else 1, 1 if facet_row else j + 1 - ) - - label = _return_label( - group[0], - facet_row_labels if facet_row else facet_col_labels, - facet_row if facet_row else facet_col, - ) - - annotations.append( - _annotation_dict( - label, - num_of_rows - j if facet_row else j + 1, - num_of_rows if facet_row else num_of_cols, - SUBPLOT_SPACING, - "row" if facet_row else "col", - flipped_rows, - ) - ) - - elif facet_row and facet_col: - groups_by_facets = list(df.groupby([facet_row, facet_col])) - tuple_to_facet_group = {item[0]: item[1] for item in groups_by_facets} - - row_values = df[facet_row].unique() - col_values = df[facet_col].unique() - color_vals = df[color_name].unique() - for row_count, x_val in enumerate(row_values): - for col_count, y_val in enumerate(col_values): - try: - group = tuple_to_facet_group[(x_val, y_val)] - except KeyError: - group = pd.DataFrame( - [[None, None, None]], columns=[x, y, color_name] - ) - - for color_val in color_vals: - if group.values.tolist() != [[None, None, None]]: - group_filtered = group[group[color_name] == color_val] - - trace = dict( - type=trace_type, - name=color_val, - marker=dict(color=colormap[color_val]), - **kwargs_trace, - ) - new_x = group_filtered[x] - new_y = group_filtered[y] - else: - trace = dict( - type=trace_type, - name=color_val, - marker=dict(color=colormap[color_val]), - showlegend=False, - **kwargs_trace, - ) - new_x = group[x] - new_y = group[y] - - if x: - trace["x"] = new_x - if y: - trace["y"] = new_y - trace = _make_trace_for_scatter( - trace, trace_type, colormap[color_val], **kwargs_marker - ) - - fig.append_trace(trace, row_count + 1, col_count + 1) - if row_count == 0: - label = _return_label( - col_values[col_count], facet_col_labels, facet_col - ) - annotations.append( - _annotation_dict( - label, - col_count + 1, - num_of_cols, - SUBPLOT_SPACING, - row_col="col", - flipped=flipped_cols, - ) - ) - label = _return_label(row_values[row_count], facet_row_labels, facet_row) - annotations.append( - _annotation_dict( - label, - num_of_rows - row_count, - num_of_rows, - SUBPLOT_SPACING, - row_col="row", - flipped=flipped_rows, - ) - ) - - return fig, annotations - - -def _facet_grid_color_numerical( - 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, -): - fig = make_subplots( - rows=num_of_rows, - cols=num_of_cols, - shared_xaxes=True, - shared_yaxes=True, - horizontal_spacing=SUBPLOT_SPACING, - vertical_spacing=SUBPLOT_SPACING, - print_grid=False, - ) - - annotations = [] - if not facet_row and not facet_col: - trace = dict( - type=trace_type, - marker=dict(color=df[color_name], colorscale=colormap, showscale=True), - **kwargs_trace, - ) - if x: - trace["x"] = df[x] - if y: - trace["y"] = df[y] - trace = _make_trace_for_scatter( - trace, trace_type, df[color_name], **kwargs_marker - ) - - fig.append_trace(trace, 1, 1) - - if (facet_row and not facet_col) or (not facet_row and facet_col): - groups_by_facet = list(df.groupby(facet_row if facet_row else facet_col)) - for j, group in enumerate(groups_by_facet): - trace = dict( - type=trace_type, - marker=dict( - color=df[color_name], - colorscale=colormap, - showscale=True, - colorbar=dict(x=1.15), - ), - **kwargs_trace, - ) - if x: - trace["x"] = group[1][x] - if y: - trace["y"] = group[1][y] - trace = _make_trace_for_scatter( - trace, trace_type, df[color_name], **kwargs_marker - ) - - fig.append_trace( - trace, j + 1 if facet_row else 1, 1 if facet_row else j + 1 - ) - - labels = facet_row_labels if facet_row else facet_col_labels - label = _return_label( - group[0], labels, facet_row if facet_row else facet_col - ) - - annotations.append( - _annotation_dict( - label, - num_of_rows - j if facet_row else j + 1, - num_of_rows if facet_row else num_of_cols, - SUBPLOT_SPACING, - "row" if facet_row else "col", - flipped=flipped_rows, - ) - ) - - elif facet_row and facet_col: - groups_by_facets = list(df.groupby([facet_row, facet_col])) - tuple_to_facet_group = {item[0]: item[1] for item in groups_by_facets} - - row_values = df[facet_row].unique() - col_values = df[facet_col].unique() - for row_count, x_val in enumerate(row_values): - for col_count, y_val in enumerate(col_values): - try: - group = tuple_to_facet_group[(x_val, y_val)] - except KeyError: - group = pd.DataFrame( - [[None, None, None]], columns=[x, y, color_name] - ) - - if group.values.tolist() != [[None, None, None]]: - trace = dict( - type=trace_type, - marker=dict( - color=df[color_name], - colorscale=colormap, - showscale=(row_count == 0), - colorbar=dict(x=1.15), - ), - **kwargs_trace, - ) - - else: - trace = dict(type=trace_type, showlegend=False, **kwargs_trace) - - if x: - trace["x"] = group[x] - if y: - trace["y"] = group[y] - trace = _make_trace_for_scatter( - trace, trace_type, df[color_name], **kwargs_marker - ) - - fig.append_trace(trace, row_count + 1, col_count + 1) - if row_count == 0: - label = _return_label( - col_values[col_count], facet_col_labels, facet_col - ) - annotations.append( - _annotation_dict( - label, - col_count + 1, - num_of_cols, - SUBPLOT_SPACING, - row_col="col", - flipped=flipped_cols, - ) - ) - label = _return_label(row_values[row_count], facet_row_labels, facet_row) - annotations.append( - _annotation_dict( - row_values[row_count], - num_of_rows - row_count, - num_of_rows, - SUBPLOT_SPACING, - row_col="row", - flipped=flipped_rows, - ) - ) - - return fig, annotations - - -def _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, -): - fig = make_subplots( - rows=num_of_rows, - cols=num_of_cols, - shared_xaxes=True, - shared_yaxes=True, - horizontal_spacing=SUBPLOT_SPACING, - vertical_spacing=SUBPLOT_SPACING, - print_grid=False, - ) - annotations = [] - if not facet_row and not facet_col: - trace = dict( - type=trace_type, - marker=dict(color=marker_color, line=kwargs_marker["line"]), - **kwargs_trace, - ) - - if x: - trace["x"] = df[x] - if y: - trace["y"] = df[y] - trace = _make_trace_for_scatter( - trace, trace_type, marker_color, **kwargs_marker - ) - - fig.append_trace(trace, 1, 1) - - elif (facet_row and not facet_col) or (not facet_row and facet_col): - groups_by_facet = list(df.groupby(facet_row if facet_row else facet_col)) - for j, group in enumerate(groups_by_facet): - trace = dict( - type=trace_type, - marker=dict(color=marker_color, line=kwargs_marker["line"]), - **kwargs_trace, - ) - - if x: - trace["x"] = group[1][x] - if y: - trace["y"] = group[1][y] - trace = _make_trace_for_scatter( - trace, trace_type, marker_color, **kwargs_marker - ) - - fig.append_trace( - trace, j + 1 if facet_row else 1, 1 if facet_row else j + 1 - ) - - label = _return_label( - group[0], - facet_row_labels if facet_row else facet_col_labels, - facet_row if facet_row else facet_col, - ) - - annotations.append( - _annotation_dict( - label, - num_of_rows - j if facet_row else j + 1, - num_of_rows if facet_row else num_of_cols, - SUBPLOT_SPACING, - "row" if facet_row else "col", - flipped_rows, - ) - ) - - elif facet_row and facet_col: - groups_by_facets = list(df.groupby([facet_row, facet_col])) - tuple_to_facet_group = {item[0]: item[1] for item in groups_by_facets} - - row_values = df[facet_row].unique() - col_values = df[facet_col].unique() - for row_count, x_val in enumerate(row_values): - for col_count, y_val in enumerate(col_values): - try: - group = tuple_to_facet_group[(x_val, y_val)] - except KeyError: - group = pd.DataFrame([[None, None]], columns=[x, y]) - trace = dict( - type=trace_type, - marker=dict(color=marker_color, line=kwargs_marker["line"]), - **kwargs_trace, - ) - if x: - trace["x"] = group[x] - if y: - trace["y"] = group[y] - trace = _make_trace_for_scatter( - trace, trace_type, marker_color, **kwargs_marker - ) - - fig.append_trace(trace, row_count + 1, col_count + 1) - if row_count == 0: - label = _return_label( - col_values[col_count], facet_col_labels, facet_col - ) - annotations.append( - _annotation_dict( - label, - col_count + 1, - num_of_cols, - SUBPLOT_SPACING, - row_col="col", - flipped=flipped_cols, - ) - ) - - label = _return_label(row_values[row_count], facet_row_labels, facet_row) - annotations.append( - _annotation_dict( - label, - num_of_rows - row_count, - num_of_rows, - SUBPLOT_SPACING, - row_col="row", - flipped=flipped_rows, - ) - ) - - return fig, annotations - - -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 - - # separate 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 diff --git a/plotly/figure_factory/_gantt.py b/plotly/figure_factory/_gantt.py deleted file mode 100644 index 006754a0ff1..00000000000 --- a/plotly/figure_factory/_gantt.py +++ /dev/null @@ -1,1035 +0,0 @@ -from numbers import Number - -import copy - -from plotly import exceptions, optional_imports -import plotly.colors as clrs -from plotly.figure_factory import utils -import plotly.graph_objects as go - -pd = optional_imports.get_module("pandas") - -REQUIRED_GANTT_KEYS = ["Task", "Start", "Finish"] - - -def _get_corner_points(x0, y0, x1, y1): - """ - Returns the corner points of a scatter rectangle - - :param x0: x-start - :param y0: y-lower - :param x1: x-end - :param y1: y-upper - :return: ([x], [y]), tuple of lists containing the x and y values - """ - - return ([x0, x1, x1, x0], [y0, y0, y1, y1]) - - -def validate_gantt(df): - """ - Validates the inputted dataframe or list - """ - if pd and isinstance(df, pd.core.frame.DataFrame): - # validate that df has all the required keys - for key in REQUIRED_GANTT_KEYS: - if key not in df: - raise exceptions.PlotlyError( - "The columns in your dataframe must include the " - "following keys: {0}".format(", ".join(REQUIRED_GANTT_KEYS)) - ) - - columns = {key: df[key].values for key in df} - num_of_rows = len(df.index) - chart = [] - # Using only keys present in the DataFrame columns - keys = list(df.columns) - for index in range(num_of_rows): - task_dict = {key: columns[key][index] for key in keys} - chart.append(task_dict) - - return chart - - # validate if df is a list - if not isinstance(df, list): - raise exceptions.PlotlyError( - "You must input either a dataframe or a list of dictionaries." - ) - - # validate if df is empty - if len(df) <= 0: - raise exceptions.PlotlyError( - "Your list is empty. It must contain at least one dictionary." - ) - if not isinstance(df[0], dict): - raise exceptions.PlotlyError("Your list must only include dictionaries.") - return df - - -def gantt( - chart, - colors, - title, - bar_width, - showgrid_x, - showgrid_y, - height, - width, - tasks=None, - task_names=None, - data=None, - group_tasks=False, - show_hover_fill=True, - show_colorbar=True, -): - """ - Refer to create_gantt() for docstring - """ - if tasks is None: - tasks = [] - if task_names is None: - task_names = [] - if data is None: - data = [] - - for index in range(len(chart)): - task = dict( - x0=chart[index]["Start"], - x1=chart[index]["Finish"], - name=chart[index]["Task"], - ) - if "Description" in chart[index]: - task["description"] = chart[index]["Description"] - tasks.append(task) - - # create a scatter trace for every task group - scatter_data_dict = dict() - marker_data_dict = dict() - - if show_hover_fill: - hoverinfo = "name" - else: - hoverinfo = "skip" - - scatter_data_template = { - "x": [], - "y": [], - "mode": "none", - "fill": "toself", - "hoverinfo": hoverinfo, - } - - marker_data_template = { - "x": [], - "y": [], - "mode": "markers", - "text": [], - "marker": dict(color="", size=1, opacity=0), - "name": "", - "showlegend": False, - } - - # create the list of task names - for index in range(len(tasks)): - tn = tasks[index]["name"] - # Is added to task_names if group_tasks is set to False, - # or if the option is used (True) it only adds them if the - # name is not already in the list - if not group_tasks or tn not in task_names: - task_names.append(tn) - # Guarantees that for grouped tasks the tasks that are inserted first - # are shown at the top - if group_tasks: - task_names.reverse() - - color_index = 0 - for index in range(len(tasks)): - tn = tasks[index]["name"] - del tasks[index]["name"] - - # If group_tasks is True, all tasks with the same name belong - # to the same row. - groupID = index - if group_tasks: - groupID = task_names.index(tn) - tasks[index]["y0"] = groupID - bar_width - tasks[index]["y1"] = groupID + bar_width - - # check if colors need to be looped - if color_index >= len(colors): - color_index = 0 - tasks[index]["fillcolor"] = colors[color_index] - color_id = tasks[index]["fillcolor"] - - if color_id not in scatter_data_dict: - scatter_data_dict[color_id] = copy.deepcopy(scatter_data_template) - - scatter_data_dict[color_id]["fillcolor"] = color_id - scatter_data_dict[color_id]["name"] = str(tn) - scatter_data_dict[color_id]["legendgroup"] = color_id - - # if there are already values append the gap - if len(scatter_data_dict[color_id]["x"]) > 0: - # a gap on the scatterplot separates the rectangles from each other - scatter_data_dict[color_id]["x"].append( - scatter_data_dict[color_id]["x"][-1] - ) - scatter_data_dict[color_id]["y"].append(None) - - xs, ys = _get_corner_points( - tasks[index]["x0"], - tasks[index]["y0"], - tasks[index]["x1"], - tasks[index]["y1"], - ) - - scatter_data_dict[color_id]["x"] += xs - scatter_data_dict[color_id]["y"] += ys - - # append dummy markers for showing start and end of interval - if color_id not in marker_data_dict: - marker_data_dict[color_id] = copy.deepcopy(marker_data_template) - marker_data_dict[color_id]["marker"]["color"] = color_id - marker_data_dict[color_id]["legendgroup"] = color_id - - marker_data_dict[color_id]["x"].append(tasks[index]["x0"]) - marker_data_dict[color_id]["x"].append(tasks[index]["x1"]) - marker_data_dict[color_id]["y"].append(groupID) - marker_data_dict[color_id]["y"].append(groupID) - - if "description" in tasks[index]: - marker_data_dict[color_id]["text"].append(tasks[index]["description"]) - marker_data_dict[color_id]["text"].append(tasks[index]["description"]) - del tasks[index]["description"] - else: - marker_data_dict[color_id]["text"].append(None) - marker_data_dict[color_id]["text"].append(None) - - color_index += 1 - - showlegend = show_colorbar - - layout = dict( - title=title, - showlegend=showlegend, - height=height, - width=width, - shapes=[], - hovermode="closest", - yaxis=dict( - showgrid=showgrid_y, - ticktext=task_names, - tickvals=list(range(len(task_names))), - range=[-1, len(task_names) + 1], - autorange=False, - zeroline=False, - ), - xaxis=dict( - showgrid=showgrid_x, - zeroline=False, - rangeselector=dict( - buttons=list( - [ - dict(count=7, label="1w", step="day", stepmode="backward"), - dict(count=1, label="1m", step="month", stepmode="backward"), - dict(count=6, label="6m", step="month", stepmode="backward"), - dict(count=1, label="YTD", step="year", stepmode="todate"), - dict(count=1, label="1y", step="year", stepmode="backward"), - dict(step="all"), - ] - ) - ), - type="date", - ), - ) - - data = [scatter_data_dict[k] for k in sorted(scatter_data_dict)] - data += [marker_data_dict[k] for k in sorted(marker_data_dict)] - - # fig = dict( - # data=data, layout=layout - # ) - fig = go.Figure(data=data, layout=layout) - return fig - - -def gantt_colorscale( - chart, - colors, - title, - index_col, - show_colorbar, - bar_width, - showgrid_x, - showgrid_y, - height, - width, - tasks=None, - task_names=None, - data=None, - group_tasks=False, - show_hover_fill=True, -): - """ - Refer to FigureFactory.create_gantt() for docstring - """ - if tasks is None: - tasks = [] - if task_names is None: - task_names = [] - if data is None: - data = [] - showlegend = False - - for index in range(len(chart)): - task = dict( - x0=chart[index]["Start"], - x1=chart[index]["Finish"], - name=chart[index]["Task"], - ) - if "Description" in chart[index]: - task["description"] = chart[index]["Description"] - tasks.append(task) - - # create a scatter trace for every task group - scatter_data_dict = dict() - # create scatter traces for the start- and endpoints - marker_data_dict = dict() - - if show_hover_fill: - hoverinfo = "name" - else: - hoverinfo = "skip" - - scatter_data_template = { - "x": [], - "y": [], - "mode": "none", - "fill": "toself", - "showlegend": False, - "hoverinfo": hoverinfo, - "legendgroup": "", - } - - marker_data_template = { - "x": [], - "y": [], - "mode": "markers", - "text": [], - "marker": dict(color="", size=1, opacity=0), - "name": "", - "showlegend": False, - "legendgroup": "", - } - - index_vals = [] - for row in range(len(tasks)): - if chart[row][index_col] not in index_vals: - index_vals.append(chart[row][index_col]) - - index_vals.sort() - - # compute the color for task based on indexing column - if isinstance(chart[0][index_col], Number): - # check that colors has at least 2 colors - if len(colors) < 2: - raise exceptions.PlotlyError( - "You must use at least 2 colors in 'colors' if you " - "are using a colorscale. However only the first two " - "colors given will be used for the lower and upper " - "bounds on the colormap." - ) - - # create the list of task names - for index in range(len(tasks)): - tn = tasks[index]["name"] - # Is added to task_names if group_tasks is set to False, - # or if the option is used (True) it only adds them if the - # name is not already in the list - if not group_tasks or tn not in task_names: - task_names.append(tn) - # Guarantees that for grouped tasks the tasks that are inserted - # first are shown at the top - if group_tasks: - task_names.reverse() - - for index in range(len(tasks)): - tn = tasks[index]["name"] - del tasks[index]["name"] - - # If group_tasks is True, all tasks with the same name belong - # to the same row. - groupID = index - if group_tasks: - groupID = task_names.index(tn) - tasks[index]["y0"] = groupID - bar_width - tasks[index]["y1"] = groupID + bar_width - - # unlabel color - colors = clrs.color_parser(colors, clrs.unlabel_rgb) - lowcolor = colors[0] - highcolor = colors[1] - - intermed = (chart[index][index_col]) / 100.0 - intermed_color = clrs.find_intermediate_color(lowcolor, highcolor, intermed) - intermed_color = clrs.color_parser(intermed_color, clrs.label_rgb) - tasks[index]["fillcolor"] = intermed_color - color_id = tasks[index]["fillcolor"] - - if color_id not in scatter_data_dict: - scatter_data_dict[color_id] = copy.deepcopy(scatter_data_template) - - scatter_data_dict[color_id]["fillcolor"] = color_id - scatter_data_dict[color_id]["name"] = str(chart[index][index_col]) - scatter_data_dict[color_id]["legendgroup"] = color_id - - # relabel colors with 'rgb' - colors = clrs.color_parser(colors, clrs.label_rgb) - - # if there are already values append the gap - if len(scatter_data_dict[color_id]["x"]) > 0: - # a gap on the scatterplot separates the rectangles from each other - scatter_data_dict[color_id]["x"].append( - scatter_data_dict[color_id]["x"][-1] - ) - scatter_data_dict[color_id]["y"].append(None) - - xs, ys = _get_corner_points( - tasks[index]["x0"], - tasks[index]["y0"], - tasks[index]["x1"], - tasks[index]["y1"], - ) - - scatter_data_dict[color_id]["x"] += xs - scatter_data_dict[color_id]["y"] += ys - - # append dummy markers for showing start and end of interval - if color_id not in marker_data_dict: - marker_data_dict[color_id] = copy.deepcopy(marker_data_template) - marker_data_dict[color_id]["marker"]["color"] = color_id - marker_data_dict[color_id]["legendgroup"] = color_id - - marker_data_dict[color_id]["x"].append(tasks[index]["x0"]) - marker_data_dict[color_id]["x"].append(tasks[index]["x1"]) - marker_data_dict[color_id]["y"].append(groupID) - marker_data_dict[color_id]["y"].append(groupID) - - if "description" in tasks[index]: - marker_data_dict[color_id]["text"].append(tasks[index]["description"]) - marker_data_dict[color_id]["text"].append(tasks[index]["description"]) - del tasks[index]["description"] - else: - marker_data_dict[color_id]["text"].append(None) - marker_data_dict[color_id]["text"].append(None) - - # add colorbar to one of the traces randomly just for display - if show_colorbar is True: - k = list(marker_data_dict.keys())[0] - marker_data_dict[k]["marker"].update( - dict( - colorscale=[[0, colors[0]], [1, colors[1]]], - showscale=True, - cmax=100, - cmin=0, - ) - ) - - if isinstance(chart[0][index_col], str): - index_vals = [] - for row in range(len(tasks)): - if chart[row][index_col] not in index_vals: - index_vals.append(chart[row][index_col]) - - index_vals.sort() - - if len(colors) < len(index_vals): - raise exceptions.PlotlyError( - "Error. The number of colors in 'colors' must be no less " - "than the number of unique index values in your group " - "column." - ) - - # make a dictionary assignment to each index value - index_vals_dict = {} - # define color index - c_index = 0 - for key in index_vals: - if c_index > len(colors) - 1: - c_index = 0 - index_vals_dict[key] = colors[c_index] - c_index += 1 - - # create the list of task names - for index in range(len(tasks)): - tn = tasks[index]["name"] - # Is added to task_names if group_tasks is set to False, - # or if the option is used (True) it only adds them if the - # name is not already in the list - if not group_tasks or tn not in task_names: - task_names.append(tn) - # Guarantees that for grouped tasks the tasks that are inserted - # first are shown at the top - if group_tasks: - task_names.reverse() - - for index in range(len(tasks)): - tn = tasks[index]["name"] - del tasks[index]["name"] - - # If group_tasks is True, all tasks with the same name belong - # to the same row. - groupID = index - if group_tasks: - groupID = task_names.index(tn) - tasks[index]["y0"] = groupID - bar_width - tasks[index]["y1"] = groupID + bar_width - - tasks[index]["fillcolor"] = index_vals_dict[chart[index][index_col]] - color_id = tasks[index]["fillcolor"] - - if color_id not in scatter_data_dict: - scatter_data_dict[color_id] = copy.deepcopy(scatter_data_template) - - scatter_data_dict[color_id]["fillcolor"] = color_id - scatter_data_dict[color_id]["legendgroup"] = color_id - scatter_data_dict[color_id]["name"] = str(chart[index][index_col]) - - # relabel colors with 'rgb' - colors = clrs.color_parser(colors, clrs.label_rgb) - - # if there are already values append the gap - if len(scatter_data_dict[color_id]["x"]) > 0: - # a gap on the scatterplot separates the rectangles from each other - scatter_data_dict[color_id]["x"].append( - scatter_data_dict[color_id]["x"][-1] - ) - scatter_data_dict[color_id]["y"].append(None) - - xs, ys = _get_corner_points( - tasks[index]["x0"], - tasks[index]["y0"], - tasks[index]["x1"], - tasks[index]["y1"], - ) - - scatter_data_dict[color_id]["x"] += xs - scatter_data_dict[color_id]["y"] += ys - - # append dummy markers for showing start and end of interval - if color_id not in marker_data_dict: - marker_data_dict[color_id] = copy.deepcopy(marker_data_template) - marker_data_dict[color_id]["marker"]["color"] = color_id - marker_data_dict[color_id]["legendgroup"] = color_id - - marker_data_dict[color_id]["x"].append(tasks[index]["x0"]) - marker_data_dict[color_id]["x"].append(tasks[index]["x1"]) - marker_data_dict[color_id]["y"].append(groupID) - marker_data_dict[color_id]["y"].append(groupID) - - if "description" in tasks[index]: - marker_data_dict[color_id]["text"].append(tasks[index]["description"]) - marker_data_dict[color_id]["text"].append(tasks[index]["description"]) - del tasks[index]["description"] - else: - marker_data_dict[color_id]["text"].append(None) - marker_data_dict[color_id]["text"].append(None) - - if show_colorbar is True: - showlegend = True - for k in scatter_data_dict: - scatter_data_dict[k]["showlegend"] = showlegend - # add colorbar to one of the traces randomly just for display - # if show_colorbar is True: - # k = list(marker_data_dict.keys())[0] - # marker_data_dict[k]["marker"].update( - # dict( - # colorscale=[[0, colors[0]], [1, colors[1]]], - # showscale=True, - # cmax=100, - # cmin=0, - # ) - # ) - - layout = dict( - title=title, - showlegend=showlegend, - height=height, - width=width, - shapes=[], - hovermode="closest", - yaxis=dict( - showgrid=showgrid_y, - ticktext=task_names, - tickvals=list(range(len(task_names))), - range=[-1, len(task_names) + 1], - autorange=False, - zeroline=False, - ), - xaxis=dict( - showgrid=showgrid_x, - zeroline=False, - rangeselector=dict( - buttons=list( - [ - dict(count=7, label="1w", step="day", stepmode="backward"), - dict(count=1, label="1m", step="month", stepmode="backward"), - dict(count=6, label="6m", step="month", stepmode="backward"), - dict(count=1, label="YTD", step="year", stepmode="todate"), - dict(count=1, label="1y", step="year", stepmode="backward"), - dict(step="all"), - ] - ) - ), - type="date", - ), - ) - - data = [scatter_data_dict[k] for k in sorted(scatter_data_dict)] - data += [marker_data_dict[k] for k in sorted(marker_data_dict)] - - # fig = dict( - # data=data, layout=layout - # ) - fig = go.Figure(data=data, layout=layout) - return fig - - -def gantt_dict( - chart, - colors, - title, - index_col, - show_colorbar, - bar_width, - showgrid_x, - showgrid_y, - height, - width, - tasks=None, - task_names=None, - data=None, - group_tasks=False, - show_hover_fill=True, -): - """ - Refer to FigureFactory.create_gantt() for docstring - """ - - if tasks is None: - tasks = [] - if task_names is None: - task_names = [] - if data is None: - data = [] - showlegend = False - - for index in range(len(chart)): - task = dict( - x0=chart[index]["Start"], - x1=chart[index]["Finish"], - name=chart[index]["Task"], - ) - if "Description" in chart[index]: - task["description"] = chart[index]["Description"] - tasks.append(task) - - # create a scatter trace for every task group - scatter_data_dict = dict() - # create scatter traces for the start- and endpoints - marker_data_dict = dict() - - if show_hover_fill: - hoverinfo = "name" - else: - hoverinfo = "skip" - - scatter_data_template = { - "x": [], - "y": [], - "mode": "none", - "fill": "toself", - "hoverinfo": hoverinfo, - "legendgroup": "", - } - - marker_data_template = { - "x": [], - "y": [], - "mode": "markers", - "text": [], - "marker": dict(color="", size=1, opacity=0), - "name": "", - "showlegend": False, - } - - index_vals = [] - for row in range(len(tasks)): - if chart[row][index_col] not in index_vals: - index_vals.append(chart[row][index_col]) - - index_vals.sort() - - # verify each value in index column appears in colors dictionary - for key in index_vals: - if key not in colors: - raise exceptions.PlotlyError( - "If you are using colors as a dictionary, all of its " - "keys must be all the values in the index column." - ) - - # create the list of task names - for index in range(len(tasks)): - tn = tasks[index]["name"] - # Is added to task_names if group_tasks is set to False, - # or if the option is used (True) it only adds them if the - # name is not already in the list - if not group_tasks or tn not in task_names: - task_names.append(tn) - # Guarantees that for grouped tasks the tasks that are inserted first - # are shown at the top - if group_tasks: - task_names.reverse() - - for index in range(len(tasks)): - tn = tasks[index]["name"] - del tasks[index]["name"] - - # If group_tasks is True, all tasks with the same name belong - # to the same row. - groupID = index - if group_tasks: - groupID = task_names.index(tn) - tasks[index]["y0"] = groupID - bar_width - tasks[index]["y1"] = groupID + bar_width - - tasks[index]["fillcolor"] = colors[chart[index][index_col]] - color_id = tasks[index]["fillcolor"] - - if color_id not in scatter_data_dict: - scatter_data_dict[color_id] = copy.deepcopy(scatter_data_template) - - scatter_data_dict[color_id]["legendgroup"] = color_id - scatter_data_dict[color_id]["fillcolor"] = color_id - - # if there are already values append the gap - if len(scatter_data_dict[color_id]["x"]) > 0: - # a gap on the scatterplot separates the rectangles from each other - scatter_data_dict[color_id]["x"].append( - scatter_data_dict[color_id]["x"][-1] - ) - scatter_data_dict[color_id]["y"].append(None) - - xs, ys = _get_corner_points( - tasks[index]["x0"], - tasks[index]["y0"], - tasks[index]["x1"], - tasks[index]["y1"], - ) - - scatter_data_dict[color_id]["x"] += xs - scatter_data_dict[color_id]["y"] += ys - - # append dummy markers for showing start and end of interval - if color_id not in marker_data_dict: - marker_data_dict[color_id] = copy.deepcopy(marker_data_template) - marker_data_dict[color_id]["marker"]["color"] = color_id - marker_data_dict[color_id]["legendgroup"] = color_id - - marker_data_dict[color_id]["x"].append(tasks[index]["x0"]) - marker_data_dict[color_id]["x"].append(tasks[index]["x1"]) - marker_data_dict[color_id]["y"].append(groupID) - marker_data_dict[color_id]["y"].append(groupID) - - if "description" in tasks[index]: - marker_data_dict[color_id]["text"].append(tasks[index]["description"]) - marker_data_dict[color_id]["text"].append(tasks[index]["description"]) - del tasks[index]["description"] - else: - marker_data_dict[color_id]["text"].append(None) - marker_data_dict[color_id]["text"].append(None) - - if show_colorbar is True: - showlegend = True - - for index_value in index_vals: - scatter_data_dict[colors[index_value]]["name"] = str(index_value) - - layout = dict( - title=title, - showlegend=showlegend, - height=height, - width=width, - shapes=[], - hovermode="closest", - yaxis=dict( - showgrid=showgrid_y, - ticktext=task_names, - tickvals=list(range(len(task_names))), - range=[-1, len(task_names) + 1], - autorange=False, - zeroline=False, - ), - xaxis=dict( - showgrid=showgrid_x, - zeroline=False, - rangeselector=dict( - buttons=list( - [ - dict(count=7, label="1w", step="day", stepmode="backward"), - dict(count=1, label="1m", step="month", stepmode="backward"), - dict(count=6, label="6m", step="month", stepmode="backward"), - dict(count=1, label="YTD", step="year", stepmode="todate"), - dict(count=1, label="1y", step="year", stepmode="backward"), - dict(step="all"), - ] - ) - ), - type="date", - ), - ) - - data = [scatter_data_dict[k] for k in sorted(scatter_data_dict)] - data += [marker_data_dict[k] for k in sorted(marker_data_dict)] - - # fig = dict( - # data=data, layout=layout - # ) - fig = go.Figure(data=data, layout=layout) - return fig - - -def create_gantt( - df, - colors=None, - index_col=None, - show_colorbar=False, - reverse_colors=False, - title="Gantt Chart", - bar_width=0.2, - showgrid_x=False, - showgrid_y=False, - height=600, - width=None, - tasks=None, - task_names=None, - data=None, - group_tasks=False, - show_hover_fill=True, -): - """ - **deprecated**, use instead - :func:`plotly.express.timeline`. - - Returns figure for a gantt chart - - :param (array|list) df: input data for gantt chart. Must be either a - a dataframe or a list. If dataframe, the columns must include - 'Task', 'Start' and 'Finish'. Other columns can be included and - used for indexing. If a list, its elements must be dictionaries - with the same required column headers: 'Task', 'Start' and - 'Finish'. - :param (str|list|dict|tuple) colors: either a plotly scale name, an - rgb or hex color, a color tuple or a list of colors. An rgb color - is of the form 'rgb(x, y, z)' where x, y, z belong to the interval - [0, 255] and a color tuple is a tuple of the form (a, b, c) where - a, b and c belong to [0, 1]. If colors is a list, it must - contain the valid color types aforementioned as its members. - If a dictionary, all values of the indexing column must be keys in - colors. - :param (str|float) index_col: the column header (if df is a data - frame) that will function as the indexing column. If df is a list, - index_col must be one of the keys in all the items of df. - :param (bool) show_colorbar: determines if colorbar will be visible. - Only applies if values in the index column are numeric. - :param (bool) show_hover_fill: enables/disables the hovertext for the - filled area of the chart. - :param (bool) reverse_colors: reverses the order of selected colors - :param (str) title: the title of the chart - :param (float) bar_width: the width of the horizontal bars in the plot - :param (bool) showgrid_x: show/hide the x-axis grid - :param (bool) showgrid_y: show/hide the y-axis grid - :param (float) height: the height of the chart - :param (float) width: the width of the chart - - Example 1: Simple Gantt Chart - - >>> from plotly.figure_factory import create_gantt - - >>> # Make data for chart - >>> df = [dict(Task="Job A", Start='2009-01-01', Finish='2009-02-30'), - ... dict(Task="Job B", Start='2009-03-05', Finish='2009-04-15'), - ... dict(Task="Job C", Start='2009-02-20', Finish='2009-05-30')] - - >>> # Create a figure - >>> fig = create_gantt(df) - >>> fig.show() - - - Example 2: Index by Column with Numerical Entries - - >>> from plotly.figure_factory import create_gantt - - >>> # Make data for chart - >>> df = [dict(Task="Job A", Start='2009-01-01', - ... Finish='2009-02-30', Complete=10), - ... dict(Task="Job B", Start='2009-03-05', - ... Finish='2009-04-15', Complete=60), - ... dict(Task="Job C", Start='2009-02-20', - ... Finish='2009-05-30', Complete=95)] - - >>> # Create a figure with Plotly colorscale - >>> fig = create_gantt(df, colors='Blues', index_col='Complete', - ... show_colorbar=True, bar_width=0.5, - ... showgrid_x=True, showgrid_y=True) - >>> fig.show() - - - Example 3: Index by Column with String Entries - - >>> from plotly.figure_factory import create_gantt - - >>> # Make data for chart - >>> df = [dict(Task="Job A", Start='2009-01-01', - ... Finish='2009-02-30', Resource='Apple'), - ... dict(Task="Job B", Start='2009-03-05', - ... Finish='2009-04-15', Resource='Grape'), - ... dict(Task="Job C", Start='2009-02-20', - ... Finish='2009-05-30', Resource='Banana')] - - >>> # Create a figure with Plotly colorscale - >>> fig = create_gantt(df, colors=['rgb(200, 50, 25)', (1, 0, 1), '#6c4774'], - ... index_col='Resource', reverse_colors=True, - ... show_colorbar=True) - >>> fig.show() - - - Example 4: Use a dictionary for colors - - >>> from plotly.figure_factory import create_gantt - >>> # Make data for chart - >>> df = [dict(Task="Job A", Start='2009-01-01', - ... Finish='2009-02-30', Resource='Apple'), - ... dict(Task="Job B", Start='2009-03-05', - ... Finish='2009-04-15', Resource='Grape'), - ... dict(Task="Job C", Start='2009-02-20', - ... Finish='2009-05-30', Resource='Banana')] - - >>> # Make a dictionary of colors - >>> colors = {'Apple': 'rgb(255, 0, 0)', - ... 'Grape': 'rgb(170, 14, 200)', - ... 'Banana': (1, 1, 0.2)} - - >>> # Create a figure with Plotly colorscale - >>> fig = create_gantt(df, colors=colors, index_col='Resource', - ... show_colorbar=True) - - >>> fig.show() - - Example 5: Use a pandas dataframe - - >>> from plotly.figure_factory import create_gantt - >>> import pandas as pd - - >>> # Make data as a dataframe - >>> df = pd.DataFrame([['Run', '2010-01-01', '2011-02-02', 10], - ... ['Fast', '2011-01-01', '2012-06-05', 55], - ... ['Eat', '2012-01-05', '2013-07-05', 94]], - ... columns=['Task', 'Start', 'Finish', 'Complete']) - - >>> # Create a figure with Plotly colorscale - >>> fig = create_gantt(df, colors='Blues', index_col='Complete', - ... show_colorbar=True, bar_width=0.5, - ... showgrid_x=True, showgrid_y=True) - >>> fig.show() - """ - # validate gantt input data - chart = validate_gantt(df) - - if index_col: - if index_col not in chart[0]: - raise exceptions.PlotlyError( - "In order to use an indexing column and assign colors to " - "the values of the index, you must choose an actual " - "column name in the dataframe or key if a list of " - "dictionaries is being used." - ) - - # validate gantt index column - index_list = [] - for dictionary in chart: - index_list.append(dictionary[index_col]) - utils.validate_index(index_list) - - # Validate colors - if isinstance(colors, dict): - colors = clrs.validate_colors_dict(colors, "rgb") - else: - colors = clrs.validate_colors(colors, "rgb") - - if reverse_colors is True: - colors.reverse() - - if not index_col: - if isinstance(colors, dict): - raise exceptions.PlotlyError( - "Error. You have set colors to a dictionary but have not " - "picked an index. An index is required if you are " - "assigning colors to particular values in a dictionary." - ) - fig = gantt( - chart, - colors, - title, - bar_width, - showgrid_x, - showgrid_y, - height, - width, - tasks=None, - task_names=None, - data=None, - group_tasks=group_tasks, - show_hover_fill=show_hover_fill, - show_colorbar=show_colorbar, - ) - return fig - else: - if not isinstance(colors, dict): - fig = gantt_colorscale( - chart, - colors, - title, - index_col, - show_colorbar, - bar_width, - showgrid_x, - showgrid_y, - height, - width, - tasks=None, - task_names=None, - data=None, - group_tasks=group_tasks, - show_hover_fill=show_hover_fill, - ) - return fig - else: - fig = gantt_dict( - chart, - colors, - title, - index_col, - show_colorbar, - bar_width, - showgrid_x, - showgrid_y, - height, - width, - tasks=None, - task_names=None, - data=None, - group_tasks=group_tasks, - show_hover_fill=show_hover_fill, - ) - return fig diff --git a/plotly/figure_factory/_hexbin_map.py b/plotly/figure_factory/_hexbin_map.py index 792cae5e238..580bd3d59d2 100644 --- a/plotly/figure_factory/_hexbin_map.py +++ b/plotly/figure_factory/_hexbin_map.py @@ -3,7 +3,6 @@ from plotly.express._chart_types import choropleth_map, scatter_map import narwhals.stable.v1 as nw import numpy as np -import warnings def _project_latlon_to_wgs84(lat, lon): @@ -530,17 +529,3 @@ def create_hexbin_map( original_data_marker=["dict", "Scattermap marker options."], ), ) - - -def create_hexbin_mapbox(*args, **kwargs): - warnings.warn( - "create_hexbin_mapbox() is deprecated and will be removed in the next major version. " - + "Please use create_hexbin_map() instead. " - + "Learn more at: https://plotly.com/python/mapbox-to-maplibre/", - stacklevel=2, - category=DeprecationWarning, - ) - if "mapbox_style" in kwargs: - kwargs["map_style"] = kwargs.pop("mapbox_style") - - return create_hexbin_map(*args, **kwargs) diff --git a/plotly/figure_factory/_ohlc.py b/plotly/figure_factory/_ohlc.py deleted file mode 100644 index a0b1b4838be..00000000000 --- a/plotly/figure_factory/_ohlc.py +++ /dev/null @@ -1,295 +0,0 @@ -from plotly import exceptions -from plotly.graph_objs import graph_objs -from plotly.figure_factory import utils - - -# Default colours for finance charts -_DEFAULT_INCREASING_COLOR = "#3D9970" # http://clrs.cc -_DEFAULT_DECREASING_COLOR = "#FF4136" - - -def validate_ohlc(open, high, low, close, direction, **kwargs): - """ - ohlc and candlestick specific validations - - Specifically, this checks that the high value is the greatest value and - the low value is the lowest value in each unit. - - See FigureFactory.create_ohlc() or FigureFactory.create_candlestick() - for params - - :raises: (PlotlyError) If the high value is not the greatest value in - each unit. - :raises: (PlotlyError) If the low value is not the lowest value in each - unit. - :raises: (PlotlyError) If direction is not 'increasing' or 'decreasing' - """ - for lst in [open, low, close]: - for index in range(len(high)): - if high[index] < lst[index]: - raise exceptions.PlotlyError( - "Oops! Looks like some of " - "your high values are less " - "the corresponding open, " - "low, or close values. " - "Double check that your data " - "is entered in O-H-L-C order" - ) - - for lst in [open, high, close]: - for index in range(len(low)): - if low[index] > lst[index]: - raise exceptions.PlotlyError( - "Oops! Looks like some of " - "your low values are greater " - "than the corresponding high" - ", open, or close values. " - "Double check that your data " - "is entered in O-H-L-C order" - ) - - direction_opts = ("increasing", "decreasing", "both") - if direction not in direction_opts: - raise exceptions.PlotlyError( - "direction must be defined as 'increasing', 'decreasing', or 'both'" - ) - - -def make_increasing_ohlc(open, high, low, close, dates, **kwargs): - """ - Makes increasing ohlc sticks - - _make_increasing_ohlc() and _make_decreasing_ohlc separate the - increasing trace from the decreasing trace so kwargs (such as - color) can be passed separately to increasing or decreasing traces - when direction is set to 'increasing' or 'decreasing' in - FigureFactory.create_candlestick() - - :param (list) open: opening values - :param (list) high: high values - :param (list) low: low values - :param (list) close: closing values - :param (list) dates: list of datetime objects. Default: None - :param kwargs: kwargs to be passed to increasing trace via - plotly.graph_objs.Scatter. - - :rtype (trace) ohlc_incr_data: Scatter trace of all increasing ohlc - sticks. - """ - (flat_increase_x, flat_increase_y, text_increase) = _OHLC( - open, high, low, close, dates - ).get_increase() - - if "name" in kwargs: - showlegend = True - else: - kwargs.setdefault("name", "Increasing") - showlegend = False - - kwargs.setdefault("line", dict(color=_DEFAULT_INCREASING_COLOR, width=1)) - kwargs.setdefault("text", text_increase) - - ohlc_incr = dict( - type="scatter", - x=flat_increase_x, - y=flat_increase_y, - mode="lines", - showlegend=showlegend, - **kwargs, - ) - return ohlc_incr - - -def make_decreasing_ohlc(open, high, low, close, dates, **kwargs): - """ - Makes decreasing ohlc sticks - - :param (list) open: opening values - :param (list) high: high values - :param (list) low: low values - :param (list) close: closing values - :param (list) dates: list of datetime objects. Default: None - :param kwargs: kwargs to be passed to increasing trace via - plotly.graph_objs.Scatter. - - :rtype (trace) ohlc_decr_data: Scatter trace of all decreasing ohlc - sticks. - """ - (flat_decrease_x, flat_decrease_y, text_decrease) = _OHLC( - open, high, low, close, dates - ).get_decrease() - - kwargs.setdefault("line", dict(color=_DEFAULT_DECREASING_COLOR, width=1)) - kwargs.setdefault("text", text_decrease) - kwargs.setdefault("showlegend", False) - kwargs.setdefault("name", "Decreasing") - - ohlc_decr = dict( - type="scatter", x=flat_decrease_x, y=flat_decrease_y, mode="lines", **kwargs - ) - return ohlc_decr - - -def create_ohlc(open, high, low, close, dates=None, direction="both", **kwargs): - """ - **deprecated**, use instead the plotly.graph_objects trace - :class:`plotly.graph_objects.Ohlc` - - :param (list) open: opening values - :param (list) high: high values - :param (list) low: low values - :param (list) close: closing - :param (list) dates: list of datetime objects. Default: None - :param (string) direction: direction can be 'increasing', 'decreasing', - or 'both'. When the direction is 'increasing', the returned figure - consists of all units where the close value is greater than the - corresponding open value, and when the direction is 'decreasing', - the returned figure consists of all units where the close value is - less than or equal to the corresponding open value. When the - direction is 'both', both increasing and decreasing units are - returned. Default: 'both' - :param kwargs: kwargs passed through plotly.graph_objs.Scatter. - These kwargs describe other attributes about the ohlc Scatter trace - such as the color or the legend name. For more information on valid - kwargs call help(plotly.graph_objs.Scatter) - - :rtype (dict): returns a representation of an ohlc chart figure. - - Example 1: Simple OHLC chart from a Pandas DataFrame - - >>> from plotly.figure_factory import create_ohlc - >>> from datetime import datetime - - >>> import pandas as pd - >>> df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv') - >>> fig = create_ohlc(df['AAPL.Open'], df['AAPL.High'], df['AAPL.Low'], df['AAPL.Close'], dates=df.index) - >>> fig.show() - """ - if dates is not None: - utils.validate_equal_length(open, high, low, close, dates) - else: - utils.validate_equal_length(open, high, low, close) - validate_ohlc(open, high, low, close, direction, **kwargs) - - if direction == "increasing": - ohlc_incr = make_increasing_ohlc(open, high, low, close, dates, **kwargs) - data = [ohlc_incr] - elif direction == "decreasing": - ohlc_decr = make_decreasing_ohlc(open, high, low, close, dates, **kwargs) - data = [ohlc_decr] - else: - ohlc_incr = make_increasing_ohlc(open, high, low, close, dates, **kwargs) - ohlc_decr = make_decreasing_ohlc(open, high, low, close, dates, **kwargs) - data = [ohlc_incr, ohlc_decr] - - layout = graph_objs.Layout(xaxis=dict(zeroline=False), hovermode="closest") - - return graph_objs.Figure(data=data, layout=layout) - - -class _OHLC(object): - """ - Refer to FigureFactory.create_ohlc_increase() for docstring. - """ - - def __init__(self, open, high, low, close, dates, **kwargs): - self.open = open - self.high = high - self.low = low - self.close = close - self.empty = [None] * len(open) - self.dates = dates - - self.all_x = [] - self.all_y = [] - self.increase_x = [] - self.increase_y = [] - self.decrease_x = [] - self.decrease_y = [] - self.get_all_xy() - self.separate_increase_decrease() - - def get_all_xy(self): - """ - Zip data to create OHLC shape - - OHLC shape: low to high vertical bar with - horizontal branches for open and close values. - If dates were added, the smallest date difference is calculated and - multiplied by .2 to get the length of the open and close branches. - If no date data was provided, the x-axis is a list of integers and the - length of the open and close branches is .2. - """ - self.all_y = list( - zip( - self.open, - self.open, - self.high, - self.low, - self.close, - self.close, - self.empty, - ) - ) - if self.dates is not None: - date_dif = [] - for i in range(len(self.dates) - 1): - date_dif.append(self.dates[i + 1] - self.dates[i]) - date_dif_min = (min(date_dif)) / 5 - self.all_x = [ - [x - date_dif_min, x, x, x, x, x + date_dif_min, None] - for x in self.dates - ] - else: - self.all_x = [ - [x - 0.2, x, x, x, x, x + 0.2, None] for x in range(len(self.open)) - ] - - def separate_increase_decrease(self): - """ - Separate data into two groups: increase and decrease - - (1) Increase, where close > open and - (2) Decrease, where close <= open - """ - for index in range(len(self.open)): - if self.close[index] is None: - pass - elif self.close[index] > self.open[index]: - self.increase_x.append(self.all_x[index]) - self.increase_y.append(self.all_y[index]) - else: - self.decrease_x.append(self.all_x[index]) - self.decrease_y.append(self.all_y[index]) - - def get_increase(self): - """ - Flatten increase data and get increase text - - :rtype (list, list, list): flat_increase_x: x-values for the increasing - trace, flat_increase_y: y=values for the increasing trace and - text_increase: hovertext for the increasing trace - """ - flat_increase_x = utils.flatten(self.increase_x) - flat_increase_y = utils.flatten(self.increase_y) - text_increase = ("Open", "Open", "High", "Low", "Close", "Close", "") * ( - len(self.increase_x) - ) - - return flat_increase_x, flat_increase_y, text_increase - - def get_decrease(self): - """ - Flatten decrease data and get decrease text - - :rtype (list, list, list): flat_decrease_x: x-values for the decreasing - trace, flat_decrease_y: y=values for the decreasing trace and - text_decrease: hovertext for the decreasing trace - """ - flat_decrease_x = utils.flatten(self.decrease_x) - flat_decrease_y = utils.flatten(self.decrease_y) - text_decrease = ("Open", "Open", "High", "Low", "Close", "Close", "") * ( - len(self.decrease_x) - ) - - return flat_decrease_x, flat_decrease_y, text_decrease diff --git a/plotly/figure_factory/_scatterplot.py b/plotly/figure_factory/_scatterplot.py deleted file mode 100644 index 75895272615..00000000000 --- a/plotly/figure_factory/_scatterplot.py +++ /dev/null @@ -1,1135 +0,0 @@ -from plotly import exceptions, optional_imports -import plotly.colors as clrs -from plotly.figure_factory import utils -from plotly.graph_objs import graph_objs -from plotly.subplots import make_subplots - -pd = optional_imports.get_module("pandas") - -DIAG_CHOICES = ["scatter", "histogram", "box"] -VALID_COLORMAP_TYPES = ["cat", "seq"] - - -def endpts_to_intervals(endpts): - """ - Returns a list of intervals for categorical colormaps - - Accepts a list or tuple of sequentially increasing numbers and returns - a list representation of the mathematical intervals with these numbers - as endpoints. For example, [1, 6] returns [[-inf, 1], [1, 6], [6, inf]] - - :raises: (PlotlyError) If input is not a list or tuple - :raises: (PlotlyError) If the input contains a string - :raises: (PlotlyError) If any number does not increase after the - previous one in the sequence - """ - length = len(endpts) - # Check if endpts is a list or tuple - if not (isinstance(endpts, (tuple)) or isinstance(endpts, (list))): - raise exceptions.PlotlyError( - "The intervals_endpts argument must " - "be a list or tuple of a sequence " - "of increasing numbers." - ) - # Check if endpts contains only numbers - for item in endpts: - if isinstance(item, str): - raise exceptions.PlotlyError( - "The intervals_endpts argument " - "must be a list or tuple of a " - "sequence of increasing " - "numbers." - ) - # Check if numbers in endpts are increasing - for k in range(length - 1): - if endpts[k] >= endpts[k + 1]: - raise exceptions.PlotlyError( - "The intervals_endpts argument " - "must be a list or tuple of a " - "sequence of increasing " - "numbers." - ) - else: - intervals = [] - # add -inf to intervals - intervals.append([float("-inf"), endpts[0]]) - for k in range(length - 1): - interval = [] - interval.append(endpts[k]) - interval.append(endpts[k + 1]) - intervals.append(interval) - # add +inf to intervals - intervals.append([endpts[length - 1], float("inf")]) - return intervals - - -def hide_tick_labels_from_box_subplots(fig): - """ - Hides tick labels for box plots in scatterplotmatrix subplots. - """ - boxplot_xaxes = [] - for trace in fig["data"]: - if trace["type"] == "box": - # stores the xaxes which correspond to boxplot subplots - # since we use xaxis1, xaxis2, etc, in plotly.py - boxplot_xaxes.append("xaxis{}".format(trace["xaxis"][1:])) - for xaxis in boxplot_xaxes: - fig["layout"][xaxis]["showticklabels"] = False - - -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 scatterplot(dataframe, headers, diag, size, height, width, title, **kwargs): - """ - Refer to FigureFactory.create_scatterplotmatrix() for docstring - - Returns fig for scatterplotmatrix without index - - """ - dim = len(dataframe) - fig = make_subplots(rows=dim, cols=dim, print_grid=False) - trace_list = [] - # Insert traces into trace_list - for listy in dataframe: - for listx in dataframe: - if (listx == listy) and (diag == "histogram"): - trace = graph_objs.Histogram(x=listx, showlegend=False) - elif (listx == listy) and (diag == "box"): - trace = graph_objs.Box(y=listx, name=None, showlegend=False) - else: - if "marker" in kwargs: - kwargs["marker"]["size"] = size - trace = graph_objs.Scatter( - x=listx, y=listy, mode="markers", showlegend=False, **kwargs - ) - trace_list.append(trace) - else: - trace = graph_objs.Scatter( - x=listx, - y=listy, - mode="markers", - marker=dict(size=size), - showlegend=False, - **kwargs, - ) - trace_list.append(trace) - - trace_index = 0 - indices = range(1, dim + 1) - for y_index in indices: - for x_index in indices: - fig.append_trace(trace_list[trace_index], y_index, x_index) - trace_index += 1 - - # Insert headers into the figure - for j in range(dim): - xaxis_key = "xaxis{}".format((dim * dim) - dim + 1 + j) - fig["layout"][xaxis_key].update(title=headers[j]) - for j in range(dim): - yaxis_key = "yaxis{}".format(1 + (dim * j)) - fig["layout"][yaxis_key].update(title=headers[j]) - - fig["layout"].update(height=height, width=width, title=title, showlegend=True) - - hide_tick_labels_from_box_subplots(fig) - - return fig - - -def scatterplot_dict( - dataframe, - headers, - diag, - size, - height, - width, - title, - index, - index_vals, - endpts, - colormap, - colormap_type, - **kwargs, -): - """ - Refer to FigureFactory.create_scatterplotmatrix() for docstring - - Returns fig for scatterplotmatrix with both index and colormap picked. - Used if colormap is a dictionary with index values as keys pointing to - colors. Forces colormap_type to behave categorically because it would - not make sense colors are assigned to each index value and thus - implies that a categorical approach should be taken - - """ - - theme = colormap - dim = len(dataframe) - fig = make_subplots(rows=dim, cols=dim, print_grid=False) - trace_list = [] - legend_param = 0 - # Work over all permutations of list pairs - for listy in dataframe: - for listx in dataframe: - # create a dictionary for index_vals - unique_index_vals = {} - for name in index_vals: - if name not in unique_index_vals: - unique_index_vals[name] = [] - - # Fill all the rest of the names into the dictionary - for name in sorted(unique_index_vals.keys()): - new_listx = [] - new_listy = [] - for j in range(len(index_vals)): - if index_vals[j] == name: - new_listx.append(listx[j]) - new_listy.append(listy[j]) - # Generate trace with VISIBLE icon - if legend_param == 1: - if (listx == listy) and (diag == "histogram"): - trace = graph_objs.Histogram( - x=new_listx, marker=dict(color=theme[name]), showlegend=True - ) - elif (listx == listy) and (diag == "box"): - trace = graph_objs.Box( - y=new_listx, - name=None, - marker=dict(color=theme[name]), - showlegend=True, - ) - else: - if "marker" in kwargs: - kwargs["marker"]["size"] = size - kwargs["marker"]["color"] = theme[name] - trace = graph_objs.Scatter( - x=new_listx, - y=new_listy, - mode="markers", - name=name, - showlegend=True, - **kwargs, - ) - else: - trace = graph_objs.Scatter( - x=new_listx, - y=new_listy, - mode="markers", - name=name, - marker=dict(size=size, color=theme[name]), - showlegend=True, - **kwargs, - ) - # Generate trace with INVISIBLE icon - else: - if (listx == listy) and (diag == "histogram"): - trace = graph_objs.Histogram( - x=new_listx, - marker=dict(color=theme[name]), - showlegend=False, - ) - elif (listx == listy) and (diag == "box"): - trace = graph_objs.Box( - y=new_listx, - name=None, - marker=dict(color=theme[name]), - showlegend=False, - ) - else: - if "marker" in kwargs: - kwargs["marker"]["size"] = size - kwargs["marker"]["color"] = theme[name] - trace = graph_objs.Scatter( - x=new_listx, - y=new_listy, - mode="markers", - name=name, - showlegend=False, - **kwargs, - ) - else: - trace = graph_objs.Scatter( - x=new_listx, - y=new_listy, - mode="markers", - name=name, - marker=dict(size=size, color=theme[name]), - showlegend=False, - **kwargs, - ) - # Push the trace into dictionary - unique_index_vals[name] = trace - trace_list.append(unique_index_vals) - legend_param += 1 - - trace_index = 0 - indices = range(1, dim + 1) - for y_index in indices: - for x_index in indices: - for name in sorted(trace_list[trace_index].keys()): - fig.append_trace(trace_list[trace_index][name], y_index, x_index) - trace_index += 1 - - # Insert headers into the figure - for j in range(dim): - xaxis_key = "xaxis{}".format((dim * dim) - dim + 1 + j) - fig["layout"][xaxis_key].update(title=headers[j]) - - for j in range(dim): - yaxis_key = "yaxis{}".format(1 + (dim * j)) - fig["layout"][yaxis_key].update(title=headers[j]) - - hide_tick_labels_from_box_subplots(fig) - - if diag == "histogram": - fig["layout"].update( - height=height, width=width, title=title, showlegend=True, barmode="stack" - ) - return fig - - else: - fig["layout"].update(height=height, width=width, title=title, showlegend=True) - return fig - - -def scatterplot_theme( - dataframe, - headers, - diag, - size, - height, - width, - title, - index, - index_vals, - endpts, - colormap, - colormap_type, - **kwargs, -): - """ - Refer to FigureFactory.create_scatterplotmatrix() for docstring - - Returns fig for scatterplotmatrix with both index and colormap picked - - """ - - # Check if index is made of string values - if isinstance(index_vals[0], str): - unique_index_vals = [] - for name in index_vals: - if name not in unique_index_vals: - unique_index_vals.append(name) - n_colors_len = len(unique_index_vals) - - # Convert colormap to list of n RGB tuples - if colormap_type == "seq": - foo = clrs.color_parser(colormap, clrs.unlabel_rgb) - foo = clrs.n_colors(foo[0], foo[1], n_colors_len) - theme = clrs.color_parser(foo, clrs.label_rgb) - - if colormap_type == "cat": - # leave list of colors the same way - theme = colormap - - dim = len(dataframe) - fig = make_subplots(rows=dim, cols=dim, print_grid=False) - trace_list = [] - legend_param = 0 - # Work over all permutations of list pairs - for listy in dataframe: - for listx in dataframe: - # create a dictionary for index_vals - unique_index_vals = {} - for name in index_vals: - if name not in unique_index_vals: - unique_index_vals[name] = [] - - c_indx = 0 # color index - # Fill all the rest of the names into the dictionary - for name in sorted(unique_index_vals.keys()): - new_listx = [] - new_listy = [] - for j in range(len(index_vals)): - if index_vals[j] == name: - new_listx.append(listx[j]) - new_listy.append(listy[j]) - # Generate trace with VISIBLE icon - if legend_param == 1: - if (listx == listy) and (diag == "histogram"): - trace = graph_objs.Histogram( - x=new_listx, - marker=dict(color=theme[c_indx]), - showlegend=True, - ) - elif (listx == listy) and (diag == "box"): - trace = graph_objs.Box( - y=new_listx, - name=None, - marker=dict(color=theme[c_indx]), - showlegend=True, - ) - else: - if "marker" in kwargs: - kwargs["marker"]["size"] = size - kwargs["marker"]["color"] = theme[c_indx] - trace = graph_objs.Scatter( - x=new_listx, - y=new_listy, - mode="markers", - name=name, - showlegend=True, - **kwargs, - ) - else: - trace = graph_objs.Scatter( - x=new_listx, - y=new_listy, - mode="markers", - name=name, - marker=dict(size=size, color=theme[c_indx]), - showlegend=True, - **kwargs, - ) - # Generate trace with INVISIBLE icon - else: - if (listx == listy) and (diag == "histogram"): - trace = graph_objs.Histogram( - x=new_listx, - marker=dict(color=theme[c_indx]), - showlegend=False, - ) - elif (listx == listy) and (diag == "box"): - trace = graph_objs.Box( - y=new_listx, - name=None, - marker=dict(color=theme[c_indx]), - showlegend=False, - ) - else: - if "marker" in kwargs: - kwargs["marker"]["size"] = size - kwargs["marker"]["color"] = theme[c_indx] - trace = graph_objs.Scatter( - x=new_listx, - y=new_listy, - mode="markers", - name=name, - showlegend=False, - **kwargs, - ) - else: - trace = graph_objs.Scatter( - x=new_listx, - y=new_listy, - mode="markers", - name=name, - marker=dict(size=size, color=theme[c_indx]), - showlegend=False, - **kwargs, - ) - # Push the trace into dictionary - unique_index_vals[name] = trace - if c_indx >= (len(theme) - 1): - c_indx = -1 - c_indx += 1 - trace_list.append(unique_index_vals) - legend_param += 1 - - trace_index = 0 - indices = range(1, dim + 1) - for y_index in indices: - for x_index in indices: - for name in sorted(trace_list[trace_index].keys()): - fig.append_trace(trace_list[trace_index][name], y_index, x_index) - trace_index += 1 - - # Insert headers into the figure - for j in range(dim): - xaxis_key = "xaxis{}".format((dim * dim) - dim + 1 + j) - fig["layout"][xaxis_key].update(title=headers[j]) - - for j in range(dim): - yaxis_key = "yaxis{}".format(1 + (dim * j)) - fig["layout"][yaxis_key].update(title=headers[j]) - - hide_tick_labels_from_box_subplots(fig) - - if diag == "histogram": - fig["layout"].update( - height=height, - width=width, - title=title, - showlegend=True, - barmode="stack", - ) - return fig - - elif diag == "box": - fig["layout"].update( - height=height, width=width, title=title, showlegend=True - ) - return fig - - else: - fig["layout"].update( - height=height, width=width, title=title, showlegend=True - ) - return fig - - else: - if endpts: - intervals = utils.endpts_to_intervals(endpts) - - # Convert colormap to list of n RGB tuples - if colormap_type == "seq": - foo = clrs.color_parser(colormap, clrs.unlabel_rgb) - foo = clrs.n_colors(foo[0], foo[1], len(intervals)) - theme = clrs.color_parser(foo, clrs.label_rgb) - - if colormap_type == "cat": - # leave list of colors the same way - theme = colormap - - dim = len(dataframe) - fig = make_subplots(rows=dim, cols=dim, print_grid=False) - trace_list = [] - legend_param = 0 - # Work over all permutations of list pairs - for listy in dataframe: - for listx in dataframe: - interval_labels = {} - for interval in intervals: - interval_labels[str(interval)] = [] - - c_indx = 0 # color index - # Fill all the rest of the names into the dictionary - for interval in intervals: - new_listx = [] - new_listy = [] - for j in range(len(index_vals)): - if interval[0] < index_vals[j] <= interval[1]: - new_listx.append(listx[j]) - new_listy.append(listy[j]) - # Generate trace with VISIBLE icon - if legend_param == 1: - if (listx == listy) and (diag == "histogram"): - trace = graph_objs.Histogram( - x=new_listx, - marker=dict(color=theme[c_indx]), - showlegend=True, - ) - elif (listx == listy) and (diag == "box"): - trace = graph_objs.Box( - y=new_listx, - name=None, - marker=dict(color=theme[c_indx]), - showlegend=True, - ) - else: - if "marker" in kwargs: - kwargs["marker"]["size"] = size - (kwargs["marker"]["color"]) = theme[c_indx] - trace = graph_objs.Scatter( - x=new_listx, - y=new_listy, - mode="markers", - name=str(interval), - showlegend=True, - **kwargs, - ) - else: - trace = graph_objs.Scatter( - x=new_listx, - y=new_listy, - mode="markers", - name=str(interval), - marker=dict(size=size, color=theme[c_indx]), - showlegend=True, - **kwargs, - ) - # Generate trace with INVISIBLE icon - else: - if (listx == listy) and (diag == "histogram"): - trace = graph_objs.Histogram( - x=new_listx, - marker=dict(color=theme[c_indx]), - showlegend=False, - ) - elif (listx == listy) and (diag == "box"): - trace = graph_objs.Box( - y=new_listx, - name=None, - marker=dict(color=theme[c_indx]), - showlegend=False, - ) - else: - if "marker" in kwargs: - kwargs["marker"]["size"] = size - (kwargs["marker"]["color"]) = theme[c_indx] - trace = graph_objs.Scatter( - x=new_listx, - y=new_listy, - mode="markers", - name=str(interval), - showlegend=False, - **kwargs, - ) - else: - trace = graph_objs.Scatter( - x=new_listx, - y=new_listy, - mode="markers", - name=str(interval), - marker=dict(size=size, color=theme[c_indx]), - showlegend=False, - **kwargs, - ) - # Push the trace into dictionary - interval_labels[str(interval)] = trace - if c_indx >= (len(theme) - 1): - c_indx = -1 - c_indx += 1 - trace_list.append(interval_labels) - legend_param += 1 - - trace_index = 0 - indices = range(1, dim + 1) - for y_index in indices: - for x_index in indices: - for interval in intervals: - fig.append_trace( - trace_list[trace_index][str(interval)], y_index, x_index - ) - trace_index += 1 - - # Insert headers into the figure - for j in range(dim): - xaxis_key = "xaxis{}".format((dim * dim) - dim + 1 + j) - fig["layout"][xaxis_key].update(title=headers[j]) - for j in range(dim): - yaxis_key = "yaxis{}".format(1 + (dim * j)) - fig["layout"][yaxis_key].update(title=headers[j]) - - hide_tick_labels_from_box_subplots(fig) - - if diag == "histogram": - fig["layout"].update( - height=height, - width=width, - title=title, - showlegend=True, - barmode="stack", - ) - return fig - - elif diag == "box": - fig["layout"].update( - height=height, width=width, title=title, showlegend=True - ) - return fig - - else: - fig["layout"].update( - height=height, width=width, title=title, showlegend=True - ) - return fig - - else: - theme = colormap - - # add a copy of rgb color to theme if it contains one color - if len(theme) <= 1: - theme.append(theme[0]) - - color = [] - for incr in range(len(theme)): - color.append([1.0 / (len(theme) - 1) * incr, theme[incr]]) - - dim = len(dataframe) - fig = make_subplots(rows=dim, cols=dim, print_grid=False) - trace_list = [] - legend_param = 0 - # Run through all permutations of list pairs - for listy in dataframe: - for listx in dataframe: - # Generate trace with VISIBLE icon - if legend_param == 1: - if (listx == listy) and (diag == "histogram"): - trace = graph_objs.Histogram( - x=listx, marker=dict(color=theme[0]), showlegend=False - ) - elif (listx == listy) and (diag == "box"): - trace = graph_objs.Box( - y=listx, marker=dict(color=theme[0]), showlegend=False - ) - else: - if "marker" in kwargs: - kwargs["marker"]["size"] = size - kwargs["marker"]["color"] = index_vals - kwargs["marker"]["colorscale"] = color - kwargs["marker"]["showscale"] = True - trace = graph_objs.Scatter( - x=listx, - y=listy, - mode="markers", - showlegend=False, - **kwargs, - ) - else: - trace = graph_objs.Scatter( - x=listx, - y=listy, - mode="markers", - marker=dict( - size=size, - color=index_vals, - colorscale=color, - showscale=True, - ), - showlegend=False, - **kwargs, - ) - # Generate trace with INVISIBLE icon - else: - if (listx == listy) and (diag == "histogram"): - trace = graph_objs.Histogram( - x=listx, marker=dict(color=theme[0]), showlegend=False - ) - elif (listx == listy) and (diag == "box"): - trace = graph_objs.Box( - y=listx, marker=dict(color=theme[0]), showlegend=False - ) - else: - if "marker" in kwargs: - kwargs["marker"]["size"] = size - kwargs["marker"]["color"] = index_vals - kwargs["marker"]["colorscale"] = color - kwargs["marker"]["showscale"] = False - trace = graph_objs.Scatter( - x=listx, - y=listy, - mode="markers", - showlegend=False, - **kwargs, - ) - else: - trace = graph_objs.Scatter( - x=listx, - y=listy, - mode="markers", - marker=dict( - size=size, - color=index_vals, - colorscale=color, - showscale=False, - ), - showlegend=False, - **kwargs, - ) - # Push the trace into list - trace_list.append(trace) - legend_param += 1 - - trace_index = 0 - indices = range(1, dim + 1) - for y_index in indices: - for x_index in indices: - fig.append_trace(trace_list[trace_index], y_index, x_index) - trace_index += 1 - - # Insert headers into the figure - for j in range(dim): - xaxis_key = "xaxis{}".format((dim * dim) - dim + 1 + j) - fig["layout"][xaxis_key].update(title=headers[j]) - for j in range(dim): - yaxis_key = "yaxis{}".format(1 + (dim * j)) - fig["layout"][yaxis_key].update(title=headers[j]) - - hide_tick_labels_from_box_subplots(fig) - - if diag == "histogram": - fig["layout"].update( - height=height, - width=width, - title=title, - showlegend=True, - barmode="stack", - ) - return fig - - elif diag == "box": - fig["layout"].update( - height=height, width=width, title=title, showlegend=True - ) - return fig - - else: - fig["layout"].update( - height=height, width=width, title=title, showlegend=True - ) - return fig - - -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, str) 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 diff --git a/plotly/figure_factory/_violin.py b/plotly/figure_factory/_violin.py deleted file mode 100644 index 285733fefd8..00000000000 --- a/plotly/figure_factory/_violin.py +++ /dev/null @@ -1,704 +0,0 @@ -from numbers import Number - -from plotly import exceptions, optional_imports -import plotly.colors as clrs -from plotly.graph_objs import graph_objs -from plotly.subplots import make_subplots - -pd = optional_imports.get_module("pandas") -np = optional_imports.get_module("numpy") -scipy_stats = optional_imports.get_module("scipy.stats") - - -def calc_stats(data): - """ - Calculate statistics for use in violin plot. - """ - x = np.asarray(data, float) - vals_min = np.min(x) - vals_max = np.max(x) - q2 = np.percentile(x, 50, method="linear") - q1 = np.percentile(x, 25, method="lower") - q3 = np.percentile(x, 75, method="higher") - iqr = q3 - q1 - whisker_dist = 1.5 * iqr - - # in order to prevent drawing whiskers outside the interval - # of data one defines the whisker positions as: - d1 = np.min(x[x >= (q1 - whisker_dist)]) - d2 = np.max(x[x <= (q3 + whisker_dist)]) - return { - "min": vals_min, - "max": vals_max, - "q1": q1, - "q2": q2, - "q3": q3, - "d1": d1, - "d2": d2, - } - - -def make_half_violin(x, y, fillcolor="#1f77b4", linecolor="rgb(0, 0, 0)"): - """ - Produces a sideways probability distribution fig violin plot. - """ - text = [ - "(pdf(y), y)=(" + "{:0.2f}".format(x[i]) + ", " + "{:0.2f}".format(y[i]) + ")" - for i in range(len(x)) - ] - - return graph_objs.Scatter( - x=x, - y=y, - mode="lines", - name="", - text=text, - fill="tonextx", - fillcolor=fillcolor, - line=graph_objs.scatter.Line(width=0.5, color=linecolor, shape="spline"), - hoverinfo="text", - opacity=0.5, - ) - - -def make_violin_rugplot(vals, pdf_max, distance, color="#1f77b4"): - """ - Returns a rugplot fig for a violin plot. - """ - return graph_objs.Scatter( - y=vals, - x=[-pdf_max - distance] * len(vals), - marker=graph_objs.scatter.Marker(color=color, symbol="line-ew-open"), - mode="markers", - name="", - showlegend=False, - hoverinfo="y", - ) - - -def make_non_outlier_interval(d1, d2): - """ - Returns the scatterplot fig of most of a violin plot. - """ - return graph_objs.Scatter( - x=[0, 0], - y=[d1, d2], - name="", - mode="lines", - line=graph_objs.scatter.Line(width=1.5, color="rgb(0,0,0)"), - ) - - -def make_quartiles(q1, q3): - """ - Makes the upper and lower quartiles for a violin plot. - """ - return graph_objs.Scatter( - x=[0, 0], - y=[q1, q3], - text=[ - "lower-quartile: " + "{:0.2f}".format(q1), - "upper-quartile: " + "{:0.2f}".format(q3), - ], - mode="lines", - line=graph_objs.scatter.Line(width=4, color="rgb(0,0,0)"), - hoverinfo="text", - ) - - -def make_median(q2): - """ - Formats the 'median' hovertext for a violin plot. - """ - return graph_objs.Scatter( - x=[0], - y=[q2], - text=["median: " + "{:0.2f}".format(q2)], - mode="markers", - marker=dict(symbol="square", color="rgb(255,255,255)"), - hoverinfo="text", - ) - - -def make_XAxis(xaxis_title, xaxis_range): - """ - Makes the x-axis for a violin plot. - """ - xaxis = graph_objs.layout.XAxis( - title=xaxis_title, - range=xaxis_range, - showgrid=False, - zeroline=False, - showline=False, - mirror=False, - ticks="", - showticklabels=False, - ) - return xaxis - - -def make_YAxis(yaxis_title): - """ - Makes the y-axis for a violin plot. - """ - yaxis = graph_objs.layout.YAxis( - title=yaxis_title, - showticklabels=True, - autorange=True, - ticklen=4, - showline=True, - zeroline=False, - showgrid=False, - mirror=False, - ) - return yaxis - - -def violinplot(vals, fillcolor="#1f77b4", rugplot=True): - """ - Refer to FigureFactory.create_violin() for docstring. - """ - vals = np.asarray(vals, float) - # summary statistics - vals_min = calc_stats(vals)["min"] - vals_max = calc_stats(vals)["max"] - q1 = calc_stats(vals)["q1"] - q2 = calc_stats(vals)["q2"] - q3 = calc_stats(vals)["q3"] - d1 = calc_stats(vals)["d1"] - d2 = calc_stats(vals)["d2"] - - # kernel density estimation of pdf - pdf = scipy_stats.gaussian_kde(vals) - # grid over the data interval - xx = np.linspace(vals_min, vals_max, 100) - # evaluate the pdf at the grid xx - yy = pdf(xx) - max_pdf = np.max(yy) - # distance from the violin plot to rugplot - distance = (2.0 * max_pdf) / 10 if rugplot else 0 - # range for x values in the plot - plot_xrange = [-max_pdf - distance - 0.1, max_pdf + 0.1] - plot_data = [ - make_half_violin(-yy, xx, fillcolor=fillcolor), - make_half_violin(yy, xx, fillcolor=fillcolor), - make_non_outlier_interval(d1, d2), - make_quartiles(q1, q3), - make_median(q2), - ] - if rugplot: - plot_data.append( - make_violin_rugplot(vals, max_pdf, distance=distance, color=fillcolor) - ) - return plot_data, plot_xrange - - -def violin_no_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 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() - - 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 - ) - color_index = 0 - for k, gr in enumerate(group_name): - vals = np.asarray(gb.get_group(gr)[data_header], float) - if color_index >= len(colors): - color_index = 0 - plot_data, plot_xrange = violinplot( - vals, fillcolor=colors[color_index], rugplot=rugplot - ) - for item in plot_data: - fig.append_trace(item, 1, k + 1) - color_index += 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 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], 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 - ) - 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 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], float) - plot_data, plot_xrange = violinplot(vals, fillcolor=colors[gr], rugplot=rugplot) - 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 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", -): - """ - **deprecated**, use instead the plotly.graph_objects trace - :class:`plotly.graph_objects.Violin`. - - :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 dictionary 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 - - >>> from plotly.figure_factory import create_violin - >>> import plotly.graph_objs as graph_objects - - >>> import numpy as np - >>> from scipy import stats - - >>> # create list of random values - >>> data_list = np.random.randn(100) - - >>> # create violin fig - >>> fig = create_violin(data_list, colors='#604d9e') - - >>> # plot - >>> fig.show() - - Example 2: Multiple Violin Plots with Qualitative Coloring - - >>> from plotly.figure_factory import create_violin - >>> import plotly.graph_objs as graph_objects - - >>> 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 - >>> fig.show() - - Example 3: Violin Plots with Colorscale - - >>> from plotly.figure_factory import create_violin - >>> import plotly.graph_objs as graph_objects - - >>> 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 - >>> fig.show() - """ - - # 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 diff --git a/plotly/tools.py b/plotly/tools.py index b0875507439..9e5eb0d966e 100644 --- a/plotly/tools.py +++ b/plotly/tools.py @@ -556,14 +556,6 @@ def return_figure_from_figure_or_data(figure_or_data, validate_figure): return figure -# Default colours for finance charts -_DEFAULT_INCREASING_COLOR = "#3D9970" # http://clrs.cc -_DEFAULT_DECREASING_COLOR = "#FF4136" - -DIAG_CHOICES = ["scatter", "histogram", "box"] -VALID_COLORMAP_TYPES = ["cat", "seq"] - - # Deprecations class FigureFactory(object): @staticmethod @@ -576,27 +568,6 @@ def _deprecated(old_method, new_method=None): "Use plotly.figure_factory.{}".format(old_method, new_method) ) - @staticmethod - def create_2D_density(*args, **kwargs): - FigureFactory._deprecated("create_2D_density", "create_2d_density") - from plotly.figure_factory import create_2d_density - - return create_2d_density(*args, **kwargs) - - @staticmethod - def create_annotated_heatmap(*args, **kwargs): - FigureFactory._deprecated("create_annotated_heatmap") - from plotly.figure_factory import create_annotated_heatmap - - return create_annotated_heatmap(*args, **kwargs) - - @staticmethod - def create_candlestick(*args, **kwargs): - FigureFactory._deprecated("create_candlestick") - from plotly.figure_factory import create_candlestick - - return create_candlestick(*args, **kwargs) - @staticmethod def create_dendrogram(*args, **kwargs): FigureFactory._deprecated("create_dendrogram") @@ -604,34 +575,6 @@ def create_dendrogram(*args, **kwargs): return create_dendrogram(*args, **kwargs) - @staticmethod - def create_distplot(*args, **kwargs): - FigureFactory._deprecated("create_distplot") - from plotly.figure_factory import create_distplot - - return create_distplot(*args, **kwargs) - - @staticmethod - def create_facet_grid(*args, **kwargs): - FigureFactory._deprecated("create_facet_grid") - from plotly.figure_factory import create_facet_grid - - return create_facet_grid(*args, **kwargs) - - @staticmethod - def create_gantt(*args, **kwargs): - FigureFactory._deprecated("create_gantt") - from plotly.figure_factory import create_gantt - - return create_gantt(*args, **kwargs) - - @staticmethod - def create_ohlc(*args, **kwargs): - FigureFactory._deprecated("create_ohlc") - from plotly.figure_factory import create_ohlc - - return create_ohlc(*args, **kwargs) - @staticmethod def create_quiver(*args, **kwargs): FigureFactory._deprecated("create_quiver") @@ -639,13 +582,6 @@ def create_quiver(*args, **kwargs): return create_quiver(*args, **kwargs) - @staticmethod - def create_scatterplotmatrix(*args, **kwargs): - FigureFactory._deprecated("create_scatterplotmatrix") - from plotly.figure_factory import create_scatterplotmatrix - - return create_scatterplotmatrix(*args, **kwargs) - @staticmethod def create_streamline(*args, **kwargs): FigureFactory._deprecated("create_streamline") @@ -667,13 +603,6 @@ def create_trisurf(*args, **kwargs): return create_trisurf(*args, **kwargs) - @staticmethod - def create_violin(*args, **kwargs): - FigureFactory._deprecated("create_violin") - from plotly.figure_factory import create_violin - - return create_violin(*args, **kwargs) - def get_config_plotly_server_url(): """ From b45f9d912adf30669d82297db9ab8416826b39d3 Mon Sep 17 00:00:00 2001 From: Emily KL <4672118+emilykl@users.noreply.github.com> Date: Thu, 18 Jun 2026 13:19:09 -0400 Subject: [PATCH 2/8] remove tests for removed Figure Factory functions --- .../test_figure_factory.py | 3074 ----------------- .../test_validate_gantt.py | 95 - .../test_tools/test_figure_factory.py | 1755 ---------- 3 files changed, 4924 deletions(-) delete mode 100644 tests/test_optional/test_figure_factory/test_validate_gantt.py diff --git a/tests/test_optional/test_figure_factory/test_figure_factory.py b/tests/test_optional/test_figure_factory/test_figure_factory.py index 91aee8d4a00..e3a41b7b18f 100644 --- a/tests/test_optional/test_figure_factory/test_figure_factory.py +++ b/tests/test_optional/test_figure_factory/test_figure_factory.py @@ -17,607 +17,6 @@ sk_measure = optional_imports.get_module("skimage") -class TestDistplot(NumpyTestUtilsMixin, TestCaseNoTemplate): - def test_wrong_curve_type(self): - # check: PlotlyError (and specific message) is raised if curve_type is - # not 'kde' or 'normal' - - kwargs = { - "hist_data": [[1, 2, 3]], - "group_labels": ["group"], - "curve_type": "curve", - } - self.assertRaisesRegex( - PlotlyError, - "curve_type must be defined as 'kde' or 'normal'", - ff.create_distplot, - **kwargs, - ) - - def test_wrong_histdata_format(self): - # check: PlotlyError if hist_data is not a list of lists or list of - # np.ndarrays (if hist_data is entered as just a list the function - # will fail) - - kwargs = {"hist_data": [1, 2, 3], "group_labels": ["group"]} - self.assertRaises(PlotlyError, ff.create_distplot, **kwargs) - - def test_unequal_data_label_length(self): - kwargs = {"hist_data": [[1, 2]], "group_labels": ["group", "group2"]} - self.assertRaises(PlotlyError, ff.create_distplot, **kwargs) - - kwargs = {"hist_data": [[1, 2], [1, 2, 3]], "group_labels": ["group"]} - self.assertRaises(PlotlyError, ff.create_distplot, **kwargs) - - def test_simple_distplot_prob_density(self): - # we should be able to create a single distplot with a simple dataset - # and default kwargs - - dp = ff.create_distplot( - hist_data=[[1, 2, 2, 3]], - group_labels=["distplot"], - histnorm="probability density", - ) - expected_dp_layout = { - "barmode": "overlay", - "hovermode": "closest", - "legend": {"traceorder": "reversed"}, - "xaxis": {"anchor": "y2", "domain": [0.0, 1.0], "zeroline": False}, - "yaxis": {"anchor": "free", "domain": [0.35, 1], "position": 0.0}, - "yaxis2": { - "anchor": "x", - "domain": [0, 0.25], - "dtick": 1, - "showticklabels": False, - }, - } - self.assert_fig_equal(dp["layout"], expected_dp_layout) - - expected_dp_data_hist = { - "autobinx": False, - "histnorm": "probability density", - "legendgroup": "distplot", - "marker": {"color": "rgb(31, 119, 180)"}, - "name": "distplot", - "opacity": 0.7, - "type": "histogram", - "x": [1, 2, 2, 3], - "xaxis": "x", - "xbins": {"end": 3.0, "size": 1.0, "start": 1.0}, - "yaxis": "y", - } - self.assert_fig_equal(dp["data"][0], expected_dp_data_hist) - - expected_dp_data_rug = { - "legendgroup": "distplot", - "marker": {"color": "rgb(31, 119, 180)", "symbol": "line-ns-open"}, - "mode": "markers", - "name": "distplot", - "showlegend": False, - "type": "scatter", - "x": [1, 2, 2, 3], - "xaxis": "x", - "y": ["distplot", "distplot", "distplot", "distplot"], - "yaxis": "y2", - } - self.assert_fig_equal(dp["data"][2], expected_dp_data_rug) - - def test_simple_distplot_prob(self): - # we should be able to create a single distplot with a simple dataset - # and default kwargs - - dp = ff.create_distplot( - hist_data=[[1, 2, 2, 3]], group_labels=["distplot"], histnorm="probability" - ) - expected_dp_layout = { - "barmode": "overlay", - "hovermode": "closest", - "legend": {"traceorder": "reversed"}, - "xaxis": {"anchor": "y2", "domain": [0.0, 1.0], "zeroline": False}, - "yaxis": {"anchor": "free", "domain": [0.35, 1], "position": 0.0}, - "yaxis2": { - "anchor": "x", - "domain": [0, 0.25], - "dtick": 1, - "showticklabels": False, - }, - } - self.assert_fig_equal(dp["layout"], expected_dp_layout) - - expected_dp_data_hist = { - "autobinx": False, - "histnorm": "probability", - "legendgroup": "distplot", - "marker": {"color": "rgb(31, 119, 180)"}, - "name": "distplot", - "opacity": 0.7, - "type": "histogram", - "x": [1, 2, 2, 3], - "xaxis": "x", - "xbins": {"end": 3.0, "size": 1.0, "start": 1.0}, - "yaxis": "y", - } - self.assert_fig_equal(dp["data"][0], expected_dp_data_hist) - - expected_dp_data_rug = { - "legendgroup": "distplot", - "marker": {"color": "rgb(31, 119, 180)", "symbol": "line-ns-open"}, - "mode": "markers", - "name": "distplot", - "showlegend": False, - "type": "scatter", - "x": [1, 2, 2, 3], - "xaxis": "x", - "y": ["distplot", "distplot", "distplot", "distplot"], - "yaxis": "y2", - } - self.assert_fig_equal(dp["data"][2], expected_dp_data_rug) - - def test_distplot_more_args_prob_dens(self): - # we should be able to create a distplot with 2 datasets no - # rugplot, defined bin_size, and added title - - hist1_x = [ - 0.8, - 1.2, - 0.2, - 0.6, - 1.6, - -0.9, - -0.07, - 1.95, - 0.9, - -0.2, - -0.5, - 0.3, - 0.4, - -0.37, - 0.6, - ] - hist2_x = [ - 0.8, - 1.5, - 1.5, - 0.6, - 0.59, - 1.0, - 0.8, - 1.7, - 0.5, - 0.8, - -0.3, - 1.2, - 0.56, - 0.3, - 2.2, - ] - - hist_data = [hist1_x] + [hist2_x] - group_labels = ["2012", "2013"] - - dp = ff.create_distplot( - hist_data, - group_labels, - histnorm="probability density", - show_rug=False, - bin_size=0.2, - ) - dp["layout"].update(title="Dist Plot") - - expected_dp_layout = { - "barmode": "overlay", - "hovermode": "closest", - "legend": {"traceorder": "reversed"}, - "xaxis": {"anchor": "y2", "domain": [0.0, 1.0], "zeroline": False}, - "yaxis": {"anchor": "free", "domain": [0.0, 1], "position": 0.0}, - "title": {"text": "Dist Plot"}, - } - self.assert_fig_equal(dp["layout"], expected_dp_layout) - - expected_dp_data_hist_1 = { - "autobinx": False, - "histnorm": "probability density", - "legendgroup": "2012", - "marker": {"color": "rgb(31, 119, 180)"}, - "name": "2012", - "opacity": 0.7, - "type": "histogram", - "x": [ - 0.8, - 1.2, - 0.2, - 0.6, - 1.6, - -0.9, - -0.07, - 1.95, - 0.9, - -0.2, - -0.5, - 0.3, - 0.4, - -0.37, - 0.6, - ], - "xaxis": "x", - "xbins": {"end": 1.95, "size": 0.2, "start": -0.9}, - "yaxis": "y", - } - self.assert_fig_equal(dp["data"][0], expected_dp_data_hist_1) - - expected_dp_data_hist_2 = { - "autobinx": False, - "histnorm": "probability density", - "legendgroup": "2013", - "marker": {"color": "rgb(255, 127, 14)"}, - "name": "2013", - "opacity": 0.7, - "type": "histogram", - "x": [ - 0.8, - 1.5, - 1.5, - 0.6, - 0.59, - 1.0, - 0.8, - 1.7, - 0.5, - 0.8, - -0.3, - 1.2, - 0.56, - 0.3, - 2.2, - ], - "xaxis": "x", - "xbins": {"end": 2.2, "size": 0.2, "start": -0.3}, - "yaxis": "y", - } - self.assert_fig_equal(dp["data"][1], expected_dp_data_hist_2) - - def test_distplot_more_args_prob(self): - # we should be able to create a distplot with 2 datasets no - # rugplot, defined bin_size, and added title - - hist1_x = [ - 0.8, - 1.2, - 0.2, - 0.6, - 1.6, - -0.9, - -0.07, - 1.95, - 0.9, - -0.2, - -0.5, - 0.3, - 0.4, - -0.37, - 0.6, - ] - hist2_x = [ - 0.8, - 1.5, - 1.5, - 0.6, - 0.59, - 1.0, - 0.8, - 1.7, - 0.5, - 0.8, - -0.3, - 1.2, - 0.56, - 0.3, - 2.2, - ] - - hist_data = [hist1_x] + [hist2_x] - group_labels = ["2012", "2013"] - - dp = ff.create_distplot( - hist_data, - group_labels, - histnorm="probability", - show_rug=False, - bin_size=0.2, - ) - dp["layout"].update(title="Dist Plot") - - expected_dp_layout = { - "barmode": "overlay", - "hovermode": "closest", - "legend": {"traceorder": "reversed"}, - "title": {"text": "Dist Plot"}, - "xaxis": {"anchor": "y2", "domain": [0.0, 1.0], "zeroline": False}, - "yaxis": {"anchor": "free", "domain": [0.0, 1], "position": 0.0}, - } - self.assert_fig_equal(dp["layout"], expected_dp_layout) - - expected_dp_data_hist_1 = { - "autobinx": False, - "histnorm": "probability", - "legendgroup": "2012", - "marker": {"color": "rgb(31, 119, 180)"}, - "name": "2012", - "opacity": 0.7, - "type": "histogram", - "x": [ - 0.8, - 1.2, - 0.2, - 0.6, - 1.6, - -0.9, - -0.07, - 1.95, - 0.9, - -0.2, - -0.5, - 0.3, - 0.4, - -0.37, - 0.6, - ], - "xaxis": "x", - "xbins": {"end": 1.95, "size": 0.2, "start": -0.9}, - "yaxis": "y", - } - self.assert_fig_equal(dp["data"][0], expected_dp_data_hist_1) - - expected_dp_data_hist_2 = { - "autobinx": False, - "histnorm": "probability", - "legendgroup": "2013", - "marker": {"color": "rgb(255, 127, 14)"}, - "name": "2013", - "opacity": 0.7, - "type": "histogram", - "x": [ - 0.8, - 1.5, - 1.5, - 0.6, - 0.59, - 1.0, - 0.8, - 1.7, - 0.5, - 0.8, - -0.3, - 1.2, - 0.56, - 0.3, - 2.2, - ], - "xaxis": "x", - "xbins": {"end": 2.2, "size": 0.2, "start": -0.3}, - "yaxis": "y", - } - self.assert_fig_equal(dp["data"][1], expected_dp_data_hist_2) - - def test_distplot_binsize_array_prob(self): - hist1_x = [ - 0.8, - 1.2, - 0.2, - 0.6, - 1.6, - -0.9, - -0.07, - 1.95, - 0.9, - -0.2, - -0.5, - 0.3, - 0.4, - -0.37, - 0.6, - ] - hist2_x = [ - 0.8, - 1.5, - 1.5, - 0.6, - 0.59, - 1.0, - 0.8, - 1.7, - 0.5, - 0.8, - -0.3, - 1.2, - 0.56, - 0.3, - 2.2, - ] - - hist_data = [hist1_x, hist2_x] - group_labels = ["2012", "2013"] - - dp = ff.create_distplot( - hist_data, - group_labels, - histnorm="probability", - show_rug=False, - bin_size=[0.2, 0.2], - ) - - expected_dp_data_hist_1 = { - "autobinx": False, - "histnorm": "probability density", - "legendgroup": "2012", - "marker": {"color": "rgb(31,119,180)"}, - "name": "2012", - "opacity": 0.7, - "type": "histogram", - "x": [ - 0.8, - 1.2, - 0.2, - 0.6, - 1.6, - -0.9, - -0.07, - 1.95, - 0.9, - -0.2, - -0.5, - 0.3, - 0.4, - -0.37, - 0.6, - ], - "xaxis": "x", - "xbins": {"end": 1.95, "size": 0.2, "start": -0.9}, - "yaxis": "y", - } - self.assert_fig_equal(dp["data"][0], expected_dp_data_hist_1) - - expected_dp_data_hist_2 = { - "autobinx": False, - "histnorm": "probability density", - "legendgroup": "2013", - "marker": {"color": "rgb(255,127,14)"}, - "name": "2013", - "opacity": 0.7, - "type": "histogram", - "x": [ - 0.8, - 1.5, - 1.5, - 0.6, - 0.59, - 1.0, - 0.8, - 1.7, - 0.5, - 0.8, - -0.3, - 1.2, - 0.56, - 0.3, - 2.2, - ], - "xaxis": "x", - "xbins": {"end": 2.2, "size": 0.2, "start": -0.3}, - "yaxis": "y", - } - self.assert_fig_equal(dp["data"][1], expected_dp_data_hist_2) - - def test_distplot_binsize_array_prob_density(self): - hist1_x = [ - 0.8, - 1.2, - 0.2, - 0.6, - 1.6, - -0.9, - -0.07, - 1.95, - 0.9, - -0.2, - -0.5, - 0.3, - 0.4, - -0.37, - 0.6, - ] - hist2_x = [ - 0.8, - 1.5, - 1.5, - 0.6, - 0.59, - 1.0, - 0.8, - 1.7, - 0.5, - 0.8, - -0.3, - 1.2, - 0.56, - 0.3, - 2.2, - ] - - hist_data = [hist1_x, hist2_x] - group_labels = ["2012", "2013"] - - dp = ff.create_distplot( - hist_data, - group_labels, - histnorm="probability", - show_rug=False, - bin_size=[0.2, 0.2], - ) - - expected_dp_data_hist_1 = { - "autobinx": False, - "histnorm": "probability density", - "legendgroup": "2012", - "marker": {"color": "rgb(31,119,180)"}, - "name": "2012", - "opacity": 0.7, - "type": "histogram", - "x": [ - 0.8, - 1.2, - 0.2, - 0.6, - 1.6, - -0.9, - -0.07, - 1.95, - 0.9, - -0.2, - -0.5, - 0.3, - 0.4, - -0.37, - 0.6, - ], - "xaxis": "x", - "xbins": {"end": 1.95, "size": 0.2, "start": -0.9}, - "yaxis": "y", - } - self.assert_fig_equal(dp["data"][0], expected_dp_data_hist_1) - - expected_dp_data_hist_2 = { - "autobinx": False, - "histnorm": "probability density", - "legendgroup": "2013", - "marker": {"color": "rgb(255,127,14)"}, - "name": "2013", - "opacity": 0.7, - "type": "histogram", - "x": [ - 0.8, - 1.5, - 1.5, - 0.6, - 0.59, - 1.0, - 0.8, - 1.7, - 0.5, - 0.8, - -0.3, - 1.2, - 0.56, - 0.3, - 2.2, - ], - "xaxis": "x", - "xbins": {"end": 2.2, "size": 0.2, "start": -0.3}, - "yaxis": "y", - } - self.assert_fig_equal(dp["data"][1], expected_dp_data_hist_2) - - class TestStreamline(TestCaseNoTemplate): def test_wrong_arrow_scale(self): # check for ValueError if arrow_scale is <= 0 @@ -1581,2479 +980,6 @@ def test_trisurf_all_args(self): self.assertTrue(isinstance(test_colors_plot["data"][0]["facecolor"][0], str)) -class TestScatterPlotMatrix(NumpyTestUtilsMixin, TestCaseNoTemplate): - def test_dataframe_input(self): - # check: dataframe is imported - df = "foo" - - pattern = ( - "Dataframe not inputed. Please use a pandas dataframe to produce " - "a scatterplot matrix." - ) - - self.assertRaisesRegex(PlotlyError, pattern, ff.create_scatterplotmatrix, df) - - def test_one_column_dataframe(self): - # check: dataframe has 1 column or less - df = pd.DataFrame([1, 2, 3]) - - pattern = ( - "Dataframe has only one column. To use the scatterplot matrix, " - "use at least 2 columns." - ) - - self.assertRaisesRegex(PlotlyError, pattern, ff.create_scatterplotmatrix, df) - - def test_valid_diag_choice(self): - # make sure that the diagonal param is valid - df = pd.DataFrame([[1, 2, 3], [4, 5, 6]]) - - self.assertRaises(PlotlyError, ff.create_scatterplotmatrix, df, diag="foo") - - def test_forbidden_params(self): - # check: the forbidden params of 'marker' in **kwargs - df = pd.DataFrame([[1, 2, 3], [4, 5, 6]]) - - kwargs = {"marker": {"size": 15}} - - pattern = ( - "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." - ) - - self.assertRaisesRegex( - PlotlyError, pattern, ff.create_scatterplotmatrix, df, **kwargs - ) - - def test_valid_index_choice(self): - # check: index is a column name - df = pd.DataFrame([[1, 2], [3, 4]], columns=["apple", "pear"]) - - pattern = ( - "Make sure you set the index input variable to one of the column " - "names of your dataframe." - ) - - self.assertRaisesRegex( - PlotlyError, pattern, ff.create_scatterplotmatrix, df, index="grape" - ) - - def test_same_data_in_dataframe_columns(self): - # check: either all numbers or strings in each dataframe column - df = pd.DataFrame([["a", 2], [3, 4]]) - - pattern = ( - "Error in dataframe. Make sure all entries of each column are " - "either numbers or strings." - ) - - self.assertRaisesRegex(PlotlyError, pattern, ff.create_scatterplotmatrix, df) - - df = pd.DataFrame([[1, 2], ["a", 4]]) - - self.assertRaisesRegex(PlotlyError, pattern, ff.create_scatterplotmatrix, df) - - def test_same_data_in_index(self): - # check: either all numbers or strings in index column - df = pd.DataFrame([["a", 2], [3, 4]], columns=["apple", "pear"]) - - pattern = ( - "Error in indexing column. Make sure all entries of each column " - "are all numbers or all strings." - ) - - self.assertRaisesRegex( - PlotlyError, pattern, ff.create_scatterplotmatrix, df, index="apple" - ) - - df = pd.DataFrame([[1, 2], ["a", 4]], columns=["apple", "pear"]) - - self.assertRaisesRegex( - PlotlyError, pattern, ff.create_scatterplotmatrix, df, index="apple" - ) - - def test_valid_colormap(self): - # check: the colormap argument is in a valid form - df = pd.DataFrame([[1, 2, 3], [4, 5, 6], [7, 8, 9]], columns=["a", "b", "c"]) - - # check: valid plotly scalename is entered - self.assertRaises( - PlotlyError, - ff.create_scatterplotmatrix, - df, - index="a", - colormap="fake_scale", - ) - - pattern_rgb = ( - "Whoops! The elements in your rgb colors tuples cannot exceed 255.0." - ) - - # check: proper 'rgb' color - self.assertRaisesRegex( - PlotlyError, - pattern_rgb, - ff.create_scatterplotmatrix, - df, - colormap="rgb(500, 1, 1)", - index="c", - ) - - self.assertRaisesRegex( - PlotlyError, - pattern_rgb, - ff.create_scatterplotmatrix, - df, - colormap=["rgb(500, 1, 1)"], - index="c", - ) - - pattern_tuple = "Whoops! The elements in your colors tuples cannot exceed 1.0." - - # check: proper color tuple - self.assertRaisesRegex( - PlotlyError, - pattern_tuple, - ff.create_scatterplotmatrix, - df, - colormap=(2, 1, 1), - index="c", - ) - - self.assertRaisesRegex( - PlotlyError, - pattern_tuple, - ff.create_scatterplotmatrix, - df, - colormap=[(2, 1, 1)], - index="c", - ) - - def test_valid_endpts(self): - # check: the endpts is a list or a tuple - df = pd.DataFrame([[1, 2, 3], [4, 5, 6], [7, 8, 9]], columns=["a", "b", "c"]) - - pattern = ( - "The intervals_endpts argument must be a list or tuple of a " - "sequence of increasing numbers." - ) - - self.assertRaisesRegex( - PlotlyError, - pattern, - ff.create_scatterplotmatrix, - df, - index="a", - colormap="Hot", - endpts="foo", - ) - - # check: the endpts are a list of numbers - self.assertRaisesRegex( - PlotlyError, - pattern, - ff.create_scatterplotmatrix, - df, - index="a", - colormap="Hot", - endpts=["a"], - ) - - # check: endpts is a list of INCREASING numbers - self.assertRaisesRegex( - PlotlyError, - pattern, - ff.create_scatterplotmatrix, - df, - index="a", - colormap="Hot", - endpts=[2, 1], - ) - - def test_dictionary_colormap(self): - # if colormap is a dictionary, make sure it all the values in the - # index column are keys in colormap - df = pd.DataFrame( - [["apple", "happy"], ["pear", "sad"]], columns=["Fruit", "Emotion"] - ) - - colormap = {"happy": "rgb(5, 5, 5)"} - - pattern = ( - "If colormap is a dictionary, all the names in the index must be keys." - ) - - self.assertRaisesRegex( - PlotlyError, - pattern, - ff.create_scatterplotmatrix, - df, - index="Emotion", - colormap=colormap, - ) - - def test_scatter_plot_matrix(self): - # check if test scatter plot matrix without index or theme matches - # with the expected output - df = pd.DataFrame( - [ - [2, "Apple"], - [6, "Pear"], - [-15, "Apple"], - [5, "Pear"], - [-2, "Apple"], - [0, "Apple"], - ], - columns=["Numbers", "Fruit"], - ) - - test_scatter_plot_matrix = ff.create_scatterplotmatrix( - df=df, - diag="box", - height=1000, - width=1000, - size=13, - title="Scatterplot Matrix", - ) - - exp_scatter_plot_matrix = { - "data": [ - { - "showlegend": False, - "type": "box", - "xaxis": "x", - "y": [2, 6, -15, 5, -2, 0], - "yaxis": "y", - }, - { - "marker": {"size": 13}, - "mode": "markers", - "showlegend": False, - "type": "scatter", - "x": ["Apple", "Pear", "Apple", "Pear", "Apple", "Apple"], - "xaxis": "x2", - "y": [2, 6, -15, 5, -2, 0], - "yaxis": "y2", - }, - { - "marker": {"size": 13}, - "mode": "markers", - "showlegend": False, - "type": "scatter", - "x": [2, 6, -15, 5, -2, 0], - "xaxis": "x3", - "y": ["Apple", "Pear", "Apple", "Pear", "Apple", "Apple"], - "yaxis": "y3", - }, - { - "name": None, - "showlegend": False, - "type": "box", - "xaxis": "x4", - "y": ["Apple", "Pear", "Apple", "Pear", "Apple", "Apple"], - "yaxis": "y4", - }, - ], - "layout": { - "height": 1000, - "showlegend": True, - "title": {"text": "Scatterplot Matrix"}, - "width": 1000, - "xaxis": { - "anchor": "y", - "domain": [0.0, 0.45], - "showticklabels": False, - }, - "xaxis2": {"anchor": "y2", "domain": [0.55, 1.0]}, - "xaxis3": { - "anchor": "y3", - "domain": [0.0, 0.45], - "title": {"text": "Numbers"}, - }, - "xaxis4": { - "anchor": "y4", - "domain": [0.55, 1.0], - "showticklabels": False, - "title": {"text": "Fruit"}, - }, - "yaxis": { - "anchor": "x", - "domain": [0.575, 1.0], - "title": {"text": "Numbers"}, - }, - "yaxis2": {"anchor": "x2", "domain": [0.575, 1.0]}, - "yaxis3": { - "anchor": "x3", - "domain": [0.0, 0.425], - "title": {"text": "Fruit"}, - }, - "yaxis4": {"anchor": "x4", "domain": [0.0, 0.425]}, - }, - } - - self.assert_fig_equal( - test_scatter_plot_matrix["data"][0], exp_scatter_plot_matrix["data"][0] - ) - - self.assert_fig_equal( - test_scatter_plot_matrix["data"][1], exp_scatter_plot_matrix["data"][1] - ) - - self.assert_fig_equal( - test_scatter_plot_matrix["layout"], exp_scatter_plot_matrix["layout"] - ) - - def test_scatter_plot_matrix_kwargs(self): - # check if test scatter plot matrix matches with - # the expected output - df = pd.DataFrame( - [ - [2, "Apple"], - [6, "Pear"], - [-15, "Apple"], - [5, "Pear"], - [-2, "Apple"], - [0, "Apple"], - ], - columns=["Numbers", "Fruit"], - ) - - test_scatter_plot_matrix = ff.create_scatterplotmatrix( - df, - index="Fruit", - endpts=[-10, -1], - diag="histogram", - height=1000, - width=1000, - size=13, - title="Scatterplot Matrix", - colormap="YlOrRd", - marker=dict(symbol=136), - ) - - exp_scatter_plot_matrix = { - "data": [ - { - "marker": {"color": "rgb(128, 0, 38)"}, - "showlegend": False, - "type": "histogram", - "x": [2, -15, -2, 0], - "xaxis": "x", - "yaxis": "y", - }, - { - "marker": {"color": "rgb(255, 255, 204)"}, - "showlegend": False, - "type": "histogram", - "x": [6, 5], - "xaxis": "x", - "yaxis": "y", - }, - ], - "layout": { - "barmode": "stack", - "height": 1000, - "showlegend": True, - "title": {"text": "Scatterplot Matrix"}, - "width": 1000, - "xaxis": { - "anchor": "y", - "domain": [0.0, 1.0], - "title": {"text": "Numbers"}, - }, - "yaxis": { - "anchor": "x", - "domain": [0.0, 1.0], - "title": {"text": "Numbers"}, - }, - }, - } - - self.assert_fig_equal( - test_scatter_plot_matrix["data"][0], exp_scatter_plot_matrix["data"][0] - ) - - self.assert_fig_equal( - test_scatter_plot_matrix["data"][1], exp_scatter_plot_matrix["data"][1] - ) - - self.assert_fig_equal( - test_scatter_plot_matrix["layout"], exp_scatter_plot_matrix["layout"] - ) - - -class TestGantt(NumpyTestUtilsMixin, TestCaseNoTemplate): - def test_df_dataframe(self): - # validate dataframe has correct column names - df1 = pd.DataFrame([[2, "Apple"]], columns=["Numbers", "Fruit"]) - self.assertRaises(PlotlyError, ff.create_gantt, df1) - - def test_df_dataframe_all_args(self): - # check if gantt chart matches with expected output - - df = pd.DataFrame( - [ - ["Job A", "2009-01-01", "2009-02-30"], - ["Job B", "2009-03-05", "2009-04-15"], - ], - columns=["Task", "Start", "Finish"], - ) - - test_gantt_chart = ff.create_gantt(df) - - exp_gantt_chart = go.Figure( - **{ - "data": [ - { - "x": ("2009-03-05", "2009-04-15", "2009-04-15", "2009-03-05"), - "y": [0.8, 0.8, 1.2, 1.2], - "mode": "none", - "fill": "toself", - "hoverinfo": "name", - "fillcolor": "rgb(255, 127, 14)", - "name": "Job B", - "legendgroup": "rgb(255, 127, 14)", - }, - { - "x": ("2009-01-01", "2009-02-30", "2009-02-30", "2009-01-01"), - "y": [-0.2, -0.2, 0.2, 0.2], - "mode": "none", - "fill": "toself", - "hoverinfo": "name", - "fillcolor": "rgb(31, 119, 180)", - "name": "Job A", - "legendgroup": "rgb(31, 119, 180)", - }, - { - "x": ("2009-03-05", "2009-04-15"), - "y": [1, 1], - "mode": "markers", - "text": [None, None], - "marker": { - "color": "rgb(255, 127, 14)", - "size": 1, - "opacity": 0, - }, - "name": "", - "showlegend": False, - "legendgroup": "rgb(255, 127, 14)", - }, - { - "x": ("2009-01-01", "2009-02-30"), - "y": [0, 0], - "mode": "markers", - "text": [None, None], - "marker": { - "color": "rgb(31, 119, 180)", - "size": 1, - "opacity": 0, - }, - "name": "", - "showlegend": False, - "legendgroup": "rgb(31, 119, 180)", - }, - ], - "layout": { - "title": "Gantt Chart", - "showlegend": False, - "height": 600, - "width": 900, - "shapes": [], - "hovermode": "closest", - "yaxis": { - "showgrid": False, - "ticktext": ["Job A", "Job B"], - "tickvals": [0, 1], - "range": [-1, 3], - "autorange": False, - "zeroline": False, - }, - "xaxis": { - "showgrid": False, - "zeroline": False, - "rangeselector": { - "buttons": [ - { - "count": 7, - "label": "1w", - "step": "day", - "stepmode": "backward", - }, - { - "count": 1, - "label": "1m", - "step": "month", - "stepmode": "backward", - }, - { - "count": 6, - "label": "6m", - "step": "month", - "stepmode": "backward", - }, - { - "count": 1, - "label": "YTD", - "step": "year", - "stepmode": "todate", - }, - { - "count": 1, - "label": "1y", - "step": "year", - "stepmode": "backward", - }, - {"step": "all"}, - ] - }, - "type": "date", - }, - }, - } - ) - - self.assert_fig_equal(test_gantt_chart["data"][1], exp_gantt_chart["data"][1]) - self.assert_fig_equal(test_gantt_chart["data"][1], exp_gantt_chart["data"][1]) - self.assert_fig_equal(test_gantt_chart["data"][2], exp_gantt_chart["data"][2]) - self.assert_fig_equal(test_gantt_chart["data"][3], exp_gantt_chart["data"][3]) - - -class TestViolin(NumpyTestUtilsMixin, TestCaseNoTemplate): - def test_colors_validation(self): - # check: colors is in an acceptable form - - data = [1, 5, 8] - - pattern = "Whoops! The elements in your rgb colors tuples cannot exceed 255.0." - - self.assertRaisesRegex( - PlotlyError, pattern, ff.create_violin, data, colors="rgb(300, 2, 3)" - ) - - self.assertRaisesRegex( - PlotlyError, pattern, ff.create_violin, data, colors=["rgb(300, 2, 3)"] - ) - - self.assertRaisesRegex( - PlotlyError, - pattern, - ff.create_violin, - data, - colors={"apple": "rgb(300, 2, 3)"}, - ) - - pattern2 = "Whoops! The elements in your colors tuples cannot exceed 1.0." - - self.assertRaisesRegex( - PlotlyError, pattern2, ff.create_violin, data, colors=(1.1, 1, 1) - ) - - self.assertRaisesRegex( - PlotlyError, pattern2, ff.create_violin, data, colors=[(1.1, 1, 1)] - ) - - self.assertRaisesRegex( - PlotlyError, pattern2, ff.create_violin, data, colors={"apple": (1.1, 1, 1)} - ) - - # check: if valid string color is inputted - self.assertRaises(PlotlyError, ff.create_violin, data, colors="foo") - - def test_data_header(self): - # make sure data_header is entered - - data = pd.DataFrame([["apple", 2], ["pear", 4]], columns=["a", "b"]) - - pattern = ( - "data_header must be the column name with the desired " - "numeric data for the violin plot." - ) - - self.assertRaisesRegex( - PlotlyError, - pattern, - ff.create_violin, - data, - group_header="a", - colors=["rgb(1, 2, 3)"], - ) - - def test_data_as_list(self): - # check: data is a non empty list of numbers - - data = [] - - pattern = ( - "If data is a list, it must be nonempty and contain " - "either numbers or dictionaries." - ) - - self.assertRaisesRegex(PlotlyError, pattern, ff.create_violin, data) - - data = [1, "foo"] - - pattern2 = "If data is a list, it must contain only numbers." - - self.assertRaisesRegex(PlotlyError, pattern2, ff.create_violin, data) - - def test_dataframe_input(self): - # check: dataframe is entered if group_header is True - - data = [1, 2, 3] - - pattern = ( - "Error. You must use a pandas DataFrame if you are using a group header." - ) - - self.assertRaisesRegex( - PlotlyError, pattern, ff.create_violin, data, group_header=True - ) - - def test_colors_dict(self): - # check: if colorscale is True, make sure colors is not a dictionary - - data = pd.DataFrame([["apple", 2], ["pear", 4]], columns=["a", "b"]) - - pattern = ( - "The colors param cannot be a dictionary if you are using a colorscale." - ) - - self.assertRaisesRegex( - PlotlyError, - pattern, - ff.create_violin, - data, - data_header="b", - group_header="a", - use_colorscale=True, - colors={"a": "rgb(1, 2, 3)"}, - ) - - # check: colors contains all group names as keys - - pattern2 = ( - "If colors is a dictionary, all the group names must " - "appear as keys in colors." - ) - - self.assertRaisesRegex( - PlotlyError, - pattern2, - ff.create_violin, - data, - data_header="b", - group_header="a", - use_colorscale=False, - colors={"a": "rgb(1, 2, 3)"}, - ) - - def test_valid_colorscale(self): - # check: if colorscale is enabled, colors is a list with 2+ items - - data = pd.DataFrame([["apple", 2], ["pear", 4]], columns=["a", "b"]) - - pattern = ( - "colors must be a list with at least 2 colors. A Plotly scale is allowed." - ) - - self.assertRaisesRegex( - PlotlyError, - pattern, - ff.create_violin, - data, - data_header="b", - group_header="a", - use_colorscale=True, - colors="rgb(1, 2, 3)", - ) - - def test_group_stats(self): - # check: group_stats is a dictionary - - data = pd.DataFrame([["apple", 2], ["pear", 4]], columns=["a", "b"]) - - pattern = "Your group_stats param must be a dictionary." - - self.assertRaisesRegex( - PlotlyError, - pattern, - ff.create_violin, - data, - data_header="b", - group_header="a", - use_colorscale=True, - colors=["rgb(1, 2, 3)", "rgb(4, 5, 6)"], - group_stats=1, - ) - - # check: all groups are represented as keys in group_stats - - pattern2 = ( - "All values/groups in the index column must be " - "represented as a key in group_stats." - ) - - self.assertRaisesRegex( - PlotlyError, - pattern2, - ff.create_violin, - data, - data_header="b", - group_header="a", - use_colorscale=True, - colors=["rgb(1, 2, 3)", "rgb(4, 5, 6)"], - group_stats={"apple": 1}, - ) - - def test_violin_fig(self): - # check: test violin fig matches expected fig - - test_violin = ff.create_violin(data=[1, 2]) - - exp_violin = { - "data": [ - { - "fill": "tonextx", - "fillcolor": "rgb(31, 119, 180)", - "hoverinfo": "text", - "line": {"color": "rgb(0, 0, 0)", "shape": "spline", "width": 0.5}, - "mode": "lines", - "name": "", - "opacity": 0.5, - "text": [ - "(pdf(y), y)=(-0.41, 1.00)", - "(pdf(y), y)=(-0.41, 1.01)", - "(pdf(y), y)=(-0.42, 1.02)", - "(pdf(y), y)=(-0.42, 1.03)", - "(pdf(y), y)=(-0.42, 1.04)", - "(pdf(y), y)=(-0.42, 1.05)", - "(pdf(y), y)=(-0.42, 1.06)", - "(pdf(y), y)=(-0.43, 1.07)", - "(pdf(y), y)=(-0.43, 1.08)", - "(pdf(y), y)=(-0.43, 1.09)", - "(pdf(y), y)=(-0.43, 1.10)", - "(pdf(y), y)=(-0.43, 1.11)", - "(pdf(y), y)=(-0.43, 1.12)", - "(pdf(y), y)=(-0.44, 1.13)", - "(pdf(y), y)=(-0.44, 1.14)", - "(pdf(y), y)=(-0.44, 1.15)", - "(pdf(y), y)=(-0.44, 1.16)", - "(pdf(y), y)=(-0.44, 1.17)", - "(pdf(y), y)=(-0.44, 1.18)", - "(pdf(y), y)=(-0.45, 1.19)", - "(pdf(y), y)=(-0.45, 1.20)", - "(pdf(y), y)=(-0.45, 1.21)", - "(pdf(y), y)=(-0.45, 1.22)", - "(pdf(y), y)=(-0.45, 1.23)", - "(pdf(y), y)=(-0.45, 1.24)", - "(pdf(y), y)=(-0.45, 1.25)", - "(pdf(y), y)=(-0.45, 1.26)", - "(pdf(y), y)=(-0.45, 1.27)", - "(pdf(y), y)=(-0.46, 1.28)", - "(pdf(y), y)=(-0.46, 1.29)", - "(pdf(y), y)=(-0.46, 1.30)", - "(pdf(y), y)=(-0.46, 1.31)", - "(pdf(y), y)=(-0.46, 1.32)", - "(pdf(y), y)=(-0.46, 1.33)", - "(pdf(y), y)=(-0.46, 1.34)", - "(pdf(y), y)=(-0.46, 1.35)", - "(pdf(y), y)=(-0.46, 1.36)", - "(pdf(y), y)=(-0.46, 1.37)", - "(pdf(y), y)=(-0.46, 1.38)", - "(pdf(y), y)=(-0.46, 1.39)", - "(pdf(y), y)=(-0.46, 1.40)", - "(pdf(y), y)=(-0.46, 1.41)", - "(pdf(y), y)=(-0.46, 1.42)", - "(pdf(y), y)=(-0.47, 1.43)", - "(pdf(y), y)=(-0.47, 1.44)", - "(pdf(y), y)=(-0.47, 1.45)", - "(pdf(y), y)=(-0.47, 1.46)", - "(pdf(y), y)=(-0.47, 1.47)", - "(pdf(y), y)=(-0.47, 1.48)", - "(pdf(y), y)=(-0.47, 1.49)", - "(pdf(y), y)=(-0.47, 1.51)", - "(pdf(y), y)=(-0.47, 1.52)", - "(pdf(y), y)=(-0.47, 1.53)", - "(pdf(y), y)=(-0.47, 1.54)", - "(pdf(y), y)=(-0.47, 1.55)", - "(pdf(y), y)=(-0.47, 1.56)", - "(pdf(y), y)=(-0.47, 1.57)", - "(pdf(y), y)=(-0.46, 1.58)", - "(pdf(y), y)=(-0.46, 1.59)", - "(pdf(y), y)=(-0.46, 1.60)", - "(pdf(y), y)=(-0.46, 1.61)", - "(pdf(y), y)=(-0.46, 1.62)", - "(pdf(y), y)=(-0.46, 1.63)", - "(pdf(y), y)=(-0.46, 1.64)", - "(pdf(y), y)=(-0.46, 1.65)", - "(pdf(y), y)=(-0.46, 1.66)", - "(pdf(y), y)=(-0.46, 1.67)", - "(pdf(y), y)=(-0.46, 1.68)", - "(pdf(y), y)=(-0.46, 1.69)", - "(pdf(y), y)=(-0.46, 1.70)", - "(pdf(y), y)=(-0.46, 1.71)", - "(pdf(y), y)=(-0.46, 1.72)", - "(pdf(y), y)=(-0.45, 1.73)", - "(pdf(y), y)=(-0.45, 1.74)", - "(pdf(y), y)=(-0.45, 1.75)", - "(pdf(y), y)=(-0.45, 1.76)", - "(pdf(y), y)=(-0.45, 1.77)", - "(pdf(y), y)=(-0.45, 1.78)", - "(pdf(y), y)=(-0.45, 1.79)", - "(pdf(y), y)=(-0.45, 1.80)", - "(pdf(y), y)=(-0.45, 1.81)", - "(pdf(y), y)=(-0.44, 1.82)", - "(pdf(y), y)=(-0.44, 1.83)", - "(pdf(y), y)=(-0.44, 1.84)", - "(pdf(y), y)=(-0.44, 1.85)", - "(pdf(y), y)=(-0.44, 1.86)", - "(pdf(y), y)=(-0.44, 1.87)", - "(pdf(y), y)=(-0.43, 1.88)", - "(pdf(y), y)=(-0.43, 1.89)", - "(pdf(y), y)=(-0.43, 1.90)", - "(pdf(y), y)=(-0.43, 1.91)", - "(pdf(y), y)=(-0.43, 1.92)", - "(pdf(y), y)=(-0.43, 1.93)", - "(pdf(y), y)=(-0.42, 1.94)", - "(pdf(y), y)=(-0.42, 1.95)", - "(pdf(y), y)=(-0.42, 1.96)", - "(pdf(y), y)=(-0.42, 1.97)", - "(pdf(y), y)=(-0.42, 1.98)", - "(pdf(y), y)=(-0.41, 1.99)", - "(pdf(y), y)=(-0.41, 2.00)", - ], - "type": "scatter", - "x": np.array( - [ - -0.41064744, - -0.41293151, - -0.41516635, - -0.41735177, - -0.41948764, - -0.42157385, - -0.42361031, - -0.42559697, - -0.42753381, - -0.42942082, - -0.43125804, - -0.43304552, - -0.43478334, - -0.4364716, - -0.4381104, - -0.4396999, - -0.44124025, - -0.44273162, - -0.4441742, - -0.4455682, - -0.44691382, - -0.44821129, - -0.44946086, - -0.45066275, - -0.45181723, - -0.45292454, - -0.45398495, - -0.45499871, - -0.45596609, - -0.45688735, - -0.45776275, - -0.45859254, - -0.45937698, - -0.46011631, - -0.46081078, - -0.46146061, - -0.46206603, - -0.46262726, - -0.46314449, - -0.46361791, - -0.4640477, - -0.46443404, - -0.46477705, - -0.46507689, - -0.46533367, - -0.46554749, - -0.46571845, - -0.4658466, - -0.46593201, - -0.4659747, - -0.4659747, - -0.46593201, - -0.4658466, - -0.46571845, - -0.46554749, - -0.46533367, - -0.46507689, - -0.46477705, - -0.46443404, - -0.4640477, - -0.46361791, - -0.46314449, - -0.46262726, - -0.46206603, - -0.46146061, - -0.46081078, - -0.46011631, - -0.45937698, - -0.45859254, - -0.45776275, - -0.45688735, - -0.45596609, - -0.45499871, - -0.45398495, - -0.45292454, - -0.45181723, - -0.45066275, - -0.44946086, - -0.44821129, - -0.44691382, - -0.4455682, - -0.4441742, - -0.44273162, - -0.44124025, - -0.4396999, - -0.4381104, - -0.4364716, - -0.43478334, - -0.43304552, - -0.43125804, - -0.42942082, - -0.42753381, - -0.42559697, - -0.42361031, - -0.42157385, - -0.41948764, - -0.41735177, - -0.41516635, - -0.41293151, - -0.41064744, - ] - ), - "y": np.array( - [ - 1.0, - 1.01010101, - 1.02020202, - 1.03030303, - 1.04040404, - 1.05050505, - 1.06060606, - 1.07070707, - 1.08080808, - 1.09090909, - 1.1010101, - 1.11111111, - 1.12121212, - 1.13131313, - 1.14141414, - 1.15151515, - 1.16161616, - 1.17171717, - 1.18181818, - 1.19191919, - 1.2020202, - 1.21212121, - 1.22222222, - 1.23232323, - 1.24242424, - 1.25252525, - 1.26262626, - 1.27272727, - 1.28282828, - 1.29292929, - 1.3030303, - 1.31313131, - 1.32323232, - 1.33333333, - 1.34343434, - 1.35353535, - 1.36363636, - 1.37373737, - 1.38383838, - 1.39393939, - 1.4040404, - 1.41414141, - 1.42424242, - 1.43434343, - 1.44444444, - 1.45454545, - 1.46464646, - 1.47474747, - 1.48484848, - 1.49494949, - 1.50505051, - 1.51515152, - 1.52525253, - 1.53535354, - 1.54545455, - 1.55555556, - 1.56565657, - 1.57575758, - 1.58585859, - 1.5959596, - 1.60606061, - 1.61616162, - 1.62626263, - 1.63636364, - 1.64646465, - 1.65656566, - 1.66666667, - 1.67676768, - 1.68686869, - 1.6969697, - 1.70707071, - 1.71717172, - 1.72727273, - 1.73737374, - 1.74747475, - 1.75757576, - 1.76767677, - 1.77777778, - 1.78787879, - 1.7979798, - 1.80808081, - 1.81818182, - 1.82828283, - 1.83838384, - 1.84848485, - 1.85858586, - 1.86868687, - 1.87878788, - 1.88888889, - 1.8989899, - 1.90909091, - 1.91919192, - 1.92929293, - 1.93939394, - 1.94949495, - 1.95959596, - 1.96969697, - 1.97979798, - 1.98989899, - 2.0, - ] - ), - }, - { - "fill": "tonextx", - "fillcolor": "rgb(31, 119, 180)", - "hoverinfo": "text", - "line": {"color": "rgb(0, 0, 0)", "shape": "spline", "width": 0.5}, - "mode": "lines", - "name": "", - "opacity": 0.5, - "text": [ - "(pdf(y), y)=(0.41, 1.00)", - "(pdf(y), y)=(0.41, 1.01)", - "(pdf(y), y)=(0.42, 1.02)", - "(pdf(y), y)=(0.42, 1.03)", - "(pdf(y), y)=(0.42, 1.04)", - "(pdf(y), y)=(0.42, 1.05)", - "(pdf(y), y)=(0.42, 1.06)", - "(pdf(y), y)=(0.43, 1.07)", - "(pdf(y), y)=(0.43, 1.08)", - "(pdf(y), y)=(0.43, 1.09)", - "(pdf(y), y)=(0.43, 1.10)", - "(pdf(y), y)=(0.43, 1.11)", - "(pdf(y), y)=(0.43, 1.12)", - "(pdf(y), y)=(0.44, 1.13)", - "(pdf(y), y)=(0.44, 1.14)", - "(pdf(y), y)=(0.44, 1.15)", - "(pdf(y), y)=(0.44, 1.16)", - "(pdf(y), y)=(0.44, 1.17)", - "(pdf(y), y)=(0.44, 1.18)", - "(pdf(y), y)=(0.45, 1.19)", - "(pdf(y), y)=(0.45, 1.20)", - "(pdf(y), y)=(0.45, 1.21)", - "(pdf(y), y)=(0.45, 1.22)", - "(pdf(y), y)=(0.45, 1.23)", - "(pdf(y), y)=(0.45, 1.24)", - "(pdf(y), y)=(0.45, 1.25)", - "(pdf(y), y)=(0.45, 1.26)", - "(pdf(y), y)=(0.45, 1.27)", - "(pdf(y), y)=(0.46, 1.28)", - "(pdf(y), y)=(0.46, 1.29)", - "(pdf(y), y)=(0.46, 1.30)", - "(pdf(y), y)=(0.46, 1.31)", - "(pdf(y), y)=(0.46, 1.32)", - "(pdf(y), y)=(0.46, 1.33)", - "(pdf(y), y)=(0.46, 1.34)", - "(pdf(y), y)=(0.46, 1.35)", - "(pdf(y), y)=(0.46, 1.36)", - "(pdf(y), y)=(0.46, 1.37)", - "(pdf(y), y)=(0.46, 1.38)", - "(pdf(y), y)=(0.46, 1.39)", - "(pdf(y), y)=(0.46, 1.40)", - "(pdf(y), y)=(0.46, 1.41)", - "(pdf(y), y)=(0.46, 1.42)", - "(pdf(y), y)=(0.47, 1.43)", - "(pdf(y), y)=(0.47, 1.44)", - "(pdf(y), y)=(0.47, 1.45)", - "(pdf(y), y)=(0.47, 1.46)", - "(pdf(y), y)=(0.47, 1.47)", - "(pdf(y), y)=(0.47, 1.48)", - "(pdf(y), y)=(0.47, 1.49)", - "(pdf(y), y)=(0.47, 1.51)", - "(pdf(y), y)=(0.47, 1.52)", - "(pdf(y), y)=(0.47, 1.53)", - "(pdf(y), y)=(0.47, 1.54)", - "(pdf(y), y)=(0.47, 1.55)", - "(pdf(y), y)=(0.47, 1.56)", - "(pdf(y), y)=(0.47, 1.57)", - "(pdf(y), y)=(0.46, 1.58)", - "(pdf(y), y)=(0.46, 1.59)", - "(pdf(y), y)=(0.46, 1.60)", - "(pdf(y), y)=(0.46, 1.61)", - "(pdf(y), y)=(0.46, 1.62)", - "(pdf(y), y)=(0.46, 1.63)", - "(pdf(y), y)=(0.46, 1.64)", - "(pdf(y), y)=(0.46, 1.65)", - "(pdf(y), y)=(0.46, 1.66)", - "(pdf(y), y)=(0.46, 1.67)", - "(pdf(y), y)=(0.46, 1.68)", - "(pdf(y), y)=(0.46, 1.69)", - "(pdf(y), y)=(0.46, 1.70)", - "(pdf(y), y)=(0.46, 1.71)", - "(pdf(y), y)=(0.46, 1.72)", - "(pdf(y), y)=(0.45, 1.73)", - "(pdf(y), y)=(0.45, 1.74)", - "(pdf(y), y)=(0.45, 1.75)", - "(pdf(y), y)=(0.45, 1.76)", - "(pdf(y), y)=(0.45, 1.77)", - "(pdf(y), y)=(0.45, 1.78)", - "(pdf(y), y)=(0.45, 1.79)", - "(pdf(y), y)=(0.45, 1.80)", - "(pdf(y), y)=(0.45, 1.81)", - "(pdf(y), y)=(0.44, 1.82)", - "(pdf(y), y)=(0.44, 1.83)", - "(pdf(y), y)=(0.44, 1.84)", - "(pdf(y), y)=(0.44, 1.85)", - "(pdf(y), y)=(0.44, 1.86)", - "(pdf(y), y)=(0.44, 1.87)", - "(pdf(y), y)=(0.43, 1.88)", - "(pdf(y), y)=(0.43, 1.89)", - "(pdf(y), y)=(0.43, 1.90)", - "(pdf(y), y)=(0.43, 1.91)", - "(pdf(y), y)=(0.43, 1.92)", - "(pdf(y), y)=(0.43, 1.93)", - "(pdf(y), y)=(0.42, 1.94)", - "(pdf(y), y)=(0.42, 1.95)", - "(pdf(y), y)=(0.42, 1.96)", - "(pdf(y), y)=(0.42, 1.97)", - "(pdf(y), y)=(0.42, 1.98)", - "(pdf(y), y)=(0.41, 1.99)", - "(pdf(y), y)=(0.41, 2.00)", - ], - "type": "scatter", - "x": np.array( - [ - 0.41064744, - 0.41293151, - 0.41516635, - 0.41735177, - 0.41948764, - 0.42157385, - 0.42361031, - 0.42559697, - 0.42753381, - 0.42942082, - 0.43125804, - 0.43304552, - 0.43478334, - 0.4364716, - 0.4381104, - 0.4396999, - 0.44124025, - 0.44273162, - 0.4441742, - 0.4455682, - 0.44691382, - 0.44821129, - 0.44946086, - 0.45066275, - 0.45181723, - 0.45292454, - 0.45398495, - 0.45499871, - 0.45596609, - 0.45688735, - 0.45776275, - 0.45859254, - 0.45937698, - 0.46011631, - 0.46081078, - 0.46146061, - 0.46206603, - 0.46262726, - 0.46314449, - 0.46361791, - 0.4640477, - 0.46443404, - 0.46477705, - 0.46507689, - 0.46533367, - 0.46554749, - 0.46571845, - 0.4658466, - 0.46593201, - 0.4659747, - 0.4659747, - 0.46593201, - 0.4658466, - 0.46571845, - 0.46554749, - 0.46533367, - 0.46507689, - 0.46477705, - 0.46443404, - 0.4640477, - 0.46361791, - 0.46314449, - 0.46262726, - 0.46206603, - 0.46146061, - 0.46081078, - 0.46011631, - 0.45937698, - 0.45859254, - 0.45776275, - 0.45688735, - 0.45596609, - 0.45499871, - 0.45398495, - 0.45292454, - 0.45181723, - 0.45066275, - 0.44946086, - 0.44821129, - 0.44691382, - 0.4455682, - 0.4441742, - 0.44273162, - 0.44124025, - 0.4396999, - 0.4381104, - 0.4364716, - 0.43478334, - 0.43304552, - 0.43125804, - 0.42942082, - 0.42753381, - 0.42559697, - 0.42361031, - 0.42157385, - 0.41948764, - 0.41735177, - 0.41516635, - 0.41293151, - 0.41064744, - ] - ), - "y": np.array( - [ - 1.0, - 1.01010101, - 1.02020202, - 1.03030303, - 1.04040404, - 1.05050505, - 1.06060606, - 1.07070707, - 1.08080808, - 1.09090909, - 1.1010101, - 1.11111111, - 1.12121212, - 1.13131313, - 1.14141414, - 1.15151515, - 1.16161616, - 1.17171717, - 1.18181818, - 1.19191919, - 1.2020202, - 1.21212121, - 1.22222222, - 1.23232323, - 1.24242424, - 1.25252525, - 1.26262626, - 1.27272727, - 1.28282828, - 1.29292929, - 1.3030303, - 1.31313131, - 1.32323232, - 1.33333333, - 1.34343434, - 1.35353535, - 1.36363636, - 1.37373737, - 1.38383838, - 1.39393939, - 1.4040404, - 1.41414141, - 1.42424242, - 1.43434343, - 1.44444444, - 1.45454545, - 1.46464646, - 1.47474747, - 1.48484848, - 1.49494949, - 1.50505051, - 1.51515152, - 1.52525253, - 1.53535354, - 1.54545455, - 1.55555556, - 1.56565657, - 1.57575758, - 1.58585859, - 1.5959596, - 1.60606061, - 1.61616162, - 1.62626263, - 1.63636364, - 1.64646465, - 1.65656566, - 1.66666667, - 1.67676768, - 1.68686869, - 1.6969697, - 1.70707071, - 1.71717172, - 1.72727273, - 1.73737374, - 1.74747475, - 1.75757576, - 1.76767677, - 1.77777778, - 1.78787879, - 1.7979798, - 1.80808081, - 1.81818182, - 1.82828283, - 1.83838384, - 1.84848485, - 1.85858586, - 1.86868687, - 1.87878788, - 1.88888889, - 1.8989899, - 1.90909091, - 1.91919192, - 1.92929293, - 1.93939394, - 1.94949495, - 1.95959596, - 1.96969697, - 1.97979798, - 1.98989899, - 2.0, - ] - ), - }, - { - "line": {"color": "rgb(0, 0, 0)", "width": 1.5}, - "mode": "lines", - "name": "", - "type": "scatter", - "x": [0, 0], - "y": [1.0, 2.0], - }, - { - "hoverinfo": "text", - "line": {"color": "rgb(0, 0, 0)", "width": 4}, - "mode": "lines", - "text": ["lower-quartile: 1.00", "upper-quartile: 2.00"], - "type": "scatter", - "x": [0, 0], - "y": [1.0, 2.0], - }, - { - "hoverinfo": "text", - "marker": {"color": "rgb(255, 255, 255)", "symbol": "square"}, - "mode": "markers", - "text": ["median: 1.50"], - "type": "scatter", - "x": [0], - "y": [1.5], - }, - { - "hoverinfo": "y", - "marker": {"color": "rgb(31, 119, 180)", "symbol": "line-ew-open"}, - "mode": "markers", - "name": "", - "showlegend": False, - "type": "scatter", - "x": [-0.55916964093970667, -0.55916964093970667], - "y": np.array([1.0, 2.0]), - }, - ], - "layout": { - "autosize": False, - "font": {"size": 11}, - "height": 450, - "hovermode": "closest", - "showlegend": False, - "title": {"text": "Violin and Rug Plot"}, - "width": 600, - "xaxis": { - "mirror": False, - "range": [-0.65916964093970665, 0.56597470078308887], - "showgrid": False, - "showline": False, - "showticklabels": False, - "ticks": "", - "title": {"text": ""}, - "zeroline": False, - }, - "yaxis": { - "autorange": True, - "mirror": False, - "showgrid": False, - "showline": False, - "showticklabels": False, - "ticklen": 4, - "ticks": "", - "title": {"text": ""}, - "zeroline": False, - }, - }, - } - - # test both items in 'data' - for i in [0, 1]: - self.assert_fig_equal(test_violin["data"][i], exp_violin["data"][i]) - - self.assert_fig_equal(test_violin["layout"], exp_violin["layout"]) - - -class TestFacetGrid(NumpyTestUtilsMixin, TestCaseNoTemplate): - def test_data_must_be_dataframe(self): - data = [] - - pattern = "You must input a pandas DataFrame." - - self.assertRaisesRegex( - PlotlyError, pattern, ff.create_facet_grid, data, "a", "b" - ) - - def test_x_and_y_for_scatter(self): - data = pd.DataFrame([[0, 0], [1, 1]], columns=["a", "b"]) - - pattern = ( - "You need to input 'x' and 'y' if you are you are using a " - "trace_type of 'scatter' or 'scattergl'." - ) - - self.assertRaisesRegex(PlotlyError, pattern, ff.create_facet_grid, data, "a") - - def test_valid_col_selection(self): - data = pd.DataFrame([[0, 0], [1, 1]], columns=["a", "b"]) - - pattern = ( - "x, y, facet_row, facet_col and color_name must be keys in your dataframe." - ) - - self.assertRaisesRegex( - PlotlyError, pattern, ff.create_facet_grid, data, "a", "c" - ) - - def test_valid_trace_type(self): - data = pd.DataFrame([[0, 0], [1, 1]], columns=["a", "b"]) - - self.assertRaises( - PlotlyError, ff.create_facet_grid, data, "a", "b", trace_type="foo" - ) - - def test_valid_scales(self): - data = pd.DataFrame([[0, 0], [1, 1]], columns=["a", "b"]) - - pattern = "'scales' must be set to 'fixed', 'free_x', 'free_y' and 'free'." - - self.assertRaisesRegex( - PlotlyError, - pattern, - ff.create_facet_grid, - data, - "a", - "b", - scales="not_free", - ) - - def test_valid_plotly_color_scale_name(self): - data = pd.DataFrame([[0, 0], [1, 1]], columns=["a", "b"]) - - self.assertRaises( - PlotlyError, - ff.create_facet_grid, - data, - "a", - "b", - color_name="a", - colormap="wrong one", - ) - - def test_facet_labels(self): - data = pd.DataFrame([["a1", 0], ["a2", 1]], columns=["a", "b"]) - - self.assertRaises( - PlotlyError, - ff.create_facet_grid, - data, - "a", - "b", - facet_row="a", - facet_row_labels={}, - ) - - self.assertRaises( - PlotlyError, - ff.create_facet_grid, - data, - "a", - "b", - facet_col="a", - facet_col_labels={}, - ) - - def test_valid_color_dict(self): - data = pd.DataFrame([[0, 0, "foo"], [1, 1, "foo"]], columns=["a", "b", "foo"]) - - pattern = ( - "If using 'colormap' as a dictionary, make sure " - "all the values of the colormap column are in " - "the keys of your dictionary." - ) - - color_dict = {"bar": "#ffffff"} - - self.assertRaisesRegex( - PlotlyError, - pattern, - ff.create_facet_grid, - data, - "a", - "b", - color_name="a", - colormap=color_dict, - ) - - def test_valid_colorscale_name(self): - data = pd.DataFrame([[0, 1, 2], [3, 4, 5]], columns=["a", "b", "c"]) - - colormap = "foo" - - self.assertRaises( - PlotlyError, - ff.create_facet_grid, - data, - "a", - "b", - color_name="c", - colormap=colormap, - ) - - def test_valid_facet_grid_fig(self): - mpg = [ - ["audi", "a4", 1.8, 1999, 4, "auto(15)", "f", 18, 29, "p", "compact"], - ["audi", "a4", 1.8, 1999, 4, "auto(l5)", "f", 18, 29, "p", "compact"], - ["audi", "a4", 2, 2008, 4, "manual(m6)", "f", 20, 31, "p", "compact"], - ["audi", "a4", 2, 2008, 4, "auto(av)", "f", 21, 30, "p", "compact"], - ["audi", "a4", 2.8, 1999, 6, "auto(l5)", "f", 16, 26, "p", "compact"], - ["audi", "a4", 2.8, 1999, 6, "manual(m5)", "f", 18, 26, "p", "compact"], - ["audi", "a4", 3.1, 2008, 6, "auto(av)", "f", 18, 27, "p", "compact"], - [ - "audi", - "a4 quattro", - 1.8, - 1999, - 4, - "manual(m5)", - "4", - 18, - 26, - "p", - "compact", - ], - [ - "audi", - "a4 quattro", - 1.8, - 1999, - 4, - "auto(l5)", - "4", - 16, - 25, - "p", - "compact", - ], - [ - "audi", - "a4 quattro", - 2, - 2008, - 4, - "manual(m6)", - "4", - 20, - 28, - "p", - "compact", - ], - ] - - df = pd.DataFrame( - mpg, - columns=[ - "manufacturer", - "model", - "displ", - "year", - "cyl", - "trans", - "drv", - "cty", - "hwy", - "fl", - "class", - ], - ) - test_facet_grid = ff.create_facet_grid(df, x="displ", y="cty", facet_col="cyl") - - exp_facet_grid = { - "data": [ - { - "marker": { - "color": "rgb(31, 119, 180)", - "line": {"color": "darkgrey", "width": 1}, - "size": 8, - }, - "mode": "markers", - "opacity": 0.6, - "type": "scatter", - "x": [1.8, 1.8, 2.0, 2.0, 1.8, 1.8, 2.0], - "xaxis": "x", - "y": [18, 18, 20, 21, 18, 16, 20], - "yaxis": "y", - }, - { - "marker": { - "color": "rgb(31, 119, 180)", - "line": {"color": "darkgrey", "width": 1}, - "size": 8, - }, - "mode": "markers", - "opacity": 0.6, - "type": "scatter", - "x": [2.8, 2.8, 3.1], - "xaxis": "x2", - "y": [16, 18, 18], - "yaxis": "y2", - }, - ], - "layout": { - "annotations": [ - { - "font": {"color": "#0f0f0f", "size": 13}, - "showarrow": False, - "text": "4", - "textangle": 0, - "x": 0.24625, - "xanchor": "center", - "xref": "paper", - "y": 1.03, - "yanchor": "middle", - "yref": "paper", - }, - { - "font": {"color": "#0f0f0f", "size": 13}, - "showarrow": False, - "text": "6", - "textangle": 0, - "x": 0.7537499999999999, - "xanchor": "center", - "xref": "paper", - "y": 1.03, - "yanchor": "middle", - "yref": "paper", - }, - { - "font": {"color": "#000000", "size": 12}, - "showarrow": False, - "text": "displ", - "textangle": 0, - "x": 0.5, - "xanchor": "center", - "xref": "paper", - "y": -0.1, - "yanchor": "middle", - "yref": "paper", - }, - { - "font": {"color": "#000000", "size": 12}, - "showarrow": False, - "text": "cty", - "textangle": -90, - "x": -0.1, - "xanchor": "center", - "xref": "paper", - "y": 0.5, - "yanchor": "middle", - "yref": "paper", - }, - ], - "height": 600, - "legend": { - "bgcolor": "#efefef", - "borderwidth": 1, - "x": 1.05, - "y": 1, - "yanchor": "top", - }, - "paper_bgcolor": "rgb(251, 251, 251)", - "showlegend": False, - "title": {"text": ""}, - "width": 600, - "xaxis": { - "anchor": "y", - "domain": [0.0, 0.4925], - "dtick": 0, - "range": [0.85, 4.1575], - "ticklen": 0, - "zeroline": False, - }, - "xaxis2": { - "anchor": "y2", - "domain": [0.5075, 1.0], - "dtick": 0, - "range": [0.85, 4.1575], - "ticklen": 0, - "zeroline": False, - }, - "yaxis": { - "anchor": "x", - "domain": [0.0, 1.0], - "dtick": 1, - "range": [15.75, 21.2625], - "ticklen": 0, - "zeroline": False, - }, - "yaxis2": { - "anchor": "x2", - "domain": [0.0, 1.0], - "dtick": 1, - "matches": "y", - "range": [15.75, 21.2625], - "showticklabels": False, - "ticklen": 0, - "zeroline": False, - }, - }, - } - - for j in [0, 1]: - self.assert_fig_equal(test_facet_grid["data"][j], exp_facet_grid["data"][j]) - - self.assert_fig_equal(test_facet_grid["layout"], exp_facet_grid["layout"]) - - -class TestBullet(NumpyTestUtilsMixin, TestCaseNoTemplate): - def test_df_as_list(self): - df = [{"titles": "Revenue"}, "foo"] - - pattern = ( - "Every entry of the data argument (list, tuple, etc) must be a dictionary." - ) - self.assertRaisesRegex(PlotlyError, pattern, ff.create_bullet, df) - - def test_not_df_or_list(self): - df = "foo" - - pattern = "You must input a pandas DataFrame, or a list of dictionaries." - self.assertRaisesRegex(PlotlyError, pattern, ff.create_bullet, df) - - def test_valid_color_lists_of_2_rgb_colors(self): - df = [{"title": "Revenue"}] - - range_colors = ["rgb(0, 0, 0)"] - measure_colors = ["rgb(0, 0, 0)"] - - pattern = ( - "Both 'range_colors' or 'measure_colors' must be a list " - "of two valid colors." - ) - self.assertRaisesRegex( - PlotlyError, pattern, ff.create_bullet, df, range_colors=range_colors - ) - - self.assertRaisesRegex( - PlotlyError, pattern, ff.create_bullet, df, measure_colors=measure_colors - ) - - def test_full_bullet(self): - data = [ - { - "title": "Revenue", - "subtitle": "US$, in thousands", - "ranges": [150, 225, 300], - "measures": [220, 270], - "markers": [250], - }, - { - "title": "Profit", - "subtitle": "%", - "ranges": [20, 25, 30], - "measures": [21, 23], - "markers": [26], - }, - { - "title": "Order Size", - "subtitle": "US$, average", - "ranges": [350, 500, 600], - "measures": [100, 320], - "markers": [550], - }, - { - "title": "New Customers", - "subtitle": "count", - "ranges": [1400, 2000, 2500], - "measures": [1000, 1650], - "markers": [2100], - }, - { - "title": "Satisfaction", - "subtitle": "out of 5", - "ranges": [3.5, 4.25, 5], - "measures": [3.2, 4.7], - "markers": [4.4], - }, - ] - - df = pd.DataFrame(data) - - measure_colors = ["rgb(255, 127, 14)", "rgb(44, 160, 44)"] - range_colors = ["rgb(255, 127, 14)", "rgb(44, 160, 44)"] - - fig = ff.create_bullet( - df, - orientation="v", - markers="markers", - measures="measures", - ranges="ranges", - subtitles="subtitle", - titles="title", - range_colors=range_colors, - measure_colors=measure_colors, - title="new title", - scatter_options={"marker": {"size": 30, "symbol": "hourglass"}}, - ) - - exp_fig = { - "data": [ - { - "base": 0, - "hoverinfo": "y", - "marker": {"color": "rgb(44.0, 160.0, 44.0)"}, - "name": "ranges", - "orientation": "v", - "type": "bar", - "width": 2, - "x": [0], - "xaxis": "x", - "y": [300], - "yaxis": "y", - }, - { - "base": 0, - "hoverinfo": "y", - "marker": {"color": "rgb(149.5, 143.5, 29.0)"}, - "name": "ranges", - "orientation": "v", - "type": "bar", - "width": 2, - "x": [0], - "xaxis": "x", - "y": [225], - "yaxis": "y", - }, - { - "base": 0, - "hoverinfo": "y", - "marker": {"color": "rgb(255.0, 127.0, 14.0)"}, - "name": "ranges", - "orientation": "v", - "type": "bar", - "width": 2, - "x": [0], - "xaxis": "x", - "y": [150], - "yaxis": "y", - }, - { - "base": 0, - "hoverinfo": "y", - "marker": {"color": "rgb(44.0, 160.0, 44.0)"}, - "name": "measures", - "orientation": "v", - "type": "bar", - "width": 0.4, - "x": [0.5], - "xaxis": "x", - "y": [270], - "yaxis": "y", - }, - { - "base": 0, - "hoverinfo": "y", - "marker": {"color": "rgb(255.0, 127.0, 14.0)"}, - "name": "measures", - "orientation": "v", - "type": "bar", - "width": 0.4, - "x": [0.5], - "xaxis": "x", - "y": [220], - "yaxis": "y", - }, - { - "hoverinfo": "y", - "marker": { - "color": "rgb(0, 0, 0)", - "size": 30, - "symbol": "hourglass", - }, - "name": "markers", - "type": "scatter", - "x": [0.5], - "xaxis": "x", - "y": [250], - "yaxis": "y", - }, - { - "base": 0, - "hoverinfo": "y", - "marker": {"color": "rgb(44.0, 160.0, 44.0)"}, - "name": "ranges", - "orientation": "v", - "type": "bar", - "width": 2, - "x": [0], - "xaxis": "x2", - "y": [30], - "yaxis": "y2", - }, - { - "base": 0, - "hoverinfo": "y", - "marker": {"color": "rgb(149.5, 143.5, 29.0)"}, - "name": "ranges", - "orientation": "v", - "type": "bar", - "width": 2, - "x": [0], - "xaxis": "x2", - "y": [25], - "yaxis": "y2", - }, - { - "base": 0, - "hoverinfo": "y", - "marker": {"color": "rgb(255.0, 127.0, 14.0)"}, - "name": "ranges", - "orientation": "v", - "type": "bar", - "width": 2, - "x": [0], - "xaxis": "x2", - "y": [20], - "yaxis": "y2", - }, - { - "base": 0, - "hoverinfo": "y", - "marker": {"color": "rgb(44.0, 160.0, 44.0)"}, - "name": "measures", - "orientation": "v", - "type": "bar", - "width": 0.4, - "x": [0.5], - "xaxis": "x2", - "y": [23], - "yaxis": "y2", - }, - { - "base": 0, - "hoverinfo": "y", - "marker": {"color": "rgb(255.0, 127.0, 14.0)"}, - "name": "measures", - "orientation": "v", - "type": "bar", - "width": 0.4, - "x": [0.5], - "xaxis": "x2", - "y": [21], - "yaxis": "y2", - }, - { - "hoverinfo": "y", - "marker": { - "color": "rgb(0, 0, 0)", - "size": 30, - "symbol": "hourglass", - }, - "name": "markers", - "type": "scatter", - "x": [0.5], - "xaxis": "x2", - "y": [26], - "yaxis": "y2", - }, - { - "base": 0, - "hoverinfo": "y", - "marker": {"color": "rgb(44.0, 160.0, 44.0)"}, - "name": "ranges", - "orientation": "v", - "type": "bar", - "width": 2, - "x": [0], - "xaxis": "x3", - "y": [600], - "yaxis": "y3", - }, - { - "base": 0, - "hoverinfo": "y", - "marker": {"color": "rgb(149.5, 143.5, 29.0)"}, - "name": "ranges", - "orientation": "v", - "type": "bar", - "width": 2, - "x": [0], - "xaxis": "x3", - "y": [500], - "yaxis": "y3", - }, - { - "base": 0, - "hoverinfo": "y", - "marker": {"color": "rgb(255.0, 127.0, 14.0)"}, - "name": "ranges", - "orientation": "v", - "type": "bar", - "width": 2, - "x": [0], - "xaxis": "x3", - "y": [350], - "yaxis": "y3", - }, - { - "base": 0, - "hoverinfo": "y", - "marker": {"color": "rgb(44.0, 160.0, 44.0)"}, - "name": "measures", - "orientation": "v", - "type": "bar", - "width": 0.4, - "x": [0.5], - "xaxis": "x3", - "y": [320], - "yaxis": "y3", - }, - { - "base": 0, - "hoverinfo": "y", - "marker": {"color": "rgb(255.0, 127.0, 14.0)"}, - "name": "measures", - "orientation": "v", - "type": "bar", - "width": 0.4, - "x": [0.5], - "xaxis": "x3", - "y": [100], - "yaxis": "y3", - }, - { - "hoverinfo": "y", - "marker": { - "color": "rgb(0, 0, 0)", - "size": 30, - "symbol": "hourglass", - }, - "name": "markers", - "type": "scatter", - "x": [0.5], - "xaxis": "x3", - "y": [550], - "yaxis": "y3", - }, - { - "base": 0, - "hoverinfo": "y", - "marker": {"color": "rgb(44.0, 160.0, 44.0)"}, - "name": "ranges", - "orientation": "v", - "type": "bar", - "width": 2, - "x": [0], - "xaxis": "x4", - "y": [2500], - "yaxis": "y4", - }, - { - "base": 0, - "hoverinfo": "y", - "marker": {"color": "rgb(149.5, 143.5, 29.0)"}, - "name": "ranges", - "orientation": "v", - "type": "bar", - "width": 2, - "x": [0], - "xaxis": "x4", - "y": [2000], - "yaxis": "y4", - }, - { - "base": 0, - "hoverinfo": "y", - "marker": {"color": "rgb(255.0, 127.0, 14.0)"}, - "name": "ranges", - "orientation": "v", - "type": "bar", - "width": 2, - "x": [0], - "xaxis": "x4", - "y": [1400], - "yaxis": "y4", - }, - { - "base": 0, - "hoverinfo": "y", - "marker": {"color": "rgb(44.0, 160.0, 44.0)"}, - "name": "measures", - "orientation": "v", - "type": "bar", - "width": 0.4, - "x": [0.5], - "xaxis": "x4", - "y": [1650], - "yaxis": "y4", - }, - { - "base": 0, - "hoverinfo": "y", - "marker": {"color": "rgb(255.0, 127.0, 14.0)"}, - "name": "measures", - "orientation": "v", - "type": "bar", - "width": 0.4, - "x": [0.5], - "xaxis": "x4", - "y": [1000], - "yaxis": "y4", - }, - { - "hoverinfo": "y", - "marker": { - "color": "rgb(0, 0, 0)", - "size": 30, - "symbol": "hourglass", - }, - "name": "markers", - "type": "scatter", - "x": [0.5], - "xaxis": "x4", - "y": [2100], - "yaxis": "y4", - }, - { - "base": 0, - "hoverinfo": "y", - "marker": {"color": "rgb(44.0, 160.0, 44.0)"}, - "name": "ranges", - "orientation": "v", - "type": "bar", - "width": 2, - "x": [0], - "xaxis": "x5", - "y": [5], - "yaxis": "y5", - }, - { - "base": 0, - "hoverinfo": "y", - "marker": {"color": "rgb(149.5, 143.5, 29.0)"}, - "name": "ranges", - "orientation": "v", - "type": "bar", - "width": 2, - "x": [0], - "xaxis": "x5", - "y": [4.25], - "yaxis": "y5", - }, - { - "base": 0, - "hoverinfo": "y", - "marker": {"color": "rgb(255.0, 127.0, 14.0)"}, - "name": "ranges", - "orientation": "v", - "type": "bar", - "width": 2, - "x": [0], - "xaxis": "x5", - "y": [3.5], - "yaxis": "y5", - }, - { - "base": 0, - "hoverinfo": "y", - "marker": {"color": "rgb(44.0, 160.0, 44.0)"}, - "name": "measures", - "orientation": "v", - "type": "bar", - "width": 0.4, - "x": [0.5], - "xaxis": "x5", - "y": [4.7], - "yaxis": "y5", - }, - { - "base": 0, - "hoverinfo": "y", - "marker": {"color": "rgb(255.0, 127.0, 14.0)"}, - "name": "measures", - "orientation": "v", - "type": "bar", - "width": 0.4, - "x": [0.5], - "xaxis": "x5", - "y": [3.2], - "yaxis": "y5", - }, - { - "hoverinfo": "y", - "marker": { - "color": "rgb(0, 0, 0)", - "size": 30, - "symbol": "hourglass", - }, - "name": "markers", - "type": "scatter", - "x": [0.5], - "xaxis": "x5", - "y": [4.4], - "yaxis": "y5", - }, - ], - "layout": { - "annotations": [ - { - "font": {"color": "#0f0f0f", "size": 13}, - "showarrow": False, - "text": "Revenue", - "textangle": 0, - "x": 0.019999999999999997, - "xanchor": "center", - "xref": "paper", - "y": 1.03, - "yanchor": "middle", - "yref": "paper", - }, - { - "font": {"color": "#0f0f0f", "size": 13}, - "showarrow": False, - "text": "Profit", - "textangle": 0, - "x": 0.26, - "xanchor": "center", - "xref": "paper", - "y": 1.03, - "yanchor": "middle", - "yref": "paper", - }, - { - "font": {"color": "#0f0f0f", "size": 13}, - "showarrow": False, - "text": "Order Size", - "textangle": 0, - "x": 0.5, - "xanchor": "center", - "xref": "paper", - "y": 1.03, - "yanchor": "middle", - "yref": "paper", - }, - { - "font": {"color": "#0f0f0f", "size": 13}, - "showarrow": False, - "text": "New Customers", - "textangle": 0, - "x": 0.74, - "xanchor": "center", - "xref": "paper", - "y": 1.03, - "yanchor": "middle", - "yref": "paper", - }, - { - "font": {"color": "#0f0f0f", "size": 13}, - "showarrow": False, - "text": "Satisfaction", - "textangle": 0, - "x": 0.98, - "xanchor": "center", - "xref": "paper", - "y": 1.03, - "yanchor": "middle", - "yref": "paper", - }, - ], - "barmode": "stack", - "height": 600, - "margin": {"l": 80}, - "shapes": [], - "showlegend": False, - "title": "new title", - "width": 1000, - "xaxis1": { - "anchor": "y", - "domain": [0.0, 0.039999999999999994], - "range": [0, 1], - "showgrid": False, - "showticklabels": False, - "zeroline": False, - }, - "xaxis2": { - "anchor": "y2", - "domain": [0.24, 0.27999999999999997], - "range": [0, 1], - "showgrid": False, - "showticklabels": False, - "zeroline": False, - }, - "xaxis3": { - "anchor": "y3", - "domain": [0.48, 0.52], - "range": [0, 1], - "showgrid": False, - "showticklabels": False, - "zeroline": False, - }, - "xaxis4": { - "anchor": "y4", - "domain": [0.72, 0.76], - "range": [0, 1], - "showgrid": False, - "showticklabels": False, - "zeroline": False, - }, - "xaxis5": { - "anchor": "y5", - "domain": [0.96, 1.0], - "range": [0, 1], - "showgrid": False, - "showticklabels": False, - "zeroline": False, - }, - "yaxis1": { - "anchor": "x", - "domain": [0.0, 1.0], - "showgrid": False, - "tickwidth": 1, - "zeroline": False, - }, - "yaxis2": { - "anchor": "x2", - "domain": [0.0, 1.0], - "showgrid": False, - "tickwidth": 1, - "zeroline": False, - }, - "yaxis3": { - "anchor": "x3", - "domain": [0.0, 1.0], - "showgrid": False, - "tickwidth": 1, - "zeroline": False, - }, - "yaxis4": { - "anchor": "x4", - "domain": [0.0, 1.0], - "showgrid": False, - "tickwidth": 1, - "zeroline": False, - }, - "yaxis5": { - "anchor": "x5", - "domain": [0.0, 1.0], - "showgrid": False, - "tickwidth": 1, - "zeroline": False, - }, - }, - } - - for i in range(len(fig["data"])): - self.assert_fig_equal(fig["data"][i], exp_fig["data"][i]) - - -class TestChoropleth(NumpyTestUtilsMixin, TestCaseNoTemplate): - # run tests if required packages are installed - if shapely and shapefile and gp: - - def test_fips_values_same_length(self): - pattern = "fips and values must be the same length" - self.assertRaisesRegex( - PlotlyError, - pattern, - ff.create_choropleth, - fips=[1001], - values=[4004, 40004], - ) - - def test_correct_order_param(self): - pattern = ( - "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" - ) - - self.assertRaisesRegex( - PlotlyError, - pattern, - ff.create_choropleth, - fips=[1], - values=[1], - order=[1, 1, 1], - ) - - def test_colorscale_and_levels_same_length(self): - self.assertRaises( - PlotlyError, - ff.create_choropleth, - fips=[1001, 1003, 1005], - values=[5, 2, 1], - colorscale=["rgb(0,0,0)"], - ) - - def test_scope_is_not_list(self): - pattern = "'scope' must be a list/tuple/sequence" - - self.assertRaisesRegex( - PlotlyError, - pattern, - ff.create_choropleth, - fips=[1001, 1003], - values=[5, 2], - scope="foo", - ) - - class TestQuiver(TestCaseNoTemplate): def test_scaleratio_param(self): x, y = np.meshgrid(np.arange(0.5, 3.5, 0.5), np.arange(0.5, 4.5, 0.5)) diff --git a/tests/test_optional/test_figure_factory/test_validate_gantt.py b/tests/test_optional/test_figure_factory/test_validate_gantt.py deleted file mode 100644 index 472a0669df2..00000000000 --- a/tests/test_optional/test_figure_factory/test_validate_gantt.py +++ /dev/null @@ -1,95 +0,0 @@ -import pytest - -from plotly import exceptions, optional_imports -from plotly.figure_factory._gantt import validate_gantt - -pd = optional_imports.get_module("pandas") - - -@pytest.mark.parametrize("input_type", ["list", "dataframe"]) -def test_valid_with_extra_keys(input_type): - """Test that extra keys beyond required ones are preserved.""" - data = [ - {"Task": "A", "Start": "2020-01-01", "Finish": "2020-01-02", "Resource": "X"}, - {"Task": "B", "Start": "2020-01-03", "Finish": "2020-01-04", "Resource": "Y"}, - ] - if input_type == "dataframe": - input_data = pd.DataFrame(data) - result = validate_gantt(input_data) - assert isinstance(result, list) - assert set(result[0].keys()) == set(input_data.columns) - else: - input_data = data - result = validate_gantt(input_data) - assert result is input_data - - assert len(result) == 2 - assert all("Resource" in row for row in result) - assert set(result[0].keys()) == set(["Task", "Start", "Finish", "Resource"]) - assert result[0]["Task"] == "A" - assert result[1]["Finish"] == "2020-01-04" - - -def test_missing_required_key_in_dataframe(): - df = pd.DataFrame( - [ - {"Task": "A", "Start": "2020-01-01"}, # Missing "Finish" - ] - ) - with pytest.raises(exceptions.PlotlyError): - validate_gantt(df) - - -def test_empty_list(): - with pytest.raises(exceptions.PlotlyError): - validate_gantt([]) - - -def test_input_is_not_list_or_dataframe(): - with pytest.raises(exceptions.PlotlyError): - validate_gantt("Not a list or DataFrame") - - -def test_dataframe_with_no_rows(): - df = pd.DataFrame(columns=["Task", "Start", "Finish"]) - result = validate_gantt(df) - assert isinstance(result, list) - assert result == [] - - -def test_list_with_dict_missing_all_keys(): - input_data = [{"Resource": "X"}] - # Should NOT raise: list input is not validated for keys - result = validate_gantt(input_data) - assert result is input_data - - -def test_large_list_with_non_dict_first_element(): - input_data = [ - "Not a dict", - *[ - { - "Task": f"Task{i}", - "Start": f"2020-01-{i % 30 + 1:02d}", - "Finish": f"2020-02-{i % 28 + 1:02d}", - } - for i in range(999) - ], - ] - with pytest.raises(exceptions.PlotlyError): - validate_gantt(input_data) - - -def test_dataframe_column_order_and_index(): - df = pd.DataFrame( - [ - {"Finish": "2023-01-02", "Start": "2023-01-01", "Task": "A"}, - {"Finish": "2023-01-03", "Start": "2023-01-02", "Task": "B"}, - ], - index=["x", "y"], - ) - result = validate_gantt(df) - assert len(result) == 2 - # Ensure values preserved regardless of order/index - assert result[0]["Task"] == "A" - assert set(result[0].keys()) == set(["Task", "Start", "Finish"]) diff --git a/tests/test_optional/test_tools/test_figure_factory.py b/tests/test_optional/test_tools/test_figure_factory.py index 209ae438235..8e2b8cf5878 100644 --- a/tests/test_optional/test_tools/test_figure_factory.py +++ b/tests/test_optional/test_tools/test_figure_factory.py @@ -1,6 +1,5 @@ import math -import datetime import plotly.figure_factory as ff from plotly.exceptions import PlotlyError @@ -111,1075 +110,6 @@ def test_more_kwargs(self): self.assert_fig_equal(quiver["layout"], expected_quiver["layout"]) -class TestFinanceCharts(TestCaseNoTemplate, NumpyTestUtilsMixin): - def test_unequal_ohlc_length(self): - # check: PlotlyError if open, high, low, close are not the same length - # for TraceFactory.create_ohlc and TraceFactory.create_candlestick - - kwargs = { - "open": [1], - "high": [1, 3], - "low": [1, 2], - "close": [1, 2], - "direction": ["increasing"], - } - self.assertRaises(PlotlyError, ff.create_ohlc, **kwargs) - self.assertRaises(PlotlyError, ff.create_candlestick, **kwargs) - - kwargs = { - "open": [1, 2], - "high": [1, 2, 3], - "low": [1, 2], - "close": [1, 2], - "direction": ["decreasing"], - } - self.assertRaises(PlotlyError, ff.create_ohlc, **kwargs) - self.assertRaises(PlotlyError, ff.create_candlestick, **kwargs) - - kwargs = {"open": [1, 2], "high": [2, 3], "low": [0], "close": [1, 3]} - self.assertRaises(PlotlyError, ff.create_ohlc, **kwargs) - self.assertRaises(PlotlyError, ff.create_candlestick, **kwargs) - - kwargs = {"open": [1, 2], "high": [2, 3], "low": [1, 2], "close": [1]} - self.assertRaises(PlotlyError, ff.create_ohlc, **kwargs) - self.assertRaises(PlotlyError, ff.create_candlestick, **kwargs) - - def test_direction_arg(self): - # check: PlotlyError if direction is not defined as "increasing" or - # "decreasing" for TraceFactory.create_ohlc and - # TraceFactory.create_candlestick - - kwargs = { - "open": [1, 4], - "high": [1, 5], - "low": [1, 2], - "close": [1, 2], - "direction": ["inc"], - } - self.assertRaisesRegex( - PlotlyError, - "direction must be defined as 'increasing', 'decreasing', or 'both'", - ff.create_ohlc, - **kwargs, - ) - self.assertRaisesRegex( - PlotlyError, - "direction must be defined as 'increasing', 'decreasing', or 'both'", - ff.create_candlestick, - **kwargs, - ) - - kwargs = { - "open": [1, 2], - "high": [1, 3], - "low": [1, 2], - "close": [1, 2], - "direction": ["d"], - } - self.assertRaisesRegex( - PlotlyError, - "direction must be defined as 'increasing', 'decreasing', or 'both'", - ff.create_ohlc, - **kwargs, - ) - self.assertRaisesRegex( - PlotlyError, - "direction must be defined as 'increasing', 'decreasing', or 'both'", - ff.create_candlestick, - **kwargs, - ) - - def test_high_highest_value(self): - # check: PlotlyError if the "high" value is less than the corresponding - # open, low, or close value because if the "high" value is not the - # highest (or equal) then the data may have been entered incorrectly. - - kwargs = {"open": [2, 3], "high": [4, 2], "low": [1, 1], "close": [1, 2]} - self.assertRaisesRegex( - PlotlyError, - "Oops! Looks like some of " - "your high values are less " - "the corresponding open, " - "low, or close values. " - "Double check that your data " - "is entered in O-H-L-C order", - ff.create_ohlc, - **kwargs, - ) - self.assertRaisesRegex( - PlotlyError, - "Oops! Looks like some of " - "your high values are less " - "the corresponding open, " - "low, or close values. " - "Double check that your data " - "is entered in O-H-L-C order", - ff.create_candlestick, - **kwargs, - ) - - def test_low_lowest_value(self): - # check: PlotlyError if the "low" value is greater than the - # corresponding open, high, or close value because if the "low" value - # is not the lowest (or equal) then the data may have been entered - # incorrectly. - - # create_ohlc_increase - kwargs = {"open": [2, 3], "high": [4, 6], "low": [3, 1], "close": [1, 2]} - self.assertRaisesRegex( - PlotlyError, - "Oops! Looks like some of " - "your low values are greater " - "than the corresponding high" - ", open, or close values. " - "Double check that your data " - "is entered in O-H-L-C order", - ff.create_ohlc, - **kwargs, - ) - self.assertRaisesRegex( - PlotlyError, - "Oops! Looks like some of " - "your low values are greater " - "than the corresponding high" - ", open, or close values. " - "Double check that your data " - "is entered in O-H-L-C order", - ff.create_candlestick, - **kwargs, - ) - - def test_one_ohlc(self): - # This should create one "increase" (i.e. close > open) ohlc stick - - ohlc = ff.create_ohlc(open=[33.0], high=[33.2], low=[32.7], close=[33.1]) - - expected_ohlc = { - "layout": {"hovermode": "closest", "xaxis": {"zeroline": False}}, - "data": [ - { - "y": [33.0, 33.0, 33.2, 32.7, 33.1, 33.1, None], - "line": {"width": 1, "color": "#3D9970"}, - "showlegend": False, - "name": "Increasing", - "text": ["Open", "Open", "High", "Low", "Close", "Close", ""], - "mode": "lines", - "type": "scatter", - "x": [-0.2, 0, 0, 0, 0, 0.2, None], - }, - { - "y": [], - "line": {"width": 1, "color": "#FF4136"}, - "showlegend": False, - "name": "Decreasing", - "text": (), - "mode": "lines", - "type": "scatter", - "x": [], - }, - ], - } - - self.assert_fig_equal( - ohlc["data"][0], expected_ohlc["data"][0], ignore=["uid", "text"] - ) - - self.assert_fig_equal( - ohlc["data"][1], expected_ohlc["data"][1], ignore=["uid", "text"] - ) - - self.assert_fig_equal(ohlc["layout"], expected_ohlc["layout"]) - - def test_one_ohlc_increase(self): - # This should create one "increase" (i.e. close > open) ohlc stick - - ohlc_incr = ff.create_ohlc( - open=[33.0], high=[33.2], low=[32.7], close=[33.1], direction="increasing" - ) - - expected_ohlc_incr = { - "data": [ - { - "line": {"color": "#3D9970", "width": 1}, - "mode": "lines", - "name": "Increasing", - "showlegend": False, - "text": ["Open", "Open", "High", "Low", "Close", "Close", ""], - "type": "scatter", - "x": [-0.2, 0, 0, 0, 0, 0.2, None], - "y": [33.0, 33.0, 33.2, 32.7, 33.1, 33.1, None], - } - ], - "layout": {"hovermode": "closest", "xaxis": {"zeroline": False}}, - } - self.assert_fig_equal(ohlc_incr["data"][0], expected_ohlc_incr["data"][0]) - self.assert_fig_equal(ohlc_incr["layout"], expected_ohlc_incr["layout"]) - - def test_one_ohlc_decrease(self): - # This should create one "increase" (i.e. close > open) ohlc stick - - ohlc_decr = ff.create_ohlc( - open=[33.0], high=[33.2], low=[30.7], close=[31.1], direction="decreasing" - ) - - expected_ohlc_decr = { - "data": [ - { - "line": {"color": "#FF4136", "width": 1}, - "mode": "lines", - "name": "Decreasing", - "showlegend": False, - "text": ["Open", "Open", "High", "Low", "Close", "Close", ""], - "type": "scatter", - "x": [-0.2, 0, 0, 0, 0, 0.2, None], - "y": [33.0, 33.0, 33.2, 30.7, 31.1, 31.1, None], - } - ], - "layout": {"hovermode": "closest", "xaxis": {"zeroline": False}}, - } - - self.assert_fig_equal(ohlc_decr["data"][0], expected_ohlc_decr["data"][0]) - self.assert_fig_equal(ohlc_decr["layout"], expected_ohlc_decr["layout"]) - - # TO-DO: put expected fig in a different file and then call to compare - def test_one_candlestick(self): - # This should create one "increase" (i.e. close > open) candlestick - - can_inc = ff.create_candlestick( - open=[33.0], high=[33.2], low=[32.7], close=[33.1] - ) - - exp_can_inc = { - "data": [ - { - "boxpoints": False, - "fillcolor": "#3D9970", - "line": {"color": "#3D9970"}, - "name": "Increasing", - "showlegend": False, - "type": "box", - "whiskerwidth": 0, - "x": [0, 0, 0, 0, 0, 0], - "y": [32.7, 33.0, 33.1, 33.1, 33.1, 33.2], - }, - { - "boxpoints": False, - "fillcolor": "#ff4136", - "line": {"color": "#ff4136"}, - "name": "Decreasing", - "showlegend": False, - "type": "box", - "whiskerwidth": 0, - "x": [], - "y": [], - }, - ], - "layout": {}, - } - - self.assert_fig_equal(can_inc["data"][0], exp_can_inc["data"][0]) - self.assert_fig_equal(can_inc["layout"], exp_can_inc["layout"]) - - def test_datetime_ohlc(self): - # Check expected outcome for ohlc chart with datetime xaxis - - high_data = [34.20, 34.37, 33.62, 34.25, 35.18, 33.25, 35.37, 34.62] - low_data = [31.70, 30.75, 32.87, 31.62, 30.81, 32.75, 32.75, 32.87] - close_data = [34.10, 31.93, 33.37, 33.18, 31.18, 33.10, 32.93, 33.70] - open_data = [33.01, 33.31, 33.50, 32.06, 34.12, 33.05, 33.31, 33.50] - - x = [ - datetime.datetime(year=2013, month=3, day=4), - datetime.datetime(year=2013, month=6, day=5), - datetime.datetime(year=2013, month=9, day=6), - datetime.datetime(year=2013, month=12, day=4), - datetime.datetime(year=2014, month=3, day=5), - datetime.datetime(year=2014, month=6, day=6), - datetime.datetime(year=2014, month=9, day=4), - datetime.datetime(year=2014, month=12, day=5), - ] - - ohlc_d = ff.create_ohlc(open_data, high_data, low_data, close_data, dates=x) - - ex_ohlc_d = { - "data": [ - { - "line": {"color": "#3D9970", "width": 1}, - "mode": "lines", - "name": "Increasing", - "showlegend": False, - "text": [ - "Open", - "Open", - "High", - "Low", - "Close", - "Close", - "", - "Open", - "Open", - "High", - "Low", - "Close", - "Close", - "", - "Open", - "Open", - "High", - "Low", - "Close", - "Close", - "", - "Open", - "Open", - "High", - "Low", - "Close", - "Close", - "", - ], - "type": "scatter", - "x": [ - datetime.datetime(2013, 2, 14, 4, 48), - datetime.datetime(2013, 3, 4, 0, 0), - datetime.datetime(2013, 3, 4, 0, 0), - datetime.datetime(2013, 3, 4, 0, 0), - datetime.datetime(2013, 3, 4, 0, 0), - datetime.datetime(2013, 3, 21, 19, 12), - None, - datetime.datetime(2013, 11, 16, 4, 48), - datetime.datetime(2013, 12, 4, 0, 0), - datetime.datetime(2013, 12, 4, 0, 0), - datetime.datetime(2013, 12, 4, 0, 0), - datetime.datetime(2013, 12, 4, 0, 0), - datetime.datetime(2013, 12, 21, 19, 12), - None, - datetime.datetime(2014, 5, 19, 4, 48), - datetime.datetime(2014, 6, 6, 0, 0), - datetime.datetime(2014, 6, 6, 0, 0), - datetime.datetime(2014, 6, 6, 0, 0), - datetime.datetime(2014, 6, 6, 0, 0), - datetime.datetime(2014, 6, 23, 19, 12), - None, - datetime.datetime(2014, 11, 17, 4, 48), - datetime.datetime(2014, 12, 5, 0, 0), - datetime.datetime(2014, 12, 5, 0, 0), - datetime.datetime(2014, 12, 5, 0, 0), - datetime.datetime(2014, 12, 5, 0, 0), - datetime.datetime(2014, 12, 22, 19, 12), - None, - ], - "y": [ - 33.01, - 33.01, - 34.2, - 31.7, - 34.1, - 34.1, - None, - 32.06, - 32.06, - 34.25, - 31.62, - 33.18, - 33.18, - None, - 33.05, - 33.05, - 33.25, - 32.75, - 33.1, - 33.1, - None, - 33.5, - 33.5, - 34.62, - 32.87, - 33.7, - 33.7, - None, - ], - }, - { - "line": {"color": "#FF4136", "width": 1}, - "mode": "lines", - "name": "Decreasing", - "showlegend": False, - "text": [ - "Open", - "Open", - "High", - "Low", - "Close", - "Close", - "", - "Open", - "Open", - "High", - "Low", - "Close", - "Close", - "", - "Open", - "Open", - "High", - "Low", - "Close", - "Close", - "", - "Open", - "Open", - "High", - "Low", - "Close", - "Close", - "", - ], - "type": "scatter", - "x": [ - datetime.datetime(2013, 5, 18, 4, 48), - datetime.datetime(2013, 6, 5, 0, 0), - datetime.datetime(2013, 6, 5, 0, 0), - datetime.datetime(2013, 6, 5, 0, 0), - datetime.datetime(2013, 6, 5, 0, 0), - datetime.datetime(2013, 6, 22, 19, 12), - None, - datetime.datetime(2013, 8, 19, 4, 48), - datetime.datetime(2013, 9, 6, 0, 0), - datetime.datetime(2013, 9, 6, 0, 0), - datetime.datetime(2013, 9, 6, 0, 0), - datetime.datetime(2013, 9, 6, 0, 0), - datetime.datetime(2013, 9, 23, 19, 12), - None, - datetime.datetime(2014, 2, 15, 4, 48), - datetime.datetime(2014, 3, 5, 0, 0), - datetime.datetime(2014, 3, 5, 0, 0), - datetime.datetime(2014, 3, 5, 0, 0), - datetime.datetime(2014, 3, 5, 0, 0), - datetime.datetime(2014, 3, 22, 19, 12), - None, - datetime.datetime(2014, 8, 17, 4, 48), - datetime.datetime(2014, 9, 4, 0, 0), - datetime.datetime(2014, 9, 4, 0, 0), - datetime.datetime(2014, 9, 4, 0, 0), - datetime.datetime(2014, 9, 4, 0, 0), - datetime.datetime(2014, 9, 21, 19, 12), - None, - ], - "y": [ - 33.31, - 33.31, - 34.37, - 30.75, - 31.93, - 31.93, - None, - 33.5, - 33.5, - 33.62, - 32.87, - 33.37, - 33.37, - None, - 34.12, - 34.12, - 35.18, - 30.81, - 31.18, - 31.18, - None, - 33.31, - 33.31, - 35.37, - 32.75, - 32.93, - 32.93, - None, - ], - }, - ], - "layout": {"hovermode": "closest", "xaxis": {"zeroline": False}}, - } - self.assert_fig_equal(ohlc_d["data"][0], ex_ohlc_d["data"][0]) - self.assert_fig_equal(ohlc_d["data"][1], ex_ohlc_d["data"][1]) - self.assert_fig_equal(ohlc_d["layout"], ex_ohlc_d["layout"]) - - def test_datetime_candlestick(self): - # Check expected outcome for candlestick chart with datetime xaxis - - high_data = [34.20, 34.37, 33.62, 34.25, 35.18, 33.25, 35.37, 34.62] - low_data = [31.70, 30.75, 32.87, 31.62, 30.81, 32.75, 32.75, 32.87] - close_data = [34.10, 31.93, 33.37, 33.18, 31.18, 33.10, 32.93, 33.70] - open_data = [33.01, 33.31, 33.50, 32.06, 34.12, 33.05, 33.31, 33.50] - - x = [ - datetime.datetime(year=2013, month=3, day=4), - datetime.datetime(year=2013, month=6, day=5), - datetime.datetime(year=2013, month=9, day=6), - datetime.datetime(year=2013, month=12, day=4), - datetime.datetime(year=2014, month=3, day=5), - datetime.datetime(year=2014, month=6, day=6), - datetime.datetime(year=2014, month=9, day=4), - datetime.datetime(year=2014, month=12, day=5), - ] - - candle = ff.create_candlestick( - open_data, high_data, low_data, close_data, dates=x - ) - exp_candle = { - "data": [ - { - "boxpoints": False, - "fillcolor": "#3D9970", - "line": {"color": "#3D9970"}, - "name": "Increasing", - "showlegend": False, - "type": "box", - "whiskerwidth": 0, - "x": [ - datetime.datetime(2013, 3, 4, 0, 0), - datetime.datetime(2013, 3, 4, 0, 0), - datetime.datetime(2013, 3, 4, 0, 0), - datetime.datetime(2013, 3, 4, 0, 0), - datetime.datetime(2013, 3, 4, 0, 0), - datetime.datetime(2013, 3, 4, 0, 0), - datetime.datetime(2013, 12, 4, 0, 0), - datetime.datetime(2013, 12, 4, 0, 0), - datetime.datetime(2013, 12, 4, 0, 0), - datetime.datetime(2013, 12, 4, 0, 0), - datetime.datetime(2013, 12, 4, 0, 0), - datetime.datetime(2013, 12, 4, 0, 0), - datetime.datetime(2014, 6, 6, 0, 0), - datetime.datetime(2014, 6, 6, 0, 0), - datetime.datetime(2014, 6, 6, 0, 0), - datetime.datetime(2014, 6, 6, 0, 0), - datetime.datetime(2014, 6, 6, 0, 0), - datetime.datetime(2014, 6, 6, 0, 0), - datetime.datetime(2014, 12, 5, 0, 0), - datetime.datetime(2014, 12, 5, 0, 0), - datetime.datetime(2014, 12, 5, 0, 0), - datetime.datetime(2014, 12, 5, 0, 0), - datetime.datetime(2014, 12, 5, 0, 0), - datetime.datetime(2014, 12, 5, 0, 0), - ], - "y": [ - 31.7, - 33.01, - 34.1, - 34.1, - 34.1, - 34.2, - 31.62, - 32.06, - 33.18, - 33.18, - 33.18, - 34.25, - 32.75, - 33.05, - 33.1, - 33.1, - 33.1, - 33.25, - 32.87, - 33.5, - 33.7, - 33.7, - 33.7, - 34.62, - ], - }, - { - "boxpoints": False, - "fillcolor": "#FF4136", - "line": {"color": "#FF4136"}, - "name": "Decreasing", - "showlegend": False, - "type": "box", - "whiskerwidth": 0, - "x": [ - datetime.datetime(2013, 6, 5, 0, 0), - datetime.datetime(2013, 6, 5, 0, 0), - datetime.datetime(2013, 6, 5, 0, 0), - datetime.datetime(2013, 6, 5, 0, 0), - datetime.datetime(2013, 6, 5, 0, 0), - datetime.datetime(2013, 6, 5, 0, 0), - datetime.datetime(2013, 9, 6, 0, 0), - datetime.datetime(2013, 9, 6, 0, 0), - datetime.datetime(2013, 9, 6, 0, 0), - datetime.datetime(2013, 9, 6, 0, 0), - datetime.datetime(2013, 9, 6, 0, 0), - datetime.datetime(2013, 9, 6, 0, 0), - datetime.datetime(2014, 3, 5, 0, 0), - datetime.datetime(2014, 3, 5, 0, 0), - datetime.datetime(2014, 3, 5, 0, 0), - datetime.datetime(2014, 3, 5, 0, 0), - datetime.datetime(2014, 3, 5, 0, 0), - datetime.datetime(2014, 3, 5, 0, 0), - datetime.datetime(2014, 9, 4, 0, 0), - datetime.datetime(2014, 9, 4, 0, 0), - datetime.datetime(2014, 9, 4, 0, 0), - datetime.datetime(2014, 9, 4, 0, 0), - datetime.datetime(2014, 9, 4, 0, 0), - datetime.datetime(2014, 9, 4, 0, 0), - ], - "y": [ - 30.75, - 33.31, - 31.93, - 31.93, - 31.93, - 34.37, - 32.87, - 33.5, - 33.37, - 33.37, - 33.37, - 33.62, - 30.81, - 34.12, - 31.18, - 31.18, - 31.18, - 35.18, - 32.75, - 33.31, - 32.93, - 32.93, - 32.93, - 35.37, - ], - }, - ], - "layout": {}, - } - - self.assert_fig_equal(candle["data"][0], exp_candle["data"][0]) - self.assert_fig_equal(candle["data"][1], exp_candle["data"][1]) - self.assert_fig_equal(candle["layout"], exp_candle["layout"]) - - -class TestAnnotatedHeatmap(TestCaseNoTemplate, NumpyTestUtilsMixin): - def test_unequal_z_text_size(self): - # check: PlotlyError if z and text are not the same dimensions - - kwargs = {"z": [[1, 2], [1, 2]], "annotation_text": [[1, 2, 3], [1]]} - self.assertRaises(PlotlyError, ff.create_annotated_heatmap, **kwargs) - - kwargs = {"z": [[1], [1]], "annotation_text": [[1], [1], [1]]} - self.assertRaises(PlotlyError, ff.create_annotated_heatmap, **kwargs) - - def test_incorrect_x_size(self): - # check: PlotlyError if x is the wrong size - - kwargs = {"z": [[1, 2], [1, 2]], "x": ["A"]} - self.assertRaises(PlotlyError, ff.create_annotated_heatmap, **kwargs) - - def test_incorrect_y_size(self): - # check: PlotlyError if y is the wrong size - - kwargs = {"z": [[1, 2], [1, 2]], "y": [1, 2, 3]} - self.assertRaises(PlotlyError, ff.create_annotated_heatmap, **kwargs) - - def test_simple_annotated_heatmap(self): - # we should be able to create a heatmap with annotated values with a - # logical text color - - z = [[1, 0, 0.5], [0.25, 0.75, 0.45]] - a_heat = ff.create_annotated_heatmap(z) - expected_a_heat = { - "data": [ - { - "colorscale": [ - [0.0, "#0d0887"], - [0.1111111111111111, "#46039f"], - [0.2222222222222222, "#7201a8"], - [0.3333333333333333, "#9c179e"], - [0.4444444444444444, "#bd3786"], - [0.5555555555555556, "#d8576b"], - [0.6666666666666666, "#ed7953"], - [0.7777777777777778, "#fb9f3a"], - [0.8888888888888888, "#fdca26"], - [1.0, "#f0f921"], - ], - "showscale": False, - "reversescale": False, - "type": "heatmap", - "z": [[1, 0, 0.5], [0.25, 0.75, 0.45]], - } - ], - "layout": { - "annotations": [ - { - "font": {"color": "#000000"}, - "showarrow": False, - "text": "1", - "x": 0, - "xref": "x", - "y": 0, - "yref": "y", - }, - { - "font": {"color": "#FFFFFF"}, - "showarrow": False, - "text": "0", - "x": 1, - "xref": "x", - "y": 0, - "yref": "y", - }, - { - "font": {"color": "#000000"}, - "showarrow": False, - "text": "0.5", - "x": 2, - "xref": "x", - "y": 0, - "yref": "y", - }, - { - "font": {"color": "#FFFFFF"}, - "showarrow": False, - "text": "0.25", - "x": 0, - "xref": "x", - "y": 1, - "yref": "y", - }, - { - "font": {"color": "#000000"}, - "showarrow": False, - "text": "0.75", - "x": 1, - "xref": "x", - "y": 1, - "yref": "y", - }, - { - "font": {"color": "#FFFFFF"}, - "showarrow": False, - "text": "0.45", - "x": 2, - "xref": "x", - "y": 1, - "yref": "y", - }, - ], - "xaxis": { - "gridcolor": "rgb(0, 0, 0)", - "showticklabels": False, - "side": "top", - "ticks": "", - }, - "yaxis": {"showticklabels": False, "ticks": "", "ticksuffix": " "}, - }, - } - - self.assert_fig_equal(a_heat["data"][0], expected_a_heat["data"][0]) - - self.assert_fig_equal(a_heat["layout"], expected_a_heat["layout"]) - - def test_annotated_heatmap_kwargs(self): - # we should be able to create an annotated heatmap with x and y axes - # labels, a defined colorscale, and supplied text. - - z = [[1, 0], [0.25, 0.75], [0.45, 0.5]] - text = [["first", "second"], ["third", "fourth"], ["fifth", "sixth"]] - a = ff.create_annotated_heatmap( - z, - x=["A", "B"], - y=["One", "Two", "Three"], - annotation_text=text, - colorscale=[[0, "rgb(255,255,255)"], [1, "#e6005a"]], - ) - expected_a = { - "data": [ - { - "colorscale": [[0, "rgb(255,255,255)"], [1, "#e6005a"]], - "showscale": False, - "reversescale": False, - "type": "heatmap", - "x": ["A", "B"], - "y": ["One", "Two", "Three"], - "z": [[1, 0], [0.25, 0.75], [0.45, 0.5]], - } - ], - "layout": { - "annotations": [ - { - "font": {"color": "#FFFFFF"}, - "showarrow": False, - "text": "first", - "x": "A", - "xref": "x", - "y": "One", - "yref": "y", - }, - { - "font": {"color": "#000000"}, - "showarrow": False, - "text": "second", - "x": "B", - "xref": "x", - "y": "One", - "yref": "y", - }, - { - "font": {"color": "#000000"}, - "showarrow": False, - "text": "third", - "x": "A", - "xref": "x", - "y": "Two", - "yref": "y", - }, - { - "font": {"color": "#FFFFFF"}, - "showarrow": False, - "text": "fourth", - "x": "B", - "xref": "x", - "y": "Two", - "yref": "y", - }, - { - "font": {"color": "#000000"}, - "showarrow": False, - "text": "fifth", - "x": "A", - "xref": "x", - "y": "Three", - "yref": "y", - }, - { - "font": {"color": "#FFFFFF"}, - "showarrow": False, - "text": "sixth", - "x": "B", - "xref": "x", - "y": "Three", - "yref": "y", - }, - ], - "xaxis": { - "dtick": 1, - "gridcolor": "rgb(0, 0, 0)", - "side": "top", - "ticks": "", - }, - "yaxis": {"dtick": 1, "ticks": "", "ticksuffix": " "}, - }, - } - self.assert_fig_equal(a["data"][0], expected_a["data"][0]) - - self.assert_fig_equal(a["layout"], expected_a["layout"]) - - def test_annotated_heatmap_reversescale(self): - # we should be able to create an annotated heatmap with x and y axes - # labels, a defined colorscale, and supplied text. - - z = [[1, 0], [0.25, 0.75], [0.45, 0.5]] - text = [["first", "second"], ["third", "fourth"], ["fifth", "sixth"]] - a = ff.create_annotated_heatmap( - z, - x=["A", "B"], - y=["One", "Two", "Three"], - annotation_text=text, - reversescale=True, - colorscale=[[0, "rgb(255,255,255)"], [1, "#e6005a"]], - ) - expected_a = { - "data": [ - { - "colorscale": [[0, "rgb(255,255,255)"], [1, "#e6005a"]], - "showscale": False, - "reversescale": True, - "type": "heatmap", - "x": ["A", "B"], - "y": ["One", "Two", "Three"], - "z": [[1, 0], [0.25, 0.75], [0.45, 0.5]], - } - ], - "layout": { - "annotations": [ - { - "font": {"color": "#000000"}, - "showarrow": False, - "text": "first", - "x": "A", - "xref": "x", - "y": "One", - "yref": "y", - }, - { - "font": {"color": "#FFFFFF"}, - "showarrow": False, - "text": "second", - "x": "B", - "xref": "x", - "y": "One", - "yref": "y", - }, - { - "font": {"color": "#FFFFFF"}, - "showarrow": False, - "text": "third", - "x": "A", - "xref": "x", - "y": "Two", - "yref": "y", - }, - { - "font": {"color": "#000000"}, - "showarrow": False, - "text": "fourth", - "x": "B", - "xref": "x", - "y": "Two", - "yref": "y", - }, - { - "font": {"color": "#FFFFFF"}, - "showarrow": False, - "text": "fifth", - "x": "A", - "xref": "x", - "y": "Three", - "yref": "y", - }, - { - "font": {"color": "#000000"}, - "showarrow": False, - "text": "sixth", - "x": "B", - "xref": "x", - "y": "Three", - "yref": "y", - }, - ], - "xaxis": { - "dtick": 1, - "gridcolor": "rgb(0, 0, 0)", - "side": "top", - "ticks": "", - }, - "yaxis": {"dtick": 1, "ticks": "", "ticksuffix": " "}, - }, - } - self.assert_fig_equal(a["data"][0], expected_a["data"][0]) - - self.assert_fig_equal(a["layout"], expected_a["layout"]) - - def test_bug_1300(self): - # https://github.com/plotly/plotly.py/issues/1300 - sub_z = [[0.1, 0.0, 0.0], [0.0, 1.0, 0.1]] - - # sub_z = sub_z.tolist() - - # Standard scale direction - fig = ff.create_annotated_heatmap( - sub_z, colorscale="Greens", showscale=True, reversescale=True - ) - - expected = graph_objs.Figure( - { - "data": [ - { - "colorscale": [ - [0.0, "rgb(247,252,245)"], - [0.125, "rgb(229,245,224)"], - [0.25, "rgb(199,233,192)"], - [0.375, "rgb(161,217,155)"], - [0.5, "rgb(116,196,118)"], - [0.625, "rgb(65,171,93)"], - [0.75, "rgb(35,139,69)"], - [0.875, "rgb(0,109,44)"], - [1.0, "rgb(0,68,27)"], - ], - "reversescale": True, - "showscale": True, - "type": "heatmap", - "z": [[0.1, 0.0, 0.0], [0.0, 1.0, 0.1]], - } - ], - "layout": { - "annotations": [ - { - "font": {"color": "#FFFFFF"}, - "showarrow": False, - "text": "0.1", - "x": 0, - "xref": "x", - "y": 0, - "yref": "y", - }, - { - "font": {"color": "#FFFFFF"}, - "showarrow": False, - "text": "0.0", - "x": 1, - "xref": "x", - "y": 0, - "yref": "y", - }, - { - "font": {"color": "#FFFFFF"}, - "showarrow": False, - "text": "0.0", - "x": 2, - "xref": "x", - "y": 0, - "yref": "y", - }, - { - "font": {"color": "#FFFFFF"}, - "showarrow": False, - "text": "0.0", - "x": 0, - "xref": "x", - "y": 1, - "yref": "y", - }, - { - "font": {"color": "#000000"}, - "showarrow": False, - "text": "1.0", - "x": 1, - "xref": "x", - "y": 1, - "yref": "y", - }, - { - "font": {"color": "#FFFFFF"}, - "showarrow": False, - "text": "0.1", - "x": 2, - "xref": "x", - "y": 1, - "yref": "y", - }, - ], - "xaxis": { - "gridcolor": "rgb(0, 0, 0)", - "showticklabels": False, - "side": "top", - "ticks": "", - }, - "yaxis": {"showticklabels": False, "ticks": "", "ticksuffix": " "}, - }, - } - ) - - # Remove uids - for trace in fig.data: - trace.update(uid=None) - for trace in expected.data: - trace.update(uid=None) - - # Perform comparison - self.assert_fig_equal(fig, expected) - - class TestTable(TestCaseNoTemplate, NumpyTestUtilsMixin): def test_fontcolor_input(self): # check: ValueError if fontcolor input is incorrect @@ -1528,688 +458,3 @@ def test_table_with_index(self): self.assert_fig_equal(index_table["layout"], exp_index_table["layout"]) -class TestGantt(TestCaseNoTemplate, NumpyTestUtilsMixin): - def test_validate_gantt(self): - # validate the basic gantt inputs - - df = [ - { - "Task": "Job A", - "Start": "2009-02-01", - "Finish": "2009-08-30", - "Complete": "a", - } - ] - - pattern2 = ( - "In order to use an indexing column and assign colors to " - "the values of the index, you must choose an actual " - "column name in the dataframe or key if a list of " - "dictionaries is being used." - ) - - self.assertRaisesRegex( - PlotlyError, pattern2, ff.create_gantt, df, index_col="foo" - ) - - df = "foo" - - pattern3 = "You must input either a dataframe or a list of dictionaries." - - self.assertRaisesRegex(PlotlyError, pattern3, ff.create_gantt, df) - - df = [] - - pattern4 = "Your list is empty. It must contain at least one dictionary." - - self.assertRaisesRegex(PlotlyError, pattern4, ff.create_gantt, df) - - df = ["foo"] - - pattern5 = "Your list must only include dictionaries." - - self.assertRaisesRegex(PlotlyError, pattern5, ff.create_gantt, df) - - def test_gantt_index(self): - # validate the index used for gantt - - df = [ - { - "Task": "Job A", - "Start": "2009-02-01", - "Finish": "2009-08-30", - "Complete": 50, - } - ] - - pattern = ( - "In order to use an indexing column and assign colors to " - "the values of the index, you must choose an actual " - "column name in the dataframe or key if a list of " - "dictionaries is being used." - ) - - self.assertRaisesRegex( - PlotlyError, pattern, ff.create_gantt, df, index_col="foo" - ) - - df = [ - { - "Task": "Job A", - "Start": "2009-02-01", - "Finish": "2009-08-30", - "Complete": "a", - }, - { - "Task": "Job A", - "Start": "2009-02-01", - "Finish": "2009-08-30", - "Complete": 50, - }, - ] - - pattern2 = ( - "Error in indexing column. Make sure all entries of each " - "column are all numbers or all strings." - ) - - self.assertRaisesRegex( - PlotlyError, pattern2, ff.create_gantt, df, index_col="Complete" - ) - - def test_gantt_validate_colors(self): - # validate the gantt colors variable - - df = [ - { - "Task": "Job A", - "Start": "2009-02-01", - "Finish": "2009-08-30", - "Complete": 75, - "Resource": "A", - }, - { - "Task": "Job B", - "Start": "2009-02-01", - "Finish": "2009-08-30", - "Complete": 50, - "Resource": "B", - }, - ] - - pattern = "Whoops! The elements in your rgb colors tuples cannot exceed 255.0." - - self.assertRaisesRegex( - PlotlyError, - pattern, - ff.create_gantt, - df, - index_col="Complete", - colors="rgb(300,1,1)", - ) - - self.assertRaises( - PlotlyError, ff.create_gantt, df, index_col="Complete", colors="foo" - ) - - pattern2 = "Whoops! The elements in your colors tuples cannot exceed 1.0." - - self.assertRaisesRegex( - PlotlyError, - pattern2, - ff.create_gantt, - df, - index_col="Complete", - colors=(2, 1, 1), - ) - - # verify that if colors is a dictionary, its keys span all the - # values in the index column - colors_dict = {75: "rgb(1, 2, 3)"} - - pattern3 = ( - "If you are using colors as a dictionary, all of its " - "keys must be all the values in the index column." - ) - - self.assertRaisesRegex( - PlotlyError, - pattern3, - ff.create_gantt, - df, - index_col="Complete", - colors=colors_dict, - ) - - # check: index is set if colors is a dictionary - colors_dict_good = {50: "rgb(1, 2, 3)", 75: "rgb(5, 10, 15)"} - - pattern4 = ( - "Error. You have set colors to a dictionary but have not " - "picked an index. An index is required if you are " - "assigning colors to particular values in a dictionary." - ) - - self.assertRaisesRegex( - PlotlyError, pattern4, ff.create_gantt, df, colors=colors_dict_good - ) - - # check: number of colors is equal to or greater than number of - # unique index string values - pattern5 = ( - "Error. The number of colors in 'colors' must be no less " - "than the number of unique index values in your group " - "column." - ) - - self.assertRaisesRegex( - PlotlyError, - pattern5, - ff.create_gantt, - df, - index_col="Resource", - colors=["#ffffff"], - ) - - # check: if index is numeric, colors has at least 2 colors in it - pattern6 = ( - "You must use at least 2 colors in 'colors' if you " - "are using a colorscale. However only the first two " - "colors given will be used for the lower and upper " - "bounds on the colormap." - ) - - self.assertRaisesRegex( - PlotlyError, - pattern6, - ff.create_gantt, - df, - index_col="Complete", - colors=["#ffffff"], - ) - - def test_gannt_groups_and_descriptions(self): - # check if grouped gantt chart matches with expected output - - df = [ - dict( - Task="Task A", - Description="Task A - 1", - Start="2008-10-05", - Finish="2009-04-15", - IndexCol="TA", - ), - dict( - Task="Task B", - Description="Task B - 1", - Start="2008-12-06", - Finish="2009-03-15", - IndexCol="TB", - ), - dict( - Task="Task C", - Description="Task C - 1", - Start="2008-09-07", - Finish="2009-03-15", - IndexCol="TC", - ), - dict( - Task="Task C", - Description="Task C - 2", - Start="2009-05-08", - Finish="2009-04-15", - IndexCol="TC", - ), - dict( - Task="Task A", - Description="Task A - 2", - Start="2009-04-20", - Finish="2009-05-30", - IndexCol="TA", - ), - ] - - test_gantt_chart = ff.create_gantt( - df, - colors=dict(TA="rgb(220, 0, 0)", TB="rgb(170, 14, 200)", TC=(1, 0.9, 0.16)), - show_colorbar=True, - index_col="IndexCol", - group_tasks=True, - ) - - exp_gantt_chart = graph_objs.Figure( - **{ - "layout": { - "showlegend": True, - "yaxis": { - "range": [-1, 4], - "zeroline": False, - "ticktext": ["Task C", "Task B", "Task A"], - "tickvals": [0, 1, 2], - "autorange": False, - "showgrid": False, - }, - "title": "Gantt Chart", - "height": 600, - "shapes": [], - "width": 900, - "xaxis": { - "zeroline": False, - "rangeselector": { - "buttons": [ - { - "count": 7, - "step": "day", - "stepmode": "backward", - "label": "1w", - }, - { - "count": 1, - "step": "month", - "stepmode": "backward", - "label": "1m", - }, - { - "count": 6, - "step": "month", - "stepmode": "backward", - "label": "6m", - }, - { - "count": 1, - "step": "year", - "stepmode": "todate", - "label": "YTD", - }, - { - "count": 1, - "step": "year", - "stepmode": "backward", - "label": "1y", - }, - {"step": "all"}, - ] - }, - "type": "date", - "showgrid": False, - }, - "hovermode": "closest", - }, - "data": [ - { - "legendgroup": "rgb(170, 14, 200)", - "name": "TB", - "fillcolor": "rgb(170, 14, 200)", - "mode": "none", - "hoverinfo": "name", - "y": [0.8, 0.8, 1.2, 1.2], - "x": ["2008-12-06", "2009-03-15", "2009-03-15", "2008-12-06"], - "fill": "toself", - }, - { - "legendgroup": "rgb(220, 0, 0)", - "name": "TA", - "fillcolor": "rgb(220, 0, 0)", - "mode": "none", - "hoverinfo": "name", - "y": [1.8, 1.8, 2.2, 2.2, None, 1.8, 1.8, 2.2, 2.2], - "x": [ - "2008-10-05", - "2009-04-15", - "2009-04-15", - "2008-10-05", - "2008-10-05", - "2009-04-20", - "2009-05-30", - "2009-05-30", - "2009-04-20", - ], - "fill": "toself", - }, - { - "legendgroup": "rgb(255, 230, 41)", - "name": "TC", - "fillcolor": "rgb(255, 230, 41)", - "mode": "none", - "hoverinfo": "name", - "y": [-0.2, -0.2, 0.2, 0.2, None, -0.2, -0.2, 0.2, 0.2], - "x": [ - "2008-09-07", - "2009-03-15", - "2009-03-15", - "2008-09-07", - "2008-09-07", - "2009-05-08", - "2009-04-15", - "2009-04-15", - "2009-05-08", - ], - "fill": "toself", - }, - { - "showlegend": False, - "legendgroup": "rgb(170, 14, 200)", - "name": "", - "text": ["Task B - 1", "Task B - 1"], - "y": [1, 1], - "mode": "markers", - "marker": { - "opacity": 0, - "color": "rgb(170, 14, 200)", - "size": 1, - }, - "x": ["2008-12-06", "2009-03-15"], - }, - { - "showlegend": False, - "legendgroup": "rgb(220, 0, 0)", - "name": "", - "text": [ - "Task A - 1", - "Task A - 1", - "Task A - 2", - "Task A - 2", - ], - "y": [2, 2, 2, 2], - "mode": "markers", - "marker": {"opacity": 0, "color": "rgb(220, 0, 0)", "size": 1}, - "x": ["2008-10-05", "2009-04-15", "2009-04-20", "2009-05-30"], - }, - { - "showlegend": False, - "legendgroup": "rgb(255, 230, 41)", - "name": "", - "text": [ - "Task C - 1", - "Task C - 1", - "Task C - 2", - "Task C - 2", - ], - "y": [0, 0, 0, 0], - "mode": "markers", - "marker": { - "opacity": 0, - "color": "rgb(255, 230, 41)", - "size": 1, - }, - "x": ["2008-09-07", "2009-03-15", "2009-05-08", "2009-04-15"], - }, - ], - } - ) - - self.assert_fig_equal(test_gantt_chart["data"][0], exp_gantt_chart["data"][0]) - self.assert_fig_equal(test_gantt_chart["data"][1], exp_gantt_chart["data"][1]) - self.assert_fig_equal(test_gantt_chart["data"][2], exp_gantt_chart["data"][2]) - self.assert_fig_equal(test_gantt_chart["data"][3], exp_gantt_chart["data"][3]) - - def test_gantt_all_args(self): - # check if gantt chart matches with expected output - - df = [ - { - "Task": "Run", - "Start": "2010-01-01", - "Finish": "2011-02-02", - "Complete": 0, - }, - { - "Task": "Fast", - "Start": "2011-01-01", - "Finish": "2012-06-05", - "Complete": 25, - }, - ] - - test_gantt_chart = ff.create_gantt( - df, - colors="Blues", - index_col="Complete", - reverse_colors=True, - title="Title", - bar_width=0.5, - showgrid_x=True, - showgrid_y=True, - height=500, - width=500, - ) - - exp_gantt_chart = graph_objs.Figure( - **{ - "data": [ - { - "x": ["2011-01-01", "2012-06-05", "2012-06-05", "2011-01-01"], - "y": [0.5, 0.5, 1.5, 1.5], - "mode": "none", - "fill": "toself", - "showlegend": False, - "hoverinfo": "name", - "legendgroup": "rgb(166.25, 167.5, 208.0)", - "fillcolor": "rgb(166.25, 167.5, 208.0)", - "name": "25", - }, - { - "x": ["2010-01-01", "2011-02-02", "2011-02-02", "2010-01-01"], - "y": [-0.5, -0.5, 0.5, 0.5], - "mode": "none", - "fill": "toself", - "showlegend": False, - "hoverinfo": "name", - "legendgroup": "rgb(220.0, 220.0, 220.0)", - "fillcolor": "rgb(220.0, 220.0, 220.0)", - "name": "0", - }, - { - "x": ["2011-01-01", "2012-06-05"], - "y": [1, 1], - "mode": "markers", - "text": [None, None], - "marker": { - "color": "rgb(166.25, 167.5, 208.0)", - "size": 1, - "opacity": 0, - }, - "name": "", - "showlegend": False, - "legendgroup": "rgb(166.25, 167.5, 208.0)", - }, - { - "x": ["2010-01-01", "2011-02-02"], - "y": [0, 0], - "mode": "markers", - "text": [None, None], - "marker": { - "color": "rgb(220.0, 220.0, 220.0)", - "size": 1, - "opacity": 0, - }, - "name": "", - "showlegend": False, - "legendgroup": "rgb(220.0, 220.0, 220.0)", - }, - ], - "layout": { - "title": "Title", - "showlegend": False, - "height": 500, - "width": 500, - "shapes": [], - "hovermode": "closest", - "yaxis": { - "showgrid": True, - "ticktext": ["Run", "Fast"], - "tickvals": [0, 1], - "range": [-1, 3], - "autorange": False, - "zeroline": False, - }, - "xaxis": { - "showgrid": True, - "zeroline": False, - "rangeselector": { - "buttons": [ - { - "count": 7, - "label": "1w", - "step": "day", - "stepmode": "backward", - }, - { - "count": 1, - "label": "1m", - "step": "month", - "stepmode": "backward", - }, - { - "count": 6, - "label": "6m", - "step": "month", - "stepmode": "backward", - }, - { - "count": 1, - "label": "YTD", - "step": "year", - "stepmode": "todate", - }, - { - "count": 1, - "label": "1y", - "step": "year", - "stepmode": "backward", - }, - {"step": "all"}, - ] - }, - "type": "date", - }, - }, - } - ) - - self.assert_fig_equal(test_gantt_chart["data"][0], exp_gantt_chart["data"][0]) - - self.assert_fig_equal(test_gantt_chart["data"][1], exp_gantt_chart["data"][1]) - - self.assert_fig_equal(test_gantt_chart["data"][2], exp_gantt_chart["data"][2]) - - self.assert_fig_equal(test_gantt_chart["layout"], exp_gantt_chart["layout"]) - - -class Test2D_Density(TestCaseNoTemplate, NumpyTestUtilsMixin): - def test_validate_2D_density(self): - # validate that x and y contain only numbers - x = [1, 2] - y = ["a", 2] - - pattern = "All elements of your 'x' and 'y' lists must be numbers." - - self.assertRaisesRegex(PlotlyError, pattern, ff.create_2d_density, x, y) - - # validate that x and y are the same length - x2 = [1] - y2 = [1, 2] - - pattern2 = "Both lists 'x' and 'y' must be the same length." - - self.assertRaisesRegex(PlotlyError, pattern2, ff.create_2d_density, x2, y2) - - def test_2D_density_all_args(self): - # check if 2D_density data matches with expected output - x = [1, 2] - y = [2, 4] - - colorscale = [ - "#7A4579", - "#D56073", - "rgb(236,158,105)", - (1, 1, 0.2), - (0.98, 0.98, 0.98), - ] - - test_2D_density_chart = ff.create_2d_density( - x, - y, - colorscale=colorscale, - hist_color="rgb(255,237,222)", - point_size=3, - height=800, - width=800, - ) - - exp_2D_density_chart = { - "data": [ - { - "marker": {"color": "rgb(0, 0, 128)", "opacity": 0.4, "size": 3}, - "mode": "markers", - "name": "points", - "type": "scatter", - "x": [1, 2], - "y": [2, 4], - }, - { - "colorscale": [ - [0.0, "rgb(122, 69, 121)"], - [0.25, "rgb(213, 96, 115)"], - [0.5, "rgb(236, 158, 105)"], - [0.75, "rgb(255, 255, 51)"], - [1.0, "rgb(250, 250, 250)"], - ], - "name": "density", - "ncontours": 20, - "reversescale": True, - "showscale": False, - "type": "histogram2dcontour", - "x": [1, 2], - "y": [2, 4], - }, - { - "marker": {"color": "rgb(255, 237, 222)"}, - "name": "x density", - "type": "histogram", - "x": [1, 2], - "yaxis": "y2", - }, - { - "marker": {"color": "rgb(255, 237, 222)"}, - "name": "y density", - "type": "histogram", - "xaxis": "x2", - "y": [2, 4], - }, - ], - "layout": { - "autosize": False, - "bargap": 0, - "height": 800, - "hovermode": "closest", - "margin": {"t": 50}, - "showlegend": False, - "title": {"text": "2D Density Plot"}, - "width": 800, - "xaxis": {"domain": [0, 0.85], "showgrid": False, "zeroline": False}, - "xaxis2": {"domain": [0.85, 1], "showgrid": False, "zeroline": False}, - "yaxis": {"domain": [0, 0.85], "showgrid": False, "zeroline": False}, - "yaxis2": {"domain": [0.85, 1], "showgrid": False, "zeroline": False}, - }, - } - - self.assert_fig_equal( - test_2D_density_chart["data"][0], exp_2D_density_chart["data"][0] - ) - - self.assert_fig_equal( - test_2D_density_chart["data"][1], exp_2D_density_chart["data"][1] - ) - - self.assert_fig_equal( - test_2D_density_chart["data"][2], exp_2D_density_chart["data"][2] - ) - - self.assert_fig_equal( - test_2D_density_chart["data"][3], exp_2D_density_chart["data"][3] - ) - - self.assert_fig_equal( - test_2D_density_chart["layout"], exp_2D_density_chart["layout"] - ) From 4c0dad7a8045057849461253c698d8d6c3dee5e5 Mon Sep 17 00:00:00 2001 From: Emily KL <4672118+emilykl@users.noreply.github.com> Date: Thu, 18 Jun 2026 13:27:10 -0400 Subject: [PATCH 3/8] add changelog entry --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 222706d86b4..c0e5134c31b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## Unreleased +### Removed +- Remove the deprecated Figure Factory functions `create_2d_density`, `create_annotated_heatmap`, `create_bullet`, `create_candlestick`, `create_choropleth`, `create_distplot`, `create_facet_grid`, `create_gantt`, `create_hexbin_mapbox`, `create_ohlc`, `create_scatterplotmatrix`, and `create_violin`. [[#5627](https://github.com/plotly/plotly.py/pull/5627)] + ### Fixed - Raise a clear `ValueError` when an unsupported marginal plot type is passed to Plotly Express, instead of failing later with a cryptic `'NoneType' object has no attribute 'constructor'` message [[#5625](https://github.com/plotly/plotly.py/pull/5625)], with thanks to @eugen-goebel for the contribution! From 901ebed2779edd49cfec5c84b740abff51a964c7 Mon Sep 17 00:00:00 2001 From: Emily KL <4672118+emilykl@users.noreply.github.com> Date: Thu, 18 Jun 2026 13:27:52 -0400 Subject: [PATCH 4/8] formatting --- tests/test_optional/test_tools/test_figure_factory.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/test_optional/test_tools/test_figure_factory.py b/tests/test_optional/test_tools/test_figure_factory.py index 8e2b8cf5878..e77e3b210c8 100644 --- a/tests/test_optional/test_tools/test_figure_factory.py +++ b/tests/test_optional/test_tools/test_figure_factory.py @@ -456,5 +456,3 @@ def test_table_with_index(self): self.assert_fig_equal(index_table["data"][0], exp_index_table["data"][0]) self.assert_fig_equal(index_table["layout"], exp_index_table["layout"]) - - From 3185b9a1567bcc1fc3bc24122b41138905568738 Mon Sep 17 00:00:00 2001 From: Emily KL <4672118+emilykl@users.noreply.github.com> Date: Thu, 18 Jun 2026 18:37:10 -0400 Subject: [PATCH 5/8] update docs to reflect removed figure factory functions --- doc/apidoc/plotly.figure_factory.rst | 11 - doc/python/annotated-heatmap.md | 107 +------ doc/python/choropleth-maps.md | 37 --- doc/python/county-choropleth.md | 288 ------------------ doc/python/distplot.md | 233 -------------- doc/python/figure-factories.md | 20 +- doc/python/gantt.md | 63 ---- doc/python/getting-started.md | 18 -- doc/python/hexbin-mapbox.md | 2 +- doc/unconverted/python/basic-statistics.md | 19 +- doc/unconverted/python/density-plots.md | 117 ------- doc/unconverted/python/linear-algebra.md | 28 +- doc/unconverted/python/statistics-charts.md | 13 - .../python/webgl-text-and-annotations.md | 1 - 14 files changed, 50 insertions(+), 907 deletions(-) delete mode 100644 doc/python/county-choropleth.md delete mode 100644 doc/unconverted/python/density-plots.md diff --git a/doc/apidoc/plotly.figure_factory.rst b/doc/apidoc/plotly.figure_factory.rst index be2a4613abf..a1a12c9456f 100644 --- a/doc/apidoc/plotly.figure_factory.rst +++ b/doc/apidoc/plotly.figure_factory.rst @@ -9,22 +9,11 @@ :toctree: generated/ :template: function.rst - create_2d_density - create_annotated_heatmap - create_bullet - create_candlestick - create_choropleth create_dendrogram - create_distplot - create_facet_grid - create_gantt create_hexbin_map - create_ohlc create_quiver - create_scatterplotmatrix create_streamline create_table create_ternary_contour create_trisurf - create_violin diff --git a/doc/python/annotated-heatmap.md b/doc/python/annotated-heatmap.md index 6a4adc4c45e..37ad05cff8b 100644 --- a/doc/python/annotated-heatmap.md +++ b/doc/python/annotated-heatmap.md @@ -38,14 +38,14 @@ jupyter: *New in v5.5* -As of version 5.5.0 of `plotly`, the **recommended way to [display annotated heatmaps is to use `px.imshow()`](/python/heatmaps/)** rather than the now-deprecated `create_annotated_heatmap` figure factory documented below for historical reasons. +Plotly Express provides the [`px.imshow()`](/python/heatmaps/) function which can be used for creating annotated heatmaps. #### Basic Annotated Heatmap for z-annotations *New in v5.5* -After creating a figure with `px.imshow`, you can add z-annotations with `.update_traces(texttemplate="%{z}")`. +When creating a figure with `px.imshow`, you can pass the parameter `text_auto=True` to add z-annotations. ```python import plotly.express as px @@ -60,50 +60,9 @@ fig = px.imshow(z, text_auto=True) fig.show() ``` -### Deprecated Figure Factory +#### Custom Text and Axis Labels -The remaining examples show how to create Annotated Heatmaps with the deprecated `create_annotated_heatmap` [figure factory](/python/figure-factories/). - - -#### Simple Annotated Heatmap - -```python -import plotly.figure_factory as ff - -z = [[.1, .3, .5, .7, .9], - [1, .8, .6, .4, .2], - [.2, 0, .5, .7, .9], - [.9, .8, .4, .2, 0], - [.3, .4, .5, .7, 1]] - -fig = ff.create_annotated_heatmap(z) -fig.show() -``` - -#### Custom Text and X & Y Labels -set `annotation_text` to a matrix with the same dimensions as `z` - -> WARNING: this legacy figure factory requires the `y` array to be provided in reverse order, and will map the `z_text` to the `z` values in reverse order. **The use of the `px.imshow()` version below is highly recommended** - -```python -import plotly.figure_factory as ff - -z = [[.1, .3, .5], - [1.0, .8, .6], - [.6, .4, .2]] - -x = ['Team A', 'Team B', 'Team C'] -y = ['Game Three', 'Game Two', 'Game One'] - -z_text = [['Win', 'Lose', 'Win'], - ['Lose', 'Lose', 'Win'], - ['Win', 'Win', 'Lose']] - -fig = ff.create_annotated_heatmap(z, x=x, y=y, annotation_text=z_text, colorscale='Viridis') -fig.show() -``` - -Here is the same figure using `px.imshow()` +To annotate cells with text other than the `z` values, set the `text` attribute with `update_traces` and display it with a `texttemplate`. You can also label the axes by passing `x` and `y`. ```python import plotly.express as px @@ -125,27 +84,9 @@ fig.update_xaxes(side="top") fig.show() ``` -#### Annotated Heatmap with numpy - -```python -import plotly.figure_factory as ff -import numpy as np -np.random.seed(1) - -z = np.random.randn(20, 20) -z_text = np.around(z, decimals=2) # Only show rounded value (full value on hover) - -fig = ff.create_annotated_heatmap(z, annotation_text=z_text, colorscale='Greys', - hoverinfo='z') - -# Make text size smaller -for i in range(len(fig.layout.annotations)): - fig.layout.annotations[i].font.size = 8 - -fig.show() -``` +#### Annotated Heatmap with a NumPy Array -Here is the same figure using `px.imshow()` +`px.imshow` works directly with NumPy arrays. Pass a [`d3-format`](https://github.com/d3/d3-format/tree/v1.4.5#d3-format) string to `text_auto` to control how the annotations are formatted. ```python import plotly.express as px @@ -158,10 +99,14 @@ fig = px.imshow(z, text_auto=".2f", color_continuous_scale='Greys', aspect="auto fig.show() ``` -Here is a fairly contrived example showing how one can display a periodic table with custom text and hover using `ff.create_annotated_heatmap()` (scroll below to see the `px.imshow()` equivalent). +#### Periodic Table with Custom Text and Hover + +`px.imshow()` can produce more elaborate annotated heatmaps. The example below renders a periodic table: the cell labels come from a custom `text` array, while `customdata` combined with a `hovertemplate` displays the element name and atomic mass on hover. ```python -# Periodic Table Data +import plotly.express as px +import numpy as np + symbol = [['H', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'He'], ['Li', 'Be', '', '', '', '', '', '', '', '', '', '', 'B', 'C', 'N', 'O', 'F', 'Ne'], ['Na', 'Mg', '', '', '', '', '', '', '', '', '', '', 'Al', 'Si', 'P', 'S', 'Cl', 'Ar'], @@ -214,36 +159,10 @@ color = [[.8, .0, .0, .0, .0, .0, .0, .0, .0, .0, .0, .0, .0, .0, .0, .0, .0, 1. [.1, .1, .1, .3, .3, .3, .5, .5, .5, .7, .7, .7, .9, .9, .9, .0, .0, .0], [.2, .2, .2, .4, .4, .4, .6, .6, .6, .8, .8, .8, 1., 1., 1., .0, .0, .0]] -# Set Colorscale colorscale=[[0.0, 'rgb(255,255,255)'], [.2, 'rgb(255, 255, 153)'], [.4, 'rgb(153, 255, 204)'], [.6, 'rgb(179, 217, 255)'], [.8, 'rgb(240, 179, 255)'],[1.0, 'rgb(255, 77, 148)']] -# Display element name and atomic mass on hover -hover=[] -for x in range(len(symbol)): - hover.append([i + '
' + 'Atomic Mass: ' + str(j) if i else '' - for i, j in zip(element[x], atomic_mass[x])]) - -import plotly.figure_factory as ff -# Make Annotated Heatmap -fig = ff.create_annotated_heatmap(color[::-1], annotation_text=symbol[::-1], text=hover[::-1], - colorscale=colorscale, font_colors=['black'], hoverinfo='text') -fig.update_layout( - title_text='Periodic Table', - margin=dict(l=10, r=10, t=10, b=10, pad=10), - xaxis=dict(zeroline=False, showgrid=False), - yaxis=dict(zeroline=False, showgrid=False, scaleanchor="x"), -) -fig.show() -``` - -Here is the same output using `px.imshow()` with much less array manipulation: - -```python -import plotly.express as px -import numpy as np - fig = px.imshow(color, color_continuous_scale=colorscale, aspect="auto", title='Periodic Table') fig.update_traces( @@ -259,4 +178,4 @@ fig.show() #### Reference -For more info on Plotly heatmaps, see: https://plotly.com/python/reference/heatmap/.
For more info on using colorscales with Plotly see: https://plotly.com/python/heatmap-and-contour-colorscales/
For more info on `ff.create_annotated_heatmap()`, see the [full function reference](https://plotly.com/python-api-reference/generated/plotly.figure_factory.create_annotated_heatmap.html#plotly.figure_factory.create_annotated_heatmap) +For more info on Plotly heatmaps, see: https://plotly.com/python/reference/heatmap/.
For more info on using colorscales with Plotly see: https://plotly.com/python/heatmap-and-contour-colorscales/ diff --git a/doc/python/choropleth-maps.md b/doc/python/choropleth-maps.md index cb6961c0e23..0919535c26d 100644 --- a/doc/python/choropleth-maps.md +++ b/doc/python/choropleth-maps.md @@ -349,43 +349,6 @@ fig.update_layout( fig.show() ``` -#### County Choropleth Figure Factory - -Plotly also includes a [legacy "figure factory" for creating US county-level choropleth maps](/python/county-choropleth/). - -```python -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'] - -colorscale = ["#f7fbff", "#ebf3fb", "#deebf7", "#d2e3f3", "#c6dbef", "#b3d2e9", "#9ecae1", - "#85bcdb", "#6baed6", "#57a0ce", "#4292c6", "#3082be", "#2171b5", "#1361a9", - "#08519c", "#0b4083", "#08306b" -] -endpts = list(np.linspace(1, 12, len(colorscale) - 1)) -fips = df_sample['FIPS'].tolist() -values = df_sample['Unemployment Rate (%)'].tolist() - - -fig = ff.create_choropleth( - fips=fips, values=values, scope=['usa'], - binning_endpoints=endpts, colorscale=colorscale, - show_state_data=False, - show_hover=True, - asp = 2.9, - title_text = 'USA by Unemployment %', - legend_title = '% unemployed' -) -fig.layout.template = None -fig.show() -``` - #### Reference See [function reference for `px.(choropleth)`](https://plotly.com/python-api-reference/generated/plotly.express.choropleth) or https://plotly.com/python/reference/choropleth/ for more information and chart attribute options! diff --git a/doc/python/county-choropleth.md b/doc/python/county-choropleth.md deleted file mode 100644 index 1e4410db37f..00000000000 --- a/doc/python/county-choropleth.md +++ /dev/null @@ -1,288 +0,0 @@ ---- -jupyter: - jupytext: - notebook_metadata_filter: all - text_representation: - extension: .md - format_name: markdown - format_version: '1.3' - jupytext_version: 1.16.3 - kernelspec: - display_name: Python 3 (ipykernel) - language: python - name: python3 - language_info: - codemirror_mode: - name: ipython - version: 3 - file_extension: .py - mimetype: text/x-python - name: python - nbconvert_exporter: python - pygments_lexer: ipython3 - version: 3.10.0 - plotly: - description: How to create colormaped representations of USA counties by FIPS - values in Python. - display_as: maps - language: python - layout: base - name: USA County Choropleth Maps - order: 11 - page_type: u-guide - permalink: python/county-choropleth/ - thumbnail: thumbnail/county-choropleth-usa-greybkgd.jpg ---- - -### Deprecation warning - - -This page describes a [legacy "figure factory" method](/python/figure-factories/) for creating map-like figures using [self-filled scatter traces](/python/shapes). **This is no longer the recommended way to make county-level choropleth maps**, instead we recommend using a [GeoJSON-based approach to making outline choropleth maps](/python/choropleth-maps/) or the alternative [tile-based choropleth maps](/python/tile-county-choropleth). - - -#### Required Packages -`plotly_geo`, `geopandas`, `pyshp` and `shapely` must be installed for this figure factory to run. - -Run the following commands to install the correct versions of the following modules: - -```python -!pip install plotly-geo==1.0.0 -!pip install geopandas==0.8.1 -!pip install pyshp==2.1.2 -!pip install shapely==1.7.1 -``` - -If you are using Windows, follow this post to properly install geopandas and dependencies: http://geoffboeing.com/2014/09/using-geopandas-windows/. If you are using Anaconda, do not use PIP to install the packages above. Instead use conda to install them: - - -conda install plotly -conda install geopandas - - -#### FIPS and Values -Every US state and county has an assigned ID regulated by the US Federal Government under the term FIPS (Federal Information Processing Standards) codes. There are state codes and county codes: the 2016 state and county FIPS codes can be found at the [US Census Website](https://www.census.gov/geographies/reference-files/2016/demo/popest/2016-fips.html). - -Combine a state FIPS code (eg. `06` for California) with a county FIPS code of the state (eg. `059` for Orange county) and this new state-county FIPS code (`06059`) uniquely refers to the specified state and county. - -`ff.create_choropleth` only needs a list of FIPS codes and a list of values. Each FIPS code points to one county and each corresponding value in `values` determines the color of the county. - - -#### Simple Example -A simple example of this is a choropleth a few counties in California: - -```python -import plotly.figure_factory as ff - -fips = ['06021', '06023', '06027', - '06029', '06033', '06059', - '06047', '06049', '06051', - '06055', '06061'] -values = range(len(fips)) - -fig = ff.create_choropleth(fips=fips, values=values) -fig.layout.template = None -fig.show() -``` - -#### Change the Scope -Even if your FIPS values belong to a single state, the scope defaults to the entire United States as displayed in the example above. Changing the scope of the choropleth shifts the zoom and position of the USA map. You can define the scope with a list of state names and the zoom will automatically adjust to include the state outlines of the selected states. - -By default `scope` is set to `['USA']` which the API treats as identical to passing a list of all 50 state names:
- -`['AK', 'AL', 'CA', ...]` - -State abbreviations (eg. `CA`) or the proper names (eg. `California`) as strings are accepted. If the state name is not recognized, the API will throw a Warning and indicate which FIPS values were ignored. - -Another param used in the example below is `binning_endpoints`. If your `values` is a list of numbers, you can bin your values into half-open intervals on the real line. - -```python -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'] == '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, scope=['CA', 'AZ', 'Nevada', 'Oregon', ' Idaho'], - binning_endpoints=[14348, 63983, 134827, 426762, 2081313], colorscale=colorscale, - county_outline={'color': 'rgb(255,255,255)', 'width': 0.5}, round_legend_values=True, - legend=dict( - title=dict( - text='Population by County' - ) - ), - title=dict( - text='California and Nearby States' - ) -) -fig.layout.template = None -fig.show() -``` - -#### Single State - -```python -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() - -endpts = 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=endpts, round_legend_values=True, - plot_bgcolor='rgb(229,229,229)', - paper_bgcolor='rgb(229,229,229)', - legend_title='Population by County', - county_outline={'color': 'rgb(255,255,255)', 'width': 0.5}, - exponent_format=True, -) -fig.layout.template = None -fig.show() -``` - -#### Multiple States - -```python -import plotly.figure_factory as ff - -import pandas as pd - -NE_states = ['Connecticut', 'Maine', 'Massachusetts', 'New Hampshire', 'Rhode Island', 'Vermont'] -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)] - -values = df_sample_r['TOT_POP'].tolist() -fips = df_sample_r['FIPS'].tolist() - -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)' -] - -fig = ff.create_choropleth( - fips=fips, values=values, - scope=NE_states, county_outline={'color': 'rgb(255,255,255)', 'width': 0.5}, - legend_title='Population per county' - -) -fig.update_layout( - legend_x = 0, - annotations = {'x': -0.12, 'xanchor': 'left'} -) - -fig.layout.template = None -fig.show() -``` - -#### Simplify County, State Lines -Below is a choropleth that uses several other parameters. For a full list of all available params call `help(ff.create_choropleth)` - -- `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. -- `simplify_state` simplifies the state outline polygon. See the [documentation](http://toblerity.org/shapely/manual.html#object.simplify) for more information. -Default for both `simplify_county` and `simplify_state` is 0.02 - -Note: This choropleth uses a divergent categorical colorscale. See http://react-colorscales.getforge.io/ for other cool colorscales. - -```python -import plotly.figure_factory as ff - -import pandas as pd - -scope = ['Oregon'] -df_sample = pd.read_csv( - 'https://raw.githubusercontent.com/plotly/datasets/master/minoritymajority.csv' -) -df_sample_r = df_sample[df_sample['STNAME'].isin(scope)] - -values = df_sample_r['TOT_POP'].tolist() -fips = df_sample_r['FIPS'].tolist() - -colorscale = ["#8dd3c7", "#ffffb3", "#bebada", "#fb8072", - "#80b1d3", "#fdb462", "#b3de69", "#fccde5", - "#d9d9d9", "#bc80bd", "#ccebc5", "#ffed6f", - "#8dd3c7", "#ffffb3", "#bebada", "#fb8072", - "#80b1d3", "#fdb462", "#b3de69", "#fccde5", - "#d9d9d9", "#bc80bd", "#ccebc5", "#ffed6f", - "#8dd3c7", "#ffffb3", "#bebada", "#fb8072", - "#80b1d3", "#fdb462", "#b3de69", "#fccde5", - "#d9d9d9", "#bc80bd", "#ccebc5", "#ffed6f"] - -fig = ff.create_choropleth( - fips=fips, values=values, scope=scope, - colorscale=colorscale, round_legend_values=True, - simplify_county=0, simplify_state=0, - county_outline={'color': 'rgb(15, 15, 55)', 'width': 0.5}, - state_outline={'width': 1}, - legend_title='pop. per county', - title='Oregon' -) - -fig.layout.template = None -fig.show() -``` - -#### The Entire USA - -```python -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'] - -colorscale = ["#f7fbff","#ebf3fb","#deebf7","#d2e3f3","#c6dbef","#b3d2e9","#9ecae1", - "#85bcdb","#6baed6","#57a0ce","#4292c6","#3082be","#2171b5","#1361a9", - "#08519c","#0b4083","#08306b"] -endpts = list(np.linspace(1, 12, len(colorscale) - 1)) -fips = df_sample['FIPS'].tolist() -values = df_sample['Unemployment Rate (%)'].tolist() - -fig = ff.create_choropleth( - fips=fips, values=values, - binning_endpoints=endpts, - colorscale=colorscale, - show_state_data=False, - show_hover=True, centroid_marker={'opacity': 0}, - asp=2.9, title='USA by Unemployment %', - legend_title='% unemployed' -) - -fig.layout.template = None -fig.show() -``` - -Also see tile county choropleths made in Python: [https://plotly.com/python/tile-county-choropleth/](https://plotly.com/python/tile-county-choropleth/) - -### Reference - -For more info on `ff.create_choropleth()`, see the [full function reference](https://plotly.com/python-api-reference/generated/plotly.figure_factory.create_choropleth.html) diff --git a/doc/python/distplot.md b/doc/python/distplot.md index 07480a39250..33335248c43 100644 --- a/doc/python/distplot.md +++ b/doc/python/distplot.md @@ -72,236 +72,3 @@ IFrame(snippet_url + 'distplot', width='100%', height=1200)

Sign up for Dash Club → Free cheat sheets plus updates from Chris Parmer and Adam Schroeder delivered to your inbox every two months. Includes tips and tricks, community apps, and deep dives into the Dash architecture. Join now.

- -## Combined statistical representations with distplot figure factory - -The distplot [figure factory](/python/figure-factories/) displays a combination of statistical representations of numerical data, such as histogram, kernel density estimation or normal curve, and rug plot. - -#### Basic Distplot - -A histogram, a kde plot and a rug plot are displayed. - -```python -import plotly.figure_factory as ff -import numpy as np -np.random.seed(1) - -x = np.random.randn(1000) -hist_data = [x] -group_labels = ['distplot'] # name of the dataset - -fig = ff.create_distplot(hist_data, group_labels) -fig.show() -``` - -#### Plot Multiple Datasets - -```python -import plotly.figure_factory as ff -import numpy as np - -# Add histogram data -x1 = np.random.randn(200) - 2 -x2 = np.random.randn(200) -x3 = np.random.randn(200) + 2 -x4 = np.random.randn(200) + 4 - -# Group data together -hist_data = [x1, x2, x3, x4] - -group_labels = ['Group 1', 'Group 2', 'Group 3', 'Group 4'] - -# Create distplot with custom bin_size -fig = ff.create_distplot(hist_data, group_labels, bin_size=.2) -fig.show() -``` - -#### Use Multiple Bin Sizes - -Different bin sizes are used for the different datasets with the `bin_size` argument. - -```python -import plotly.figure_factory as ff -import numpy as np - -# Add histogram data -x1 = np.random.randn(200)-2 -x2 = np.random.randn(200) -x3 = np.random.randn(200)+2 -x4 = np.random.randn(200)+4 - -# Group data together -hist_data = [x1, x2, x3, x4] - -group_labels = ['Group 1', 'Group 2', 'Group 3', 'Group 4'] - -# Create distplot with custom bin_size -fig = ff.create_distplot(hist_data, group_labels, bin_size=[.1, .25, .5, 1]) -fig.show() -``` - -#### Customize Rug Text, Colors & Title - -```python -import plotly.figure_factory as ff -import numpy as np - -x1 = np.random.randn(26) -x2 = np.random.randn(26) + .5 - -group_labels = ['2014', '2015'] - -rug_text_one = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', - 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', - 'u', 'v', 'w', 'x', 'y', 'z'] - -rug_text_two = ['aa', 'bb', 'cc', 'dd', 'ee', 'ff', 'gg', 'hh', 'ii', 'jj', - 'kk', 'll', 'mm', 'nn', 'oo', 'pp', 'qq', 'rr', 'ss', 'tt', - 'uu', 'vv', 'ww', 'xx', 'yy', 'zz'] - -rug_text = [rug_text_one, rug_text_two] # for hover in rug plot -colors = ['rgb(0, 0, 100)', 'rgb(0, 200, 200)'] - -# Create distplot with custom bin_size -fig = ff.create_distplot( - [x1, x2], group_labels, bin_size=.2, - rug_text=rug_text, colors=colors) - -fig.update_layout(title_text='Customized Distplot') -fig.show() -``` - -#### Plot Normal Curve - -```python -import plotly.figure_factory as ff -import numpy as np - -x1 = np.random.randn(200) -x2 = np.random.randn(200) + 2 - -group_labels = ['Group 1', 'Group 2'] - -colors = ['slategray', 'magenta'] - -# Create distplot with curve_type set to 'normal' -fig = ff.create_distplot([x1, x2], group_labels, bin_size=.5, - curve_type='normal', # override default 'kde' - colors=colors) - -# Add title -fig.update_layout(title_text='Distplot with Normal Distribution') -fig.show() -``` - -#### Plot Only Curve and Rug - -```python -import plotly.figure_factory as ff -import numpy as np - -x1 = np.random.randn(200) - 1 -x2 = np.random.randn(200) -x3 = np.random.randn(200) + 1 - -hist_data = [x1, x2, x3] - -group_labels = ['Group 1', 'Group 2', 'Group 3'] -colors = ['#333F44', '#37AA9C', '#94F3E4'] - -# Create distplot with curve_type set to 'normal' -fig = ff.create_distplot(hist_data, group_labels, show_hist=False, colors=colors) - -# Add title -fig.update_layout(title_text='Curve and Rug Plot') -fig.show() -``` - -#### Plot Only Hist and Rug - -```python -import plotly.figure_factory as ff -import numpy as np - -x1 = np.random.randn(200) - 1 -x2 = np.random.randn(200) -x3 = np.random.randn(200) + 1 - -hist_data = [x1, x2, x3] - -group_labels = ['Group 1', 'Group 2', 'Group 3'] -colors = ['#835AF1', '#7FA6EE', '#B8F7D4'] - -# Create distplot with curve_type set to 'normal' -fig = ff.create_distplot(hist_data, group_labels, colors=colors, bin_size=.25, - show_curve=False) - -# Add title -fig.update_layout(title_text='Hist and Rug Plot') -fig.show() -``` - -#### Plot Hist and Rug with Different Bin Sizes - -```python -import plotly.figure_factory as ff -import numpy as np - -x1 = np.random.randn(200) - 2 -x2 = np.random.randn(200) -x3 = np.random.randn(200) + 2 - -hist_data = [x1, x2, x3] - -group_labels = ['Group 1', 'Group 2', 'Group 3'] -colors = ['#393E46', '#2BCDC1', '#F66095'] - -fig = ff.create_distplot(hist_data, group_labels, colors=colors, - bin_size=[0.3, 0.2, 0.1], show_curve=False) - -# Add title -fig.update(layout_title_text='Hist and Rug Plot') -fig.show() -``` - -#### Plot Only Hist and Curve - -```python -import plotly.figure_factory as ff -import numpy as np - -x1 = np.random.randn(200) - 2 -x2 = np.random.randn(200) -x3 = np.random.randn(200) + 2 - -hist_data = [x1, x2, x3] - -group_labels = ['Group 1', 'Group 2', 'Group 3'] -colors = ['#A56CC1', '#A6ACEC', '#63F5EF'] - -# Create distplot with curve_type set to 'normal' -fig = ff.create_distplot(hist_data, group_labels, colors=colors, - bin_size=.2, show_rug=False) - -# Add title -fig.update_layout(title_text='Hist and Curve Plot') -fig.show() -``` - -#### Distplot with Pandas - -```python -import plotly.figure_factory as ff -import numpy as np -import pandas as pd - -df = pd.DataFrame({'2012': np.random.randn(200), - '2013': np.random.randn(200)+1}) -fig = ff.create_distplot([df[c] for c in df.columns], df.columns, bin_size=.25) -fig.show() -``` - -#### Reference - - -For more info on `ff.create_distplot()`, see the [full function reference](https://plotly.com/python-api-reference/generated/plotly.figure_factory.create_distplot.html) diff --git a/doc/python/figure-factories.md b/doc/python/figure-factories.md index 20fadd7c818..814da7a2b29 100644 --- a/doc/python/figure-factories.md +++ b/doc/python/figure-factories.md @@ -35,7 +35,7 @@ jupyter: #### `plotly.figure_factory` -The `plotly.figure_factory` module contains dedicated functions for creating very specific types of plots that were at the time of their creation difficult to create with [graph objects](/python/graph-objects/) and prior to the existence of [Plotly Express](/python/plotly-express/). As new functionality gets added to [Plotly.js](https://plotly.com/javascript/) and to Plotly Express, certain Figure Factories become unnecessary and are therefore deprecated as "legacy", but remain in the module for backwards-compatibility reasons. +The `plotly.figure_factory` module contains dedicated functions for creating very specific types of plots that were at the time of their creation difficult to create with [graph objects](/python/graph-objects/) and prior to the existence of [Plotly Express](/python/plotly-express/). As new functionality gets added to [Plotly.js](https://plotly.com/javascript/) and to Plotly Express, certain Figure Factories become unnecessary and have therefore been removed. The following types of plots are still difficult to create with Graph Objects or Plotly Express and therefore the corresponding Figure Factories are *not* deprecated: @@ -47,12 +47,20 @@ The following types of plots are still difficult to create with Graph Objects or * [Ternary Contour Plots](/python/ternary-contour/) * [Triangulated Surface Plots](/python/trisurf/) -Deprecated "legacy" Figure Factories include: +The following "legacy" Figure Factories have been removed. Use the recommended alternative instead: - * [Annotated Heatmaps](/python/annotated-heatmap/), deprecated by [heatmaps with `px.imshow()`](/python/heatmaps/) - * [County Choropleth Maps](/python/county-choropleth/), deprecated by regular [Choropleth maps with GeoJSON input](/python/choropleth-maps/) - * [Distplots](/python/distplot/), mostly deprecated by [`px.histogram`](/python/histograms/) except for KDE plots, which `px.histogram` doesn't support yet - * [Gantt Charts](/python/gantt/), deprecated by [`px.timeline`](/python/gantt/) + * `create_2d_density`: use [`px.density_heatmap`](/python/2D-Histogram/) + * `create_annotated_heatmap`: use [`px.imshow`](/python/heatmaps/) + * `create_bullet`: use [`go.Indicator`](/python/indicator/) + * `create_candlestick`: use [`go.Candlestick`](/python/candlestick-charts/) + * `create_choropleth`: use [`px.choropleth`](/python/choropleth-maps/) with custom GeoJSON + * `create_distplot`: use [Plotly Express](/python/plotly-express/) functions like [`px.histogram`](/python/histograms/) + * `create_facet_grid`: use [Plotly Express](/python/plotly-express/) functions with the [`facet_row` and `facet_col` arguments](/python/facet-plots/) + * `create_gantt`: use [`px.timeline`](/python/gantt/) + * `create_hexbin_mapbox`: use [`create_hexbin_map`](/python/hexbin-mapbox/) + * `create_ohlc`: use [`go.Ohlc`](/python/ohlc-charts/) + * `create_scatterplotmatrix`: use [`go.Splom`](/python/splom/) + * `create_violin`: use [`go.Violin`](/python/violin/) #### Reference diff --git a/doc/python/gantt.md b/doc/python/gantt.md index 33908bf139a..586099e9e0e 100644 --- a/doc/python/gantt.md +++ b/doc/python/gantt.md @@ -109,66 +109,3 @@ df = pd.DataFrame([ fig = px.timeline(df, x_start="Start", x_end="Finish", y="Resource", color="Resource") fig.show() ``` - -#### Deprecated Figure Factory - -Prior to the introduction of `plotly.express.timeline()` in version 4.9, the recommended way to make Gantt charts was to use the now-deprecated `create_gantt()` [figure factory](/python/figure-factories/), as follows: - -```python -import plotly.figure_factory as ff - -df = [dict(Task="Job A", Start='2009-01-01', Finish='2009-02-28'), - dict(Task="Job B", Start='2009-03-05', Finish='2009-04-15'), - dict(Task="Job C", Start='2009-02-20', Finish='2009-05-30')] - -fig = ff.create_gantt(df) -fig.show() -``` - - -#### Group Tasks Together - - -The following example shows how to use the now-deprecated `create_gantt()` [figure factory](/python/figure-factories/) to color tasks by a numeric variable. - - -```python -import plotly.figure_factory as ff - -df = [dict(Task="Job-1", Start='2017-01-01', Finish='2017-02-02', Resource='Complete'), - dict(Task="Job-1", Start='2017-02-15', Finish='2017-03-15', Resource='Incomplete'), - dict(Task="Job-2", Start='2017-01-17', Finish='2017-02-17', Resource='Not Started'), - dict(Task="Job-2", Start='2017-01-17', Finish='2017-02-17', Resource='Complete'), - dict(Task="Job-3", Start='2017-03-10', Finish='2017-03-20', Resource='Not Started'), - dict(Task="Job-3", Start='2017-04-01', Finish='2017-04-20', Resource='Not Started'), - dict(Task="Job-3", Start='2017-05-18', Finish='2017-06-18', Resource='Not Started'), - dict(Task="Job-4", Start='2017-01-14', Finish='2017-03-14', Resource='Complete')] - -colors = {'Not Started': 'rgb(220, 0, 0)', - 'Incomplete': (1, 0.9, 0.16), - 'Complete': 'rgb(0, 255, 100)'} - -fig = ff.create_gantt(df, colors=colors, index_col='Resource', show_colorbar=True, - group_tasks=True) -fig.show() -``` - -#### Color by Numeric Variable - -The following example shows how to use the now-deprecated `create_gantt()` [figure factory](/python/figure-factories/) to color tasks by a numeric variable. - -```python -import plotly.figure_factory as ff - -df = [dict(Task="Job A", Start='2009-01-01', Finish='2009-02-28', Complete=10), - dict(Task="Job B", Start='2008-12-05', Finish='2009-04-15', Complete=60), - dict(Task="Job C", Start='2009-02-20', Finish='2009-05-30', Complete=95)] - -fig = ff.create_gantt(df, colors='Viridis', index_col='Complete', show_colorbar=True) -fig.show() -``` - -#### Reference - - -For more info on `ff.create_gantt()`, see the [full function reference](https://plotly.com/python-api-reference/generated/plotly.figure_factory.create_gantt.html) diff --git a/doc/python/getting-started.md b/doc/python/getting-started.md index c50cceff19e..f9d21def422 100644 --- a/doc/python/getting-started.md +++ b/doc/python/getting-started.md @@ -200,24 +200,6 @@ or conda. $ conda install -c plotly python-kaleido ``` -#### Extended Geo Support - -Some plotly.py features rely on fairly large geographic shape files. The county -choropleth figure factory is one such example. These shape files are distributed as a -separate `plotly-geo` package. This package can be installed using pip... - -``` -$ pip install plotly-geo==1.0.0 -``` - -or conda. - -``` -$ conda install -c plotly plotly-geo=1.0.0 -``` - -See [_USA County Choropleth Maps in Python_](/python/county-choropleth/) for more information on the county choropleth figure factory. - ### Where to next? Once you've installed, you can use our documentation in three main ways: diff --git a/doc/python/hexbin-mapbox.md b/doc/python/hexbin-mapbox.md index 079b337f952..164f5d68e2c 100644 --- a/doc/python/hexbin-mapbox.md +++ b/doc/python/hexbin-mapbox.md @@ -156,4 +156,4 @@ fig.show() #### Reference -For more info on Plotly maps, see: https://plotly.com/python/maps.
For more info on using colorscales with Plotly see: https://plotly.com/python/heatmap-and-contour-colorscales/
For more info on `ff.create_annotated_heatmap()`, see the [full function reference](https://plotly.com/python-api-reference/generated/plotly.figure_factory.create_hexbin_mapbox.html#plotly.figure_factory.create_hexbin_mapbox) +For more info on Plotly maps, see: https://plotly.com/python/maps.
For more info on using colorscales with Plotly see: https://plotly.com/python/heatmap-and-contour-colorscales/
For more info on `ff.create_hexbin_map()`, see the [full function reference](https://plotly.com/python-api-reference/generated/plotly.figure_factory.create_hexbin_map.html#plotly.figure_factory.create_hexbin_map) diff --git a/doc/unconverted/python/basic-statistics.md b/doc/unconverted/python/basic-statistics.md index fc422efd72f..d8c9d0765aa 100644 --- a/doc/unconverted/python/basic-statistics.md +++ b/doc/unconverted/python/basic-statistics.md @@ -104,7 +104,24 @@ We can visualize these statistics by producing a Plotly box or Violin chart. ```python y = data['alcohol'].values.tolist() -fig = FF.create_violin(y, title='Violin Plot', colors='#604d9e') +trace = go.Violin( + y=y, + name='Violin Plot', + box_visible=True, + meanline_visible=True, + fillcolor='#604d9e', + points='all', +) + +layout = go.Layout( + width=500, + yaxis=dict( + title='Alcohol Consumption by Country', + zeroline=False + ), +) + +fig = go.Figure(data=[trace], layout=layout) py.iplot(fig, filename='alcohol-violin-visual') ``` diff --git a/doc/unconverted/python/density-plots.md b/doc/unconverted/python/density-plots.md deleted file mode 100644 index 5ad4494e0d7..00000000000 --- a/doc/unconverted/python/density-plots.md +++ /dev/null @@ -1,117 +0,0 @@ ---- -jupyter: - jupytext: - notebook_metadata_filter: all - text_representation: - extension: .md - format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.1 - kernelspec: - display_name: Python 2 - language: python - name: python2 - plotly: - description: How to make a 2d density plot in python. Examples of density plots - with kernel density estimations, custom color-scales, and smoothing. - display_as: statistical - language: python - layout: base - name: 2d Density Plots - order: 7 - page_type: u-guide - permalink: python/density-plots/ - thumbnail: thumbnail/density.gif ---- - - -#### New to Plotly? -Plotly's Python library is free and open source! [Get started](https://plot.ly/python/getting-started/) by downloading the client and [reading the primer](https://plot.ly/python/getting-started/). -
You can set up Plotly to work in [online](https://plot.ly/python/getting-started/#initialization-for-online-plotting) or [offline](https://plot.ly/python/getting-started/#initialization-for-offline-plotting) mode, or in [jupyter notebooks](https://plot.ly/python/getting-started/#start-plotting-online). -
We also have a quick-reference [cheatsheet](https://images.plot.ly/plotly-documentation/images/python_cheat_sheet.pdf) (new!) to help you get started! - - - -#### Version Check -Note: 2D Density Plots are available in version 2.0.0+
-Run `pip install plotly --upgrade` to update your Plotly version - - -```python deletable=true editable=true -import plotly -plotly.__version__ -``` - - -#### 2D Histogram Contour Plot with Histogram Subplots - - -```python deletable=true editable=true -import plotly.plotly as py -import plotly.figure_factory as ff - -import numpy as np - -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)) - -colorscale = ['#7A4579', '#D56073', 'rgb(236,158,105)', (1, 1, 0.2), (0.98,0.98,0.98)] - -fig = ff.create_2d_density( - x, y, colorscale=colorscale, - hist_color='rgb(255, 237, 222)', point_size=3 -) - -py.iplot(fig, filename='histogram_subplots') -``` - - -#### 2D Histogram Contour Plot with Slider Control - - - -https://jsfiddle.net/plotlygraphs/y9sdy76h/4/embedded/result,js,html/ - - - -Add slider controls to 2d-density-plot plots with the postMessage API. - -See the code on JSFiddle. - -Watch the 5 second video of how it works: - - - -![IPython terminal](https://raw.githubusercontent.com/plotly/documentation/gh-pages/all_static/images/flight_conflicts.gif) - - - -#### Reference - - -```python deletable=true editable=true -help(ff.create_2d_density) -``` - -```python deletable=true editable=true -from IPython.display import display, HTML - -display(HTML('')) -display(HTML('')) - -! pip install git+https://github.com/plotly/publisher.git --upgrade -import publisher -publisher.publish( - 'density-plots.ipynb', 'python/density-plots/', 'Python 2d Density Plots | plotly', - 'How to make a 2d density plot in python. Examples of density plots with kernel density estimations, custom color-scales, and smoothing.', - title='Python 2d Density Plots | plotly', - name='2d Density Plots', - thumbnail='thumbnail/density.gif', language='python', - has_thumbnail='true', display_as='statistical', order=7, - ipynb= '~notebook_demo/25') -``` - -```python deletable=true editable=true - -``` diff --git a/doc/unconverted/python/linear-algebra.md b/doc/unconverted/python/linear-algebra.md index 35fb7a7ac29..2affe3312d6 100644 --- a/doc/unconverted/python/linear-algebra.md +++ b/doc/unconverted/python/linear-algebra.md @@ -61,12 +61,7 @@ matrix2 = np.matrix( ) matrix_sum = matrix1 + matrix2 - -colorscale = [[0, '#EAEFC4'], [1, '#9BDF46']] -font=['#000000', '#000000'] - -table = FF.create_annotated_heatmap(matrix_sum.tolist(), colorscale=colorscale, font_colors=font) -py.iplot(table, filename='matrix-sum') +matrix_sum ``` #### Multiply Two Matrices @@ -84,12 +79,7 @@ matrix2 = np.matrix( ) matrix_prod = matrix1 * matrix2 - -colorscale = [[0, '#F1FFD9'], [1, '#8BDBF5']] -font=['#000000', '#000000'] - -table = FF.create_annotated_heatmap(matrix_prod.tolist(), colorscale=colorscale, font_colors=font) -py.iplot(table, filename='matrix-prod') +matrix_prod ``` #### Solve Matrix Equation @@ -107,12 +97,7 @@ B = np.matrix( ) X = np.linalg.solve(A, B) - -colorscale = [[0, '#497285'], [1, '#DFEBED']] -font=['#000000', '#000000'] - -table = FF.create_annotated_heatmap(X.tolist(), colorscale=colorscale, font_colors=font) -py.iplot(table, filename='matrix-eq') +X ``` #### Find the Determinant @@ -136,12 +121,7 @@ matrix = np.matrix( ) inverse = np.linalg.inv(matrix) - -colorscale = [[0, '#F1FAFB'], [1, '#A0E4F1']] -font=['#000000', '#000000'] - -table = FF.create_annotated_heatmap(inverse.tolist(), colorscale=colorscale, font_colors=font) -py.iplot(table, filename='inverse') +inverse ``` #### Find Eigenvalues diff --git a/doc/unconverted/python/statistics-charts.md b/doc/unconverted/python/statistics-charts.md index f4fffcede6c..90fb1435eb2 100644 --- a/doc/unconverted/python/statistics-charts.md +++ b/doc/unconverted/python/statistics-charts.md @@ -86,19 +86,6 @@ data = [ py.iplot(data, filename='wind-data-box-plot') ``` -#### Scatterplot Matrix - - -We will be producing a `scatterplot matrix` with all the columns of our data. For more info on the histogram charts, you can checkout the [documentation page](https://plot.ly/python/scatterplot-matrix/). - -```python -fig = FF.create_scatterplotmatrix(wind_data, - height=1000, - width=1000, - title='Wind Data - Scatterplot Matrix') -py.iplot(fig, filename='wind-data-scatterplot-matrix') -``` - ```python from IPython.display import display, HTML diff --git a/doc/unconverted/python/webgl-text-and-annotations.md b/doc/unconverted/python/webgl-text-and-annotations.md index e018d35ef40..c55d289115f 100644 --- a/doc/unconverted/python/webgl-text-and-annotations.md +++ b/doc/unconverted/python/webgl-text-and-annotations.md @@ -36,7 +36,6 @@ Plotly's Python library is free and open source! [Get started](https://plot.ly/p import numpy as np import plotly.plotly as py import plotly.graph_objs as go -from plotly.figure_factory import create_annotated_heatmap n=250 From a203a2bed783311257064bf1b0ac6d95e3959047 Mon Sep 17 00:00:00 2001 From: Emily KL <4672118+emilykl@users.noreply.github.com> Date: Fri, 19 Jun 2026 10:57:30 -0400 Subject: [PATCH 6/8] remove plotly-geo, pyshp, and shapely dev dependencies (used by removed county-choropleth) --- README.md | 18 ---------- doc/requirements.txt | 3 -- pyproject.toml | 3 -- uv.lock | 82 -------------------------------------------- 4 files changed, 106 deletions(-) diff --git a/README.md b/README.md index 6ee878a7dfe..1f86173f319 100644 --- a/README.md +++ b/README.md @@ -125,24 +125,6 @@ or conda conda install -c conda-forge python-kaleido ``` -### Extended Geo Support - -Some plotly.py features rely on fairly large geographic shape files. The county -choropleth figure factory is one such example. These shape files are distributed as a -separate `plotly-geo` package. This package can be installed using pip... - -``` -pip install plotly-geo==1.0.0 -``` - -or conda - -``` -conda install -c plotly plotly-geo=1.0.0 -``` - -`plotly-geo` can be found on Github at https://github.com/plotly/plotly-geo. - ## Copyright and Licenses Code and documentation copyright 2019 Plotly, Inc. diff --git a/doc/requirements.txt b/doc/requirements.txt index c8f9a7bfeec..f80b22e528b 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -21,12 +21,10 @@ orjson pandas==1.4.0 pathlib patsy==0.5.6 -plotly-geo polars pooch psutil pyarrow -pyshp==2.1.2 python-frontmatter==1.1.0 recommonmark requests @@ -34,7 +32,6 @@ scikit-image==0.20.0 scikit-learn scipy==1.9.1 setuptools<=81 -shapely==2.0.5 sphinx==3.5.4 sphinx_bootstrap_theme sphinxcontrib-applehelp==1.0.2 diff --git a/pyproject.toml b/pyproject.toml index 41232d7febd..204927b2df5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -67,14 +67,11 @@ dev_optional = [ "pandas", "pdfrw", "pillow", - "plotly-geo", "polars[timezone]", "pyarrow", - "pyshp", "pytz", "scikit-image", "scipy", - "shapely", "statsmodels", "vaex;python_version<='3.9'", "xarray" diff --git a/uv.lock b/uv.lock index 8a4fb6dfbaf..c6f2fc8ac03 100644 --- a/uv.lock +++ b/uv.lock @@ -6680,15 +6680,12 @@ dev = [ { name = "pillow", version = "10.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, { name = "pillow", version = "11.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, { name = "pillow", version = "12.2.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, - { name = "plotly-geo" }, { name = "polars", version = "1.8.2", source = { registry = "https://pypi.org/simple" }, extra = ["timezone"], marker = "python_full_version < '3.9' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, { name = "polars", version = "1.36.1", source = { registry = "https://pypi.org/simple" }, extra = ["timezone"], marker = "python_full_version == '3.9.*' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, { name = "polars", version = "1.39.3", source = { registry = "https://pypi.org/simple" }, extra = ["timezone"], marker = "python_full_version >= '3.10' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, { name = "pyarrow", version = "17.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, { name = "pyarrow", version = "20.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, { name = "pyarrow", version = "23.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, - { name = "pyshp", version = "2.3.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, - { name = "pyshp", version = "3.0.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, { name = "pytest", version = "8.3.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, { name = "pytest", version = "8.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, { name = "pytest", version = "9.0.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, @@ -6705,8 +6702,6 @@ dev = [ { name = "scipy", version = "1.13.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, { name = "scipy", version = "1.15.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*' or (python_full_version >= '3.11' and extra == 'extra-6-plotly-dev-pandas1') or (python_full_version < '3.10' and extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (python_full_version < '3.10' and extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (python_full_version < '3.10' and extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3') or (python_full_version >= '3.11' and extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, { name = "scipy", version = "1.17.1", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.11' and extra != 'extra-6-plotly-dev-pandas1') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3')" }, - { name = "shapely", version = "2.0.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, - { name = "shapely", version = "2.1.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, { name = "statsmodels", version = "0.14.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, { name = "statsmodels", version = "0.14.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, { name = "vaex", version = "4.17.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, @@ -6768,15 +6763,12 @@ dev-optional = [ { name = "pillow", version = "10.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, { name = "pillow", version = "11.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, { name = "pillow", version = "12.2.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, - { name = "plotly-geo" }, { name = "polars", version = "1.8.2", source = { registry = "https://pypi.org/simple" }, extra = ["timezone"], marker = "python_full_version < '3.9' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, { name = "polars", version = "1.36.1", source = { registry = "https://pypi.org/simple" }, extra = ["timezone"], marker = "python_full_version == '3.9.*' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, { name = "polars", version = "1.39.3", source = { registry = "https://pypi.org/simple" }, extra = ["timezone"], marker = "python_full_version >= '3.10' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, { name = "pyarrow", version = "17.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, { name = "pyarrow", version = "20.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, { name = "pyarrow", version = "23.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, - { name = "pyshp", version = "2.3.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, - { name = "pyshp", version = "3.0.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, { name = "pytest", version = "8.3.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, { name = "pytest", version = "8.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, { name = "pytest", version = "9.0.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, @@ -6793,8 +6785,6 @@ dev-optional = [ { name = "scipy", version = "1.13.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, { name = "scipy", version = "1.15.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*' or (python_full_version >= '3.11' and extra == 'extra-6-plotly-dev-pandas1') or (python_full_version < '3.10' and extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (python_full_version < '3.10' and extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (python_full_version < '3.10' and extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3') or (python_full_version >= '3.11' and extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, { name = "scipy", version = "1.17.1", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.11' and extra != 'extra-6-plotly-dev-pandas1') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3')" }, - { name = "shapely", version = "2.0.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, - { name = "shapely", version = "2.1.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, { name = "statsmodels", version = "0.14.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, { name = "statsmodels", version = "0.14.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, { name = "vaex", version = "4.17.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9' or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2') or (extra == 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas3') or (extra == 'extra-6-plotly-dev-pandas2' and extra == 'extra-6-plotly-dev-pandas3')" }, @@ -6852,10 +6842,8 @@ requires-dist = [ { name = "plotly", extras = ["dev-optional"], marker = "extra == 'dev'" }, { name = "plotly", extras = ["express"], marker = "extra == 'dev-optional'" }, { name = "plotly", extras = ["kaleido"], marker = "extra == 'dev-optional'" }, - { name = "plotly-geo", marker = "extra == 'dev-optional'" }, { name = "polars", extras = ["timezone"], marker = "extra == 'dev-optional'" }, { name = "pyarrow", marker = "extra == 'dev-optional'" }, - { name = "pyshp", marker = "extra == 'dev-optional'" }, { name = "pytest", marker = "extra == 'dev-core'" }, { name = "pytz", marker = "extra == 'dev-optional'" }, { name = "requests", marker = "extra == 'dev-core'" }, @@ -6863,22 +6851,12 @@ requires-dist = [ { name = "scikit-image", marker = "extra == 'dev-optional'" }, { name = "scipy", marker = "extra == 'dev-optional'" }, { name = "setuptools", marker = "extra == 'dev-pandas1'", specifier = "<82" }, - { name = "shapely", marker = "extra == 'dev-optional'" }, { name = "statsmodels", marker = "extra == 'dev-optional'" }, { name = "vaex", marker = "python_full_version < '3.10' and extra == 'dev-optional'" }, { name = "xarray", marker = "extra == 'dev-optional'" }, ] provides-extras = ["express", "kaleido", "dev-core", "dev-build", "dev-optional", "dev", "dev-pandas1", "dev-pandas2", "dev-pandas3"] -[[package]] -name = "plotly-geo" -version = "1.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/35/4c/38d10312391d45a14048ce8e21deed2fff6ca66397c970a07412221e45dd/plotly-geo-1.0.0.tar.gz", hash = "sha256:422359c859fc1bccfd5baaffd82d23f4ea06686c1822e72f76270c9d7f82d70e", size = 23718591, upload-time = "2019-07-16T16:46:27.28Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/be/c6/be7d476e8c14c318c7b80329317d5dd5d1b876c393c9f8c0363b0dd188b8/plotly_geo-1.0.0-py3-none-any.whl", hash = "sha256:9f695ca0a48494c821d8ab612d33b092bc64ec8de86d021c5209cc0b217aa9ce", size = 23719997, upload-time = "2019-07-16T16:46:21.502Z" }, -] - [[package]] name = "pluggy" version = "1.5.0" @@ -8472,66 +8450,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl", hash = "sha256:9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913", size = 10216, upload-time = "2024-09-29T09:24:11.978Z" }, ] -[[package]] -name = "pyshp" -version = "2.3.1" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version > '3.8' and python_full_version < '3.9' and sys_platform == 'win32'", - "python_full_version <= '3.8' and sys_platform == 'win32'", - "python_full_version >= '3.8.1' and python_full_version < '3.9' and sys_platform != 'win32'", - "python_full_version > '3.8' and python_full_version < '3.8.1' and sys_platform != 'win32'", - "python_full_version <= '3.8' and sys_platform != 'win32'", -] -sdist = { url = "https://files.pythonhosted.org/packages/63/9f/0dd21250c60375a532c35e89fad8d5e8a3f1a2e3f7c389ccc5a60b05263e/pyshp-2.3.1.tar.gz", hash = "sha256:4caec82fd8dd096feba8217858068bacb2a3b5950f43c048c6dc32a3489d5af1", size = 1731544, upload-time = "2022-07-27T19:51:28.409Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/98/2f/68116db5b36b895c0450e3072b8cb6c2fac0359279b182ea97014d3c8ac0/pyshp-2.3.1-py2.py3-none-any.whl", hash = "sha256:67024c0ccdc352ba5db777c4e968483782dfa78f8e200672a90d2d30fd8b7b49", size = 46537, upload-time = "2022-07-27T19:51:26.34Z" }, -] - -[[package]] -name = "pyshp" -version = "3.0.3" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14' and sys_platform == 'win32' and extra != 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2' and extra != 'extra-6-plotly-dev-pandas3'", - "python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform == 'win32' and extra != 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2' and extra != 'extra-6-plotly-dev-pandas3'", - "python_full_version >= '3.14' and sys_platform != 'win32' and extra != 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2' and extra != 'extra-6-plotly-dev-pandas3'", - "python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform != 'win32' and extra != 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2' and extra != 'extra-6-plotly-dev-pandas3'", - "python_full_version == '3.11.*' and sys_platform == 'win32' and extra != 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2' and extra != 'extra-6-plotly-dev-pandas3'", - "python_full_version == '3.11.*' and sys_platform != 'win32' and extra != 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2' and extra != 'extra-6-plotly-dev-pandas3'", - "python_full_version == '3.10.*' and sys_platform == 'win32' and extra != 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2' and extra != 'extra-6-plotly-dev-pandas3'", - "python_full_version == '3.10.*' and sys_platform != 'win32' and extra != 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2' and extra != 'extra-6-plotly-dev-pandas3'", - "python_full_version == '3.9.*' and sys_platform == 'win32' and extra != 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2' and extra != 'extra-6-plotly-dev-pandas3'", - "python_full_version == '3.9.*' and sys_platform != 'win32' and extra != 'extra-6-plotly-dev-pandas1' and extra == 'extra-6-plotly-dev-pandas2' and extra != 'extra-6-plotly-dev-pandas3'", - "python_full_version >= '3.14' and sys_platform == 'win32' and extra == 'extra-6-plotly-dev-pandas1' and extra != 'extra-6-plotly-dev-pandas2' and extra != 'extra-6-plotly-dev-pandas3'", - "python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform == 'win32' and extra == 'extra-6-plotly-dev-pandas1' and extra != 'extra-6-plotly-dev-pandas2' and extra != 'extra-6-plotly-dev-pandas3'", - "python_full_version == '3.11.*' and sys_platform == 'win32' and extra == 'extra-6-plotly-dev-pandas1' and extra != 'extra-6-plotly-dev-pandas2' and extra != 'extra-6-plotly-dev-pandas3'", - "python_full_version >= '3.14' and sys_platform != 'win32' and extra == 'extra-6-plotly-dev-pandas1' and extra != 'extra-6-plotly-dev-pandas2' and extra != 'extra-6-plotly-dev-pandas3'", - "python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform != 'win32' and extra == 'extra-6-plotly-dev-pandas1' and extra != 'extra-6-plotly-dev-pandas2' and extra != 'extra-6-plotly-dev-pandas3'", - "python_full_version == '3.11.*' and sys_platform != 'win32' and extra == 'extra-6-plotly-dev-pandas1' and extra != 'extra-6-plotly-dev-pandas2' and extra != 'extra-6-plotly-dev-pandas3'", - "python_full_version == '3.10.*' and sys_platform == 'win32' and extra == 'extra-6-plotly-dev-pandas1' and extra != 'extra-6-plotly-dev-pandas2' and extra != 'extra-6-plotly-dev-pandas3'", - "python_full_version == '3.10.*' and sys_platform != 'win32' and extra == 'extra-6-plotly-dev-pandas1' and extra != 'extra-6-plotly-dev-pandas2' and extra != 'extra-6-plotly-dev-pandas3'", - "python_full_version == '3.9.*' and sys_platform == 'win32' and extra == 'extra-6-plotly-dev-pandas1' and extra != 'extra-6-plotly-dev-pandas2' and extra != 'extra-6-plotly-dev-pandas3'", - "python_full_version == '3.9.*' and sys_platform != 'win32' and extra == 'extra-6-plotly-dev-pandas1' and extra != 'extra-6-plotly-dev-pandas2' and extra != 'extra-6-plotly-dev-pandas3'", - "python_full_version >= '3.14' and sys_platform == 'win32' and extra != 'extra-6-plotly-dev-pandas1' and extra != 'extra-6-plotly-dev-pandas2'", - "python_full_version >= '3.14' and sys_platform == 'emscripten' and extra != 'extra-6-plotly-dev-pandas1' and extra != 'extra-6-plotly-dev-pandas2'", - "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-6-plotly-dev-pandas1' and extra != 'extra-6-plotly-dev-pandas2'", - "python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform == 'win32' and extra != 'extra-6-plotly-dev-pandas1' and extra != 'extra-6-plotly-dev-pandas2'", - "python_full_version == '3.11.*' and sys_platform == 'win32' and extra != 'extra-6-plotly-dev-pandas1' and extra != 'extra-6-plotly-dev-pandas2'", - "python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform == 'emscripten' and extra != 'extra-6-plotly-dev-pandas1' and extra != 'extra-6-plotly-dev-pandas2'", - "python_full_version == '3.11.*' and sys_platform == 'emscripten' and extra != 'extra-6-plotly-dev-pandas1' and extra != 'extra-6-plotly-dev-pandas2'", - "python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-6-plotly-dev-pandas1' and extra != 'extra-6-plotly-dev-pandas2'", - "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-6-plotly-dev-pandas1' and extra != 'extra-6-plotly-dev-pandas2'", - "python_full_version == '3.10.*' and sys_platform == 'win32' and extra != 'extra-6-plotly-dev-pandas1' and extra != 'extra-6-plotly-dev-pandas2'", - "python_full_version == '3.10.*' and sys_platform != 'win32' and extra != 'extra-6-plotly-dev-pandas1' and extra != 'extra-6-plotly-dev-pandas2'", - "python_full_version == '3.9.*' and sys_platform == 'win32' and extra != 'extra-6-plotly-dev-pandas1' and extra != 'extra-6-plotly-dev-pandas2'", - "python_full_version == '3.9.*' and sys_platform != 'win32' and extra != 'extra-6-plotly-dev-pandas1' and extra != 'extra-6-plotly-dev-pandas2'", -] -sdist = { url = "https://files.pythonhosted.org/packages/8c/20/8b07bae73aaa0c3f5a2683ba6e23b46e977e2d33a88126d56bbcc2d135cd/pyshp-3.0.3.tar.gz", hash = "sha256:bf4678b13dd53578ed87669676a2fffeccbcded1ec8ff9cafb36d1b660f4b305", size = 2192568, upload-time = "2025-11-28T17:47:31.616Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/82/06/cad54e8ce758bd836ee5411691cbd49efeb9cc611b374670fce299519334/pyshp-3.0.3-py3-none-any.whl", hash = "sha256:28c8fac8c0c25bb0fecbbfd10ead7f319c2ff2f3b0b44a94f22bd2c93510ad42", size = 58465, upload-time = "2025-11-28T17:47:30.328Z" }, -] - [[package]] name = "pytest" version = "8.3.5" From 6bfa2d4a445ba8e0473e120b50237d674b287eeb Mon Sep 17 00:00:00 2001 From: Emily KL <4672118+emilykl@users.noreply.github.com> Date: Fri, 19 Jun 2026 12:02:52 -0400 Subject: [PATCH 7/8] update metadata --- doc/python/hexbin-mapbox.md | 2 +- doc/python/location-mode.md | 2 +- doc/python/map-configuration.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/python/hexbin-mapbox.md b/doc/python/hexbin-mapbox.md index 164f5d68e2c..3744e8377bd 100644 --- a/doc/python/hexbin-mapbox.md +++ b/doc/python/hexbin-mapbox.md @@ -27,7 +27,7 @@ jupyter: language: python layout: base name: Hexbin Mapbox - order: 14 + order: 13 page_type: u-guide permalink: python/hexbin-mapbox/ thumbnail: thumbnail/hexbin_mapbox.jpg diff --git a/doc/python/location-mode.md b/doc/python/location-mode.md index ae8a53c42ff..32d6ff26cd1 100644 --- a/doc/python/location-mode.md +++ b/doc/python/location-mode.md @@ -28,7 +28,7 @@ jupyter: language: python layout: base name: Locations for Outline-based Maps - order: 15 + order: 14 page_type: example_index permalink: python/outline-map-locations/ thumbnail: thumbnail/choropleth.jpg diff --git a/doc/python/map-configuration.md b/doc/python/map-configuration.md index f7cee50282a..59831eaaffc 100644 --- a/doc/python/map-configuration.md +++ b/doc/python/map-configuration.md @@ -27,7 +27,7 @@ jupyter: language: python layout: base name: Map Configuration and Styling on Geo Maps - order: 13 + order: 12 page_type: u-guide permalink: python/map-configuration/ thumbnail: thumbnail/county-level-choropleth.jpg From bdfe6fd6c7b859a0225183070a6e318f873faed6 Mon Sep 17 00:00:00 2001 From: Emily KL <4672118+emilykl@users.noreply.github.com> Date: Fri, 19 Jun 2026 12:03:45 -0400 Subject: [PATCH 8/8] docs edits --- doc/python/figure-factories.md | 8 ++++---- doc/python/scatter-plots-on-maps.md | 2 +- doc/unconverted/python/linear-algebra.md | 9 +++++---- doc/unconverted/python/statistics-charts.md | 20 ++++++++++++++++++++ 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/doc/python/figure-factories.md b/doc/python/figure-factories.md index 814da7a2b29..6c39f43acc7 100644 --- a/doc/python/figure-factories.md +++ b/doc/python/figure-factories.md @@ -35,9 +35,9 @@ jupyter: #### `plotly.figure_factory` -The `plotly.figure_factory` module contains dedicated functions for creating very specific types of plots that were at the time of their creation difficult to create with [graph objects](/python/graph-objects/) and prior to the existence of [Plotly Express](/python/plotly-express/). As new functionality gets added to [Plotly.js](https://plotly.com/javascript/) and to Plotly Express, certain Figure Factories become unnecessary and have therefore been removed. +The `plotly.figure_factory` module contains dedicated functions for creating very specific types of plots that are difficult to create with [graph objects](/python/graph-objects/) and [Plotly Express](/python/plotly-express/). -The following types of plots are still difficult to create with Graph Objects or Plotly Express and therefore the corresponding Figure Factories are *not* deprecated: +The following plot types can be created with Figure Factory: * [Dendrograms](/python/dendrogram/) * [Hexagonal Binning Tile Map](/python/hexbin-mapbox/) @@ -47,7 +47,7 @@ The following types of plots are still difficult to create with Graph Objects or * [Ternary Contour Plots](/python/ternary-contour/) * [Triangulated Surface Plots](/python/trisurf/) -The following "legacy" Figure Factories have been removed. Use the recommended alternative instead: +The following legacy Figure Factory functions have been replaced by Plotly Express functions, or native Graph Objects trace types, and have been removed from the library in version 7.0. Use the recommended alternatives instead: * `create_2d_density`: use [`px.density_heatmap`](/python/2D-Histogram/) * `create_annotated_heatmap`: use [`px.imshow`](/python/heatmaps/) @@ -64,5 +64,5 @@ The following "legacy" Figure Factories have been removed. Use the recommended a #### Reference -For more information about the contents of `plotly.figure_factory`, including deprecated methods, please refer to our [API Reference documentation](https://plotly.com/python-api-reference/plotly.figure_factory.html). +For more information about the contents of `plotly.figure_factory`, please refer to our [API Reference documentation](https://plotly.com/python-api-reference/plotly.figure_factory.html). diff --git a/doc/python/scatter-plots-on-maps.md b/doc/python/scatter-plots-on-maps.md index dfdcd1662cd..2d358418115 100644 --- a/doc/python/scatter-plots-on-maps.md +++ b/doc/python/scatter-plots-on-maps.md @@ -28,7 +28,7 @@ jupyter: language: python layout: base name: Scatter Plots on Maps - order: 12 + order: 11 page_type: u-guide permalink: python/scatter-plots-on-maps/ thumbnail: thumbnail/scatter-plot-on-maps.jpg diff --git a/doc/unconverted/python/linear-algebra.md b/doc/unconverted/python/linear-algebra.md index 2affe3312d6..af16afadf4d 100644 --- a/doc/unconverted/python/linear-algebra.md +++ b/doc/unconverted/python/linear-algebra.md @@ -36,6 +36,7 @@ The tutorial below imports [NumPy](http://www.numpy.org/), [Pandas](https://plot ```python import plotly.plotly as py +import plotly.express as px import plotly.graph_objs as go from plotly.tools import FigureFactory as FF @@ -61,7 +62,7 @@ matrix2 = np.matrix( ) matrix_sum = matrix1 + matrix2 -matrix_sum +px.imshow(matrix_sum, text_auto=True) ``` #### Multiply Two Matrices @@ -79,7 +80,7 @@ matrix2 = np.matrix( ) matrix_prod = matrix1 * matrix2 -matrix_prod +px.imshow(matrix_prod, text_auto=True) ``` #### Solve Matrix Equation @@ -97,7 +98,7 @@ B = np.matrix( ) X = np.linalg.solve(A, B) -X +px.imshow(X, text_auto=True) ``` #### Find the Determinant @@ -121,7 +122,7 @@ matrix = np.matrix( ) inverse = np.linalg.inv(matrix) -inverse +px.imshow(inverse, text_auto=True) ``` #### Find Eigenvalues diff --git a/doc/unconverted/python/statistics-charts.md b/doc/unconverted/python/statistics-charts.md index 90fb1435eb2..c584532c0b2 100644 --- a/doc/unconverted/python/statistics-charts.md +++ b/doc/unconverted/python/statistics-charts.md @@ -86,6 +86,26 @@ data = [ py.iplot(data, filename='wind-data-box-plot') ``` +#### Scatterplot Matrix (SPLOM) + + +We will be producing a scatterplot matrix chart, also known as a SPLOM chart, with all the columns of our data. For more info on SPLOM traces, you can checkout the [documentation page](https://plot.ly/python/splom/). + +```python +fig = go.Figure(data=go.Splom( + dimensions=[ + dict(label=col, values=wind_data[col]) for col in wind_data.columns + ] +)) + +fig.update_layout( + title='Wind Data - Scatterplot Matrix', + height=1000, + width=1000, +) +py.iplot(fig, filename='wind-data-scatterplot-matrix') +``` + ```python from IPython.display import display, HTML