def map_face2color(face, colormap, scale, vmin, vmax):
    """
    Normalize facecolor values by vmin/vmax and return rgb-color strings

    This function takes a tuple color along with a colormap and a minimum
    (vmin) and maximum (vmax) range of possible mean distances for the
    given parametrized surface. It returns an rgb color based on the mean
    distance between vmin and vmax

    """
    if vmin >= vmax:
        raise exceptions.PlotlyError("Incorrect relation between vmin "
                                     "and vmax. The vmin value cannot be "
                                     "bigger than or equal to the value "
                                     "of vmax.")
    if len(colormap) == 1:
        # color each triangle face with the same color in colormap
        face_color = colormap[0]
        face_color = colors.convert_to_RGB_255(face_color)
        face_color = colors.label_rgb(face_color)
        return face_color
    if face == vmax:
        # pick last color in colormap
        face_color = colormap[-1]
        face_color = colors.convert_to_RGB_255(face_color)
        face_color = colors.label_rgb(face_color)
        return face_color
    else:
        if scale is None:
            # find the normalized distance t of a triangle face between
            # vmin and vmax where the distance is between 0 and 1
            t = (face - vmin) / float((vmax - vmin))
            low_color_index = int(t / (1. / (len(colormap) - 1)))

            face_color = colors.find_intermediate_color(
                colormap[low_color_index], colormap[low_color_index + 1],
                t * (len(colormap) - 1) - low_color_index)

            face_color = colors.convert_to_RGB_255(face_color)
            face_color = colors.label_rgb(face_color)
        else:
            # find the face color for a non-linearly interpolated scale
            t = (face - vmin) / float((vmax - vmin))

            low_color_index = 0
            for k in range(len(scale) - 1):
                if scale[k] <= t < scale[k + 1]:
                    break
                low_color_index += 1

            low_scale_val = scale[low_color_index]
            high_scale_val = scale[low_color_index + 1]

            face_color = colors.find_intermediate_color(
                colormap[low_color_index], colormap[low_color_index + 1],
                (t - low_scale_val) / (high_scale_val - low_scale_val))

            face_color = colors.convert_to_RGB_255(face_color)
            face_color = colors.label_rgb(face_color)
        return face_color
Example #2
0
def get_color(colorscale, nu, ex_=()):

    if len(ex_) == 2:

        mi, ma = ex_

        if mi == nu == ma:

            nu = 0

        else:

            nu = _scale(mi, nu, ma)

    for ie in range(len(colorscale) - 1):

        fr1, co1 = colorscale[ie]

        fr2, co2 = colorscale[ie + 1]

        if fr1 <= nu <= fr2:

            return find_intermediate_color(
                *convert_colors_to_same_type([co1, co2])[0],
                _scale(fr1, nu, fr2),
                colortype="rgb",
            )
Example #3
0
def _colors(ncontours, colormap=None):
    """
    Return a list of ``ncontours`` colors from the ``colormap`` colorscale.
    """
    if colormap in clrs.PLOTLY_SCALES.keys():
        cmap = clrs.PLOTLY_SCALES[colormap]
    else:
        raise exceptions.PlotlyError(
            "Colorscale must be a valid Plotly Colorscale."
            "The available colorscale names are {}".format(
                clrs.PLOTLY_SCALES.keys()))
    values = np.linspace(0, 1, ncontours)
    vals_cmap = np.array([pair[0] for pair in cmap])
    cols = np.array([pair[1] for pair in cmap])
    inds = np.searchsorted(vals_cmap, values)
    if "#" in cols[0]:  # for Viridis
        cols = [clrs.label_rgb(clrs.hex_to_rgb(col)) for col in cols]

    colors = [cols[0]]
    for ind, val in zip(inds[1:], values[1:]):
        val1, val2 = vals_cmap[ind - 1], vals_cmap[ind]
        interm = (val - val1) / (val2 - val1)
        col = clrs.find_intermediate_color(cols[ind - 1],
                                           cols[ind],
                                           interm,
                                           colortype="rgb")
        colors.append(col)
    return colors
def _colors(ncontours, colormap=None):
    """
    Return a list of ``ncontours`` colors from the ``colormap`` colorscale.
    """
    if colormap in clrs.PLOTLY_SCALES.keys():
        cmap = clrs.PLOTLY_SCALES[colormap]
    else:
        raise exceptions.PlotlyError(
            "Colorscale must be a valid Plotly Colorscale."
            "The available colorscale names are {}".format(
                clrs.PLOTLY_SCALES.keys()))
    values = np.linspace(0, 1, ncontours)
    vals_cmap = np.array([pair[0] for pair in cmap])
    cols = np.array([pair[1] for pair in cmap])
    inds = np.searchsorted(vals_cmap, values)
    if '#' in cols[0]:  # for Viridis
        cols = [clrs.label_rgb(clrs.hex_to_rgb(col)) for col in cols]

    colors = [cols[0]]
    for ind, val in zip(inds[1:], values[1:]):
        val1, val2 = vals_cmap[ind - 1], vals_cmap[ind]
        interm = (val - val1) / (val2 - val1)
        col = clrs.find_intermediate_color(cols[ind - 1],
                                           cols[ind], interm,
                                           colortype='rgb')
        colors.append(col)
    return colors
Example #5
0
def get_colors_from_colorscale(color_candidates: dict):
    """Assign a color to each dict entry"""
    color_scale = PLOTLY_SCALES['Rainbow']
    color_scale_floats = [i[0] for i in color_scale]
    color_scale_rgbs = [i[1] for i in color_scale]
    color_scale = {k: v for k, v in PLOTLY_SCALES['Rainbow']}
    float_rgb_dict = dict()
    for k, v in color_candidates.items():
        if v in color_scale_floats:
            float_rgb_dict[k] = color_scale[v]
        else:
            for i, s_v in enumerate(color_scale_floats):
                if v < s_v:
                    float_rgb_dict[k] = find_intermediate_color(
                        color_scale_rgbs[i - 1], color_scale_rgbs[i], v, 'rgb')
                    break
    return float_rgb_dict
Example #6
0
def get_colors_from_name(colormapname, numbervalues, reverse=False):

    plotly_colors, plotly_scale = colors.convert_colors_to_same_type(colormapname)
    if reverse:
        plotly_colors.reverse()
    plotly_scale = np.array(plotly_scale)

    plotly_colors = np.array(list(map(literal_eval, [color[3:] for color in plotly_colors])))/255.0
    vmin = 0
    vmax = numbervalues
    values = np.arange(0, vmax)
    v = (values - vmin)/(vmax - vmin)
    closest_indices = [sorted(np.argsort(np.abs(plotly_scale - i))[0:2])  for i in v]
    newcolors = [colors.find_intermediate_color(plotly_colors[indices[0]], plotly_colors[indices[1]], value)
                  for indices, value in zip(closest_indices, v)]
    newcolors = [colors.label_rgb(colors.convert_to_RGB_255(i)) for i in newcolors]

    return newcolors
def get_color_at(colorscale: ColorScaleTy, offset: float) -> str:
    """
    Plotly continuous colorscales assign colors to the range [0, 1]. This
    function computes the intermediate color for any value in that range.

    Args:
        colorscale:
            a plotly continuous colorscale defined with RGB string colors
        offset: value in the range [0, 1]
    Returns:
        color in rgb string format
    """
    if len(colorscale) < 1:
        raise ValueError("colorscale must have at least one color")

    if offset <= 0 or len(colorscale) == 1:
        return str(colors.convert_colors_to_same_type(colorscale[0][1])[0][0])
    if offset >= 1:
        return str(colors.convert_colors_to_same_type(colorscale[-1][1])[0][0])

    low_color = high_color = ""
    for cutoff, color in colorscale:
        if offset > float(cutoff):
            low_cutoff, low_color = float(cutoff), str(color)
        else:
            high_cutoff, high_color = float(cutoff), str(color)
            break

    low_color = colors.convert_colors_to_same_type(low_color)[0][0]
    high_color = colors.convert_colors_to_same_type(high_color)[0][0]

    # noinspection PyUnboundLocalVariable
    return str(
        colors.find_intermediate_color(
            lowcolor=low_color,
            highcolor=high_color,
            intermed=((offset - low_cutoff) / (high_cutoff - low_cutoff)),
            colortype="rgb"
        )
    )
Example #8
0
def get_color(colorscale: ColorScaleType, midpoint: float) -> str:
    """Given a colorscale, it interpolates the expected color at a given
    midpoint, on a scale from 0 to 1."""
    if 0 > midpoint > 1:
        raise ValueError(
            f"The 'midpoint' should be a float value between 0 and 1, not {midpoint}."
        )
    scale = [s for s, _ in colorscale]
    colors = [_any_to_rgb(c) for _, c in colorscale]
    del colorscale
    if midpoint in scale:
        return colors[scale.index(midpoint)]
    ceil = min(filter(lambda s: s > midpoint, scale))
    floor = max(filter(lambda s: s < midpoint, scale))
    midpoint_normalised = normalise(midpoint, min_=floor, max_=ceil)
    color: str = find_intermediate_color(
        lowcolor=colors[scale.index(floor)],
        highcolor=colors[scale.index(ceil)],
        intermed=midpoint_normalised,
        colortype="rgb",
    )
    return color
def create_choropleth(fips,
                      values,
                      scope=["usa"],
                      binning_endpoints=None,
                      colorscale=None,
                      order=None,
                      simplify_county=0.02,
                      simplify_state=0.02,
                      asp=None,
                      show_hover=True,
                      show_state_data=True,
                      state_outline=None,
                      county_outline=None,
                      centroid_marker=None,
                      round_legend_values=False,
                      exponent_format=False,
                      legend_title="",
                      **layout_options):
    """
    Returns figure for county choropleth. Uses data from package_data.

    :param (list) fips: list of FIPS values which correspond to the con
        catination of state and county ids. An example is '01001'.
    :param (list) values: list of numbers/strings which correspond to the
        fips list. These are the values that will determine how the counties
        are colored.
    :param (list) scope: list of states and/or states abbreviations. Fits
        all states in the camera tightly. Selecting ['usa'] is the equivalent
        of appending all 50 states into your scope list. Selecting only 'usa'
        does not include 'Alaska', 'Puerto Rico', 'American Samoa',
        'Commonwealth of the Northern Mariana Islands', 'Guam',
        'United States Virgin Islands'. These must be added manually to the
        list.
        Default = ['usa']
    :param (list) binning_endpoints: ascending numbers which implicitly define
        real number intervals which are used as bins. The colorscale used must
        have the same number of colors as the number of bins and this will
        result in a categorical colormap.
    :param (list) colorscale: a list of colors with length equal to the
        number of categories of colors. The length must match either all
        unique numbers in the 'values' list or if endpoints is being used, the
        number of categories created by the endpoints.\n
        For example, if binning_endpoints = [4, 6, 8], then there are 4 bins:
        [-inf, 4), [4, 6), [6, 8), [8, inf)
    :param (list) order: a list of the unique categories (numbers/bins) in any
        desired order. This is helpful if you want to order string values to
        a chosen colorscale.
    :param (float) simplify_county: determines the simplification factor
        for the counties. The larger the number, the fewer vertices and edges
        each polygon has. See
        http://toblerity.org/shapely/manual.html#object.simplify for more
        information.
        Default = 0.02
    :param (float) simplify_state: simplifies the state outline polygon.
        See http://toblerity.org/shapely/manual.html#object.simplify for more
        information.
        Default = 0.02
    :param (float) asp: the width-to-height aspect ratio for the camera.
        Default = 2.5
    :param (bool) show_hover: show county hover and centroid info
    :param (bool) show_state_data: reveals state boundary lines
    :param (dict) state_outline: dict of attributes of the state outline
        including width and color. See
        https://plot.ly/python/reference/#scatter-marker-line for all valid
        params
    :param (dict) county_outline: dict of attributes of the county outline
        including width and color. See
        https://plot.ly/python/reference/#scatter-marker-line for all valid
        params
    :param (dict) centroid_marker: dict of attributes of the centroid marker.
        The centroid markers are invisible by default and appear visible on
        selection. See https://plot.ly/python/reference/#scatter-marker for
        all valid params
    :param (bool) round_legend_values: automatically round the numbers that
        appear in the legend to the nearest integer.
        Default = False
    :param (bool) exponent_format: if set to True, puts numbers in the K, M,
        B number format. For example 4000.0 becomes 4.0K
        Default = False
    :param (str) legend_title: title that appears above the legend
    :param **layout_options: a **kwargs argument for all layout parameters


    Example 1: Florida
    ```
    import plotly.plotly as py
    import plotly.figure_factory as ff

    import numpy as np
    import pandas as pd

    df_sample = pd.read_csv(
        'https://raw.githubusercontent.com/plotly/datasets/master/minoritymajority.csv'
    )
    df_sample_r = df_sample[df_sample['STNAME'] == 'Florida']

    values = df_sample_r['TOT_POP'].tolist()
    fips = df_sample_r['FIPS'].tolist()

    binning_endpoints = list(np.mgrid[min(values):max(values):4j])
    colorscale = ["#030512","#1d1d3b","#323268","#3d4b94","#3e6ab0",
                  "#4989bc","#60a7c7","#85c5d3","#b7e0e4","#eafcfd"]
    fig = ff.create_choropleth(
        fips=fips, values=values, scope=['Florida'], show_state_data=True,
        colorscale=colorscale, binning_endpoints=binning_endpoints,
        round_legend_values=True, plot_bgcolor='rgb(229,229,229)',
        paper_bgcolor='rgb(229,229,229)', legend_title='Florida Population',
        county_outline={'color': 'rgb(255,255,255)', 'width': 0.5},
        exponent_format=True,
    )
    py.iplot(fig, filename='choropleth_florida')
    ```

    Example 2: New England
    ```
    import plotly.plotly as py
    import plotly.figure_factory as ff

    import pandas as pd

    NE_states = ['Connecticut', 'Maine', 'Massachusetts',
                 'New Hampshire', 'Rhode Island']
    df_sample = pd.read_csv(
        'https://raw.githubusercontent.com/plotly/datasets/master/minoritymajority.csv'
    )
    df_sample_r = df_sample[df_sample['STNAME'].isin(NE_states)]
    colorscale = ['rgb(68.0, 1.0, 84.0)',
     'rgb(66.0, 64.0, 134.0)',
     'rgb(38.0, 130.0, 142.0)',
     'rgb(63.0, 188.0, 115.0)',
     'rgb(216.0, 226.0, 25.0)']

    values = df_sample_r['TOT_POP'].tolist()
    fips = df_sample_r['FIPS'].tolist()
    fig = ff.create_choropleth(
        fips=fips, values=values, scope=NE_states, show_state_data=True
    )
    py.iplot(fig, filename='choropleth_new_england')
    ```

    Example 3: California and Surrounding States
    ```
    import plotly.plotly as py
    import plotly.figure_factory as ff

    import pandas as pd

    df_sample = pd.read_csv(
        'https://raw.githubusercontent.com/plotly/datasets/master/minoritymajority.csv'
    )
    df_sample_r = df_sample[df_sample['STNAME'] == 'California']

    values = df_sample_r['TOT_POP'].tolist()
    fips = df_sample_r['FIPS'].tolist()

    colorscale = [
        'rgb(193, 193, 193)',
        'rgb(239,239,239)',
        'rgb(195, 196, 222)',
        'rgb(144,148,194)',
        'rgb(101,104,168)',
        'rgb(65, 53, 132)'
    ]

    fig = ff.create_choropleth(
        fips=fips, values=values, colorscale=colorscale,
        scope=['CA', 'AZ', 'Nevada', 'Oregon', ' Idaho'],
        binning_endpoints=[14348, 63983, 134827, 426762, 2081313],
        county_outline={'color': 'rgb(255,255,255)', 'width': 0.5},
        legend_title='California Counties',
        title='California and Nearby States'
    )
    py.iplot(fig, filename='choropleth_california_and_surr_states_outlines')
    ```

    Example 4: USA
    ```
    import plotly.plotly as py
    import plotly.figure_factory as ff

    import numpy as np
    import pandas as pd

    df_sample = pd.read_csv(
        'https://raw.githubusercontent.com/plotly/datasets/master/laucnty16.csv'
    )
    df_sample['State FIPS Code'] = df_sample['State FIPS Code'].apply(
        lambda x: str(x).zfill(2)
    )
    df_sample['County FIPS Code'] = df_sample['County FIPS Code'].apply(
        lambda x: str(x).zfill(3)
    )
    df_sample['FIPS'] = (
        df_sample['State FIPS Code'] + df_sample['County FIPS Code']
    )

    binning_endpoints = list(np.linspace(1, 12, len(colorscale) - 1))
    colorscale = ["#f7fbff", "#ebf3fb", "#deebf7", "#d2e3f3", "#c6dbef",
                  "#b3d2e9", "#9ecae1", "#85bcdb", "#6baed6", "#57a0ce",
                  "#4292c6", "#3082be", "#2171b5", "#1361a9", "#08519c",
                  "#0b4083","#08306b"]
    fips = df_sample['FIPS']
    values = df_sample['Unemployment Rate (%)']
    fig = ff.create_choropleth(
        fips=fips, values=values, scope=['usa'],
        binning_endpoints=binning_endpoints, colorscale=colorscale,
        show_hover=True, centroid_marker={'opacity': 0},
        asp=2.9, title='USA by Unemployment %',
        legend_title='Unemployment %'
    )

    py.iplot(fig, filename='choropleth_full_usa')
    ```
    """
    # ensure optional modules imported
    if not _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]
            ]
            y = [
                poly.simplify(simplify_state).exterior.xy[1].tolist()
                for poly in df_state["geometry"][index]
            ]
            for segment in range(len(x)):
                x_states = x_states + x[segment]
                y_states = y_states + y[segment]
                x_states.append(np.nan)
                y_states.append(np.nan)
        x_states.append(np.nan)
        y_states.append(np.nan)

    for lev in LEVELS:
        county_data = dict(
            type="scatter",
            mode="lines",
            x=x_traces[lev],
            y=y_traces[lev],
            line=county_outline,
            fill="toself",
            fillcolor=color_lookup[lev],
            name=lev,
            hoverinfo="none",
        )
        plot_data.append(county_data)

    if show_hover:
        hover_points = dict(
            type="scatter",
            showlegend=False,
            legendgroup="centroids",
            x=x_centroids,
            y=y_centroids,
            text=centroid_text,
            name="US Counties",
            mode="markers",
            marker={
                "color": "white",
                "opacity": 0
            },
            hoverinfo="text",
        )
        centroids_on_select = dict(
            selected=dict(marker=centroid_marker),
            unselected=dict(marker=dict(opacity=0)),
        )
        hover_points.update(centroids_on_select)
        plot_data.append(hover_points)

    if show_state_data:
        state_data = dict(
            type="scatter",
            legendgroup="States",
            line=state_outline,
            x=x_states,
            y=y_states,
            hoverinfo="text",
            showlegend=False,
            mode="lines",
        )
        plot_data.append(state_data)

    DEFAULT_LAYOUT = dict(
        hovermode="closest",
        xaxis=dict(
            autorange=False,
            range=USA_XRANGE,
            showgrid=False,
            zeroline=False,
            fixedrange=True,
            showticklabels=False,
        ),
        yaxis=dict(
            autorange=False,
            range=USA_YRANGE,
            showgrid=False,
            zeroline=False,
            fixedrange=True,
            showticklabels=False,
        ),
        margin=dict(t=40, b=20, r=20, l=20),
        width=900,
        height=450,
        dragmode="select",
        legend=dict(traceorder="reversed",
                    xanchor="right",
                    yanchor="top",
                    x=1,
                    y=1),
        annotations=[],
    )
    fig = dict(data=plot_data, layout=DEFAULT_LAYOUT)
    fig["layout"].update(layout_options)
    fig["layout"]["annotations"].append(
        dict(
            x=1,
            y=1.05,
            xref="paper",
            yref="paper",
            xanchor="right",
            showarrow=False,
            text="<b>" + legend_title + "</b>",
        ))

    if len(scope) == 1 and scope[0].lower() == "usa":
        xaxis_range_low = -125.0
        xaxis_range_high = -55.0
        yaxis_range_low = 25.0
        yaxis_range_high = 49.0
    else:
        xaxis_range_low = float("inf")
        xaxis_range_high = float("-inf")
        yaxis_range_low = float("inf")
        yaxis_range_high = float("-inf")
        for trace in fig["data"]:
            if all(isinstance(n, Number) for n in trace["x"]):
                calc_x_min = min(trace["x"] or [float("inf")])
                calc_x_max = max(trace["x"] or [float("-inf")])
                if calc_x_min < xaxis_range_low:
                    xaxis_range_low = calc_x_min
                if calc_x_max > xaxis_range_high:
                    xaxis_range_high = calc_x_max
            if all(isinstance(n, Number) for n in trace["y"]):
                calc_y_min = min(trace["y"] or [float("inf")])
                calc_y_max = max(trace["y"] or [float("-inf")])
                if calc_y_min < yaxis_range_low:
                    yaxis_range_low = calc_y_min
                if calc_y_max > yaxis_range_high:
                    yaxis_range_high = calc_y_max

    # camera zoom
    fig["layout"]["xaxis"]["range"] = [xaxis_range_low, xaxis_range_high]
    fig["layout"]["yaxis"]["range"] = [yaxis_range_low, yaxis_range_high]

    # aspect ratio
    if asp is None:
        usa_x_range = USA_XRANGE[1] - USA_XRANGE[0]
        usa_y_range = USA_YRANGE[1] - USA_YRANGE[0]
        asp = usa_x_range / usa_y_range

    # based on your figure
    width = float(fig["layout"]["xaxis"]["range"][1] -
                  fig["layout"]["xaxis"]["range"][0])
    height = float(fig["layout"]["yaxis"]["range"][1] -
                   fig["layout"]["yaxis"]["range"][0])

    center = (
        sum(fig["layout"]["xaxis"]["range"]) / 2.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)
def colormap(i):
    return label_rgb([
        int(n)
        for n in find_intermediate_color([0, 255., 255.], [255., 0., 0], i)
    ])
Example #11
0
def violin_colorscale(
    data,
    data_header,
    group_header,
    colors,
    use_colorscale,
    group_stats,
    rugplot,
    sort,
    height,
    width,
    title,
):
    """
    Refer to FigureFactory.create_violin() for docstring.

    Returns fig for violin plot with colorscale.

    """

    # collect all group names
    group_name = []
    for name in data[group_header]:
        if name not in group_name:
            group_name.append(name)
    if sort:
        group_name.sort()

    # make sure all group names are keys in group_stats
    for group in group_name:
        if group not in group_stats:
            raise exceptions.PlotlyError("All values/groups in the index "
                                         "column must be represented "
                                         "as a key in group_stats.")

    gb = data.groupby([group_header])
    L = len(group_name)

    fig = make_subplots(rows=1,
                        cols=L,
                        shared_yaxes=True,
                        horizontal_spacing=0.025,
                        print_grid=False)

    # prepare low and high color for colorscale
    lowcolor = clrs.color_parser(colors[0], clrs.unlabel_rgb)
    highcolor = clrs.color_parser(colors[1], clrs.unlabel_rgb)

    # find min and max values in group_stats
    group_stats_values = []
    for key in group_stats:
        group_stats_values.append(group_stats[key])

    max_value = max(group_stats_values)
    min_value = min(group_stats_values)

    for k, gr in enumerate(group_name):
        vals = np.asarray(gb.get_group(gr)[data_header], np.float)

        # find intermediate color from colorscale
        intermed = (group_stats[gr] - min_value) / (max_value - min_value)
        intermed_color = clrs.find_intermediate_color(lowcolor, highcolor,
                                                      intermed)

        plot_data, plot_xrange = violinplot(
            vals, fillcolor="rgb{}".format(intermed_color), rugplot=rugplot)
        layout = graph_objs.Layout()

        for item in plot_data:
            fig.append_trace(item, 1, k + 1)
        fig["layout"].update(
            {"xaxis{}".format(k + 1): make_XAxis(group_name[k], plot_xrange)})
    # add colorbar to plot
    trace_dummy = graph_objs.Scatter(
        x=[0],
        y=[0],
        mode="markers",
        marker=dict(
            size=2,
            cmin=min_value,
            cmax=max_value,
            colorscale=[[0, colors[0]], [1, colors[1]]],
            showscale=True,
        ),
        showlegend=False,
    )
    fig.append_trace(trace_dummy, 1, L)

    # set the sharey axis style
    fig["layout"].update({"yaxis{}".format(1): make_YAxis("")})
    fig["layout"].update(
        title=title,
        showlegend=False,
        hovermode="closest",
        autosize=False,
        height=height,
        width=width,
    )

    return fig
Example #12
0
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
Example #13
0
def map_face2color(face, colormap, scale, vmin, vmax):
    """
    Normalize facecolor values by vmin/vmax and return rgb-color strings

    This function takes a tuple color along with a colormap and a minimum
    (vmin) and maximum (vmax) range of possible mean distances for the
    given parametrized surface. It returns an rgb color based on the mean
    distance between vmin and vmax

    """
    if vmin >= vmax:
        raise exceptions.PlotlyError("Incorrect relation between vmin "
                                     "and vmax. The vmin value cannot be "
                                     "bigger than or equal to the value "
                                     "of vmax.")
    if len(colormap) == 1:
        # color each triangle face with the same color in colormap
        face_color = colormap[0]
        face_color = colors.convert_to_RGB_255(face_color)
        face_color = colors.label_rgb(face_color)
        return face_color
    if face == vmax:
        # pick last color in colormap
        face_color = colormap[-1]
        face_color = colors.convert_to_RGB_255(face_color)
        face_color = colors.label_rgb(face_color)
        return face_color
    else:
        if scale is None:
            # find the normalized distance t of a triangle face between
            # vmin and vmax where the distance is between 0 and 1
            t = (face - vmin) / float((vmax - vmin))
            low_color_index = int(t / (1./(len(colormap) - 1)))

            face_color = colors.find_intermediate_color(
                colormap[low_color_index],
                colormap[low_color_index + 1],
                t * (len(colormap) - 1) - low_color_index
            )

            face_color = colors.convert_to_RGB_255(face_color)
            face_color = colors.label_rgb(face_color)
        else:
            # find the face color for a non-linearly interpolated scale
            t = (face - vmin) / float((vmax - vmin))

            low_color_index = 0
            for k in range(len(scale) - 1):
                if scale[k] <= t < scale[k+1]:
                    break
                low_color_index += 1

            low_scale_val = scale[low_color_index]
            high_scale_val = scale[low_color_index + 1]

            face_color = colors.find_intermediate_color(
                colormap[low_color_index],
                colormap[low_color_index + 1],
                (t - low_scale_val)/(high_scale_val - low_scale_val)
            )

            face_color = colors.convert_to_RGB_255(face_color)
            face_color = colors.label_rgb(face_color)
        return face_color
Example #14
0
def gantt_colorscale(chart, colors, title, index_col, show_colorbar, bar_width,
                     showgrid_x, showgrid_y, height, width, tasks=None,
                     task_names=None, data=None, group_tasks=False):
    """
    Refer to FigureFactory.create_gantt() for docstring
    """
    if tasks is None:
        tasks = []
    if task_names is None:
        task_names = []
    if data is None:
        data = []
    showlegend = False

    for index in range(len(chart)):
        task = dict(x0=chart[index]['Start'],
                    x1=chart[index]['Finish'],
                    name=chart[index]['Task'])
        if 'Description' in chart[index]:
            task['description'] = chart[index]['Description']
        tasks.append(task)

    shape_template = {
        'type': 'rect',
        'xref': 'x',
        'yref': 'y',
        'opacity': 1,
        'line': {
            'width': 0,
        }
    }

    # compute the color for task based on indexing column
    if isinstance(chart[0][index_col], Number):
        # check that colors has at least 2 colors
        if len(colors) < 2:
            raise exceptions.PlotlyError(
                "You must use at least 2 colors in 'colors' if you "
                "are using a colorscale. However only the first two "
                "colors given will be used for the lower and upper "
                "bounds on the colormap."
            )

        # create the list of task names
        for index in range(len(tasks)):
            tn = tasks[index]['name']
            # Is added to task_names if group_tasks is set to False,
            # or if the option is used (True) it only adds them if the
            # name is not already in the list
            if not group_tasks or tn not in task_names:
                task_names.append(tn)
        # Guarantees that for grouped tasks the tasks that are inserted
        # first are shown at the top
        if group_tasks:
            task_names.reverse()

        for index in range(len(tasks)):
            tn = tasks[index]['name']
            del tasks[index]['name']
            tasks[index].update(shape_template)

            # If group_tasks is True, all tasks with the same name belong
            # to the same row.
            groupID = index
            if group_tasks:
                groupID = task_names.index(tn)
            tasks[index]['y0'] = groupID - bar_width
            tasks[index]['y1'] = groupID + bar_width

            # unlabel color
            colors = 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
            # relabel colors with 'rgb'
            colors = clrs.color_parser(colors, clrs.label_rgb)

            # add a line for hover text and autorange
            entry = dict(
                x=[tasks[index]['x0'], tasks[index]['x1']],
                y=[groupID, groupID],
                name='',
                marker={'color': 'white'}
            )
            if "description" in tasks[index]:
                entry['text'] = tasks[index]['description']
                del tasks[index]['description']
            data.append(entry)

        if show_colorbar is True:
            # generate dummy data for colorscale visibility
            data.append(
                dict(
                    x=[tasks[index]['x0'], tasks[index]['x0']],
                    y=[index, index],
                    name='',
                    marker={'color': 'white',
                            'colorscale': [[0, colors[0]], [1, colors[1]]],
                            'showscale': True,
                            'cmax': 100,
                            'cmin': 0}
                )
            )

    if isinstance(chart[0][index_col], str):
        index_vals = []
        for row in range(len(tasks)):
            if chart[row][index_col] not in index_vals:
                index_vals.append(chart[row][index_col])

        index_vals.sort()

        if len(colors) < len(index_vals):
            raise exceptions.PlotlyError(
                "Error. The number of colors in 'colors' must be no less "
                "than the number of unique index values in your group "
                "column."
            )

        # make a dictionary assignment to each index value
        index_vals_dict = {}
        # define color index
        c_index = 0
        for key in index_vals:
            if c_index > len(colors) - 1:
                c_index = 0
            index_vals_dict[key] = colors[c_index]
            c_index += 1

        # create the list of task names
        for index in range(len(tasks)):
            tn = tasks[index]['name']
            # Is added to task_names if group_tasks is set to False,
            # or if the option is used (True) it only adds them if the
            # name is not already in the list
            if not group_tasks or tn not in task_names:
                task_names.append(tn)
        # Guarantees that for grouped tasks the tasks that are inserted
        # first are shown at the top
        if group_tasks:
            task_names.reverse()

        for index in range(len(tasks)):
            tn = tasks[index]['name']
            del tasks[index]['name']
            tasks[index].update(shape_template)
            # If group_tasks is True, all tasks with the same name belong
            # to the same row.
            groupID = index
            if group_tasks:
                groupID = task_names.index(tn)
            tasks[index]['y0'] = groupID - bar_width
            tasks[index]['y1'] = groupID + bar_width

            tasks[index]['fillcolor'] = index_vals_dict[
                chart[index][index_col]
            ]

            # add a line for hover text and autorange
            entry = dict(
                x=[tasks[index]['x0'], tasks[index]['x1']],
                y=[groupID, groupID],
                name='',
                marker={'color': 'white'}
            )
            if "description" in tasks[index]:
                entry['text'] = tasks[index]['description']
                del tasks[index]['description']
            data.append(entry)

        if show_colorbar is True:
            # generate dummy data to generate legend
            showlegend = True
            for k, index_value in enumerate(index_vals):
                data.append(
                    dict(
                        x=[tasks[index]['x0'], tasks[index]['x0']],
                        y=[k, k],
                        showlegend=True,
                        name=str(index_value),
                        hoverinfo='none',
                        marker=dict(
                            color=colors[k],
                            size=1
                        )
                    )
                )

    layout = dict(
        title=title,
        showlegend=showlegend,
        height=height,
        width=width,
        shapes=[],
        hovermode='closest',
        yaxis=dict(
            showgrid=showgrid_y,
            ticktext=task_names,
            tickvals=list(range(len(task_names))),
            range=[-1, len(task_names) + 1],
            autorange=False,
            zeroline=False,
        ),
        xaxis=dict(
            showgrid=showgrid_x,
            zeroline=False,
            rangeselector=dict(
                buttons=list([
                    dict(count=7,
                         label='1w',
                         step='day',
                         stepmode='backward'),
                    dict(count=1,
                         label='1m',
                         step='month',
                         stepmode='backward'),
                    dict(count=6,
                         label='6m',
                         step='month',
                         stepmode='backward'),
                    dict(count=1,
                         label='YTD',
                         step='year',
                         stepmode='todate'),
                    dict(count=1,
                         label='1y',
                         step='year',
                         stepmode='backward'),
                    dict(step='all')
                ])
            ),
            type='date'
        )
    )
    layout['shapes'] = tasks

    fig = dict(data=data, layout=layout)
    return fig
Example #15
0
def violin_colorscale(data, data_header, group_header, colors, use_colorscale,
                      group_stats, rugplot, sort, height, width,
                      title):
    """
    Refer to FigureFactory.create_violin() for docstring.

    Returns fig for violin plot with colorscale.

    """

    # collect all group names
    group_name = []
    for name in data[group_header]:
        if name not in group_name:
            group_name.append(name)
    if sort:
        group_name.sort()

    # make sure all group names are keys in group_stats
    for group in group_name:
        if group not in group_stats:
            raise exceptions.PlotlyError("All values/groups in the index "
                                         "column must be represented "
                                         "as a key in group_stats.")

    gb = data.groupby([group_header])
    L = len(group_name)

    fig = make_subplots(rows=1, cols=L,
                        shared_yaxes=True,
                        horizontal_spacing=0.025,
                        print_grid=False)

    # prepare low and high color for colorscale
    lowcolor = clrs.color_parser(colors[0], clrs.unlabel_rgb)
    highcolor = clrs.color_parser(colors[1], clrs.unlabel_rgb)

    # find min and max values in group_stats
    group_stats_values = []
    for key in group_stats:
        group_stats_values.append(group_stats[key])

    max_value = max(group_stats_values)
    min_value = min(group_stats_values)

    for k, gr in enumerate(group_name):
        vals = np.asarray(gb.get_group(gr)[data_header], np.float)

        # find intermediate color from colorscale
        intermed = (group_stats[gr] - min_value) / (max_value - min_value)
        intermed_color = clrs.find_intermediate_color(
            lowcolor, highcolor, intermed
        )

        plot_data, plot_xrange = violinplot(
            vals,
            fillcolor='rgb{}'.format(intermed_color),
            rugplot=rugplot
        )
        layout = graph_objs.Layout()

        for item in plot_data:
            fig.append_trace(item, 1, k + 1)
        fig['layout'].update(
            {'xaxis{}'.format(k + 1): make_XAxis(group_name[k], plot_xrange)}
        )
    # add colorbar to plot
    trace_dummy = graph_objs.Scatter(
        x=[0],
        y=[0],
        mode='markers',
        marker=dict(
            size=2,
            cmin=min_value,
            cmax=max_value,
            colorscale=[[0, colors[0]],
                        [1, colors[1]]],
            showscale=True),
        showlegend=False,
    )
    fig.append_trace(trace_dummy, 1, L)

    # set the sharey axis style
    fig['layout'].update({'yaxis{}'.format(1): make_YAxis('')})
    fig['layout'].update(
        title=title,
        showlegend=False,
        hovermode='closest',
        autosize=False,
        height=height,
        width=width
    )

    return fig
Example #16
0
def gantt_colorscale(
    chart,
    colors,
    title,
    index_col,
    show_colorbar,
    bar_width,
    showgrid_x,
    showgrid_y,
    height,
    width,
    tasks=None,
    task_names=None,
    data=None,
    group_tasks=False,
):
    """
    Refer to FigureFactory.create_gantt() for docstring
    """
    if tasks is None:
        tasks = []
    if task_names is None:
        task_names = []
    if data is None:
        data = []
    showlegend = False

    for index in range(len(chart)):
        task = dict(
            x0=chart[index]["Start"],
            x1=chart[index]["Finish"],
            name=chart[index]["Task"],
        )
        if "Description" in chart[index]:
            task["description"] = chart[index]["Description"]
        tasks.append(task)

    shape_template = {
        "type": "rect",
        "xref": "x",
        "yref": "y",
        "opacity": 1,
        "line": {
            "width": 0
        },
    }

    # compute the color for task based on indexing column
    if isinstance(chart[0][index_col], Number):
        # check that colors has at least 2 colors
        if len(colors) < 2:
            raise exceptions.PlotlyError(
                "You must use at least 2 colors in 'colors' if you "
                "are using a colorscale. However only the first two "
                "colors given will be used for the lower and upper "
                "bounds on the colormap.")

        # create the list of task names
        for index in range(len(tasks)):
            tn = tasks[index]["name"]
            # Is added to task_names if group_tasks is set to False,
            # or if the option is used (True) it only adds them if the
            # name is not already in the list
            if not group_tasks or tn not in task_names:
                task_names.append(tn)
        # Guarantees that for grouped tasks the tasks that are inserted
        # first are shown at the top
        if group_tasks:
            task_names.reverse()

        for index in range(len(tasks)):
            tn = tasks[index]["name"]
            del tasks[index]["name"]
            tasks[index].update(shape_template)

            # If group_tasks is True, all tasks with the same name belong
            # to the same row.
            groupID = index
            if group_tasks:
                groupID = task_names.index(tn)
            tasks[index]["y0"] = groupID - bar_width
            tasks[index]["y1"] = groupID + bar_width

            # unlabel color
            colors = 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
            # relabel colors with 'rgb'
            colors = clrs.color_parser(colors, clrs.label_rgb)

            # add a line for hover text and autorange
            entry = dict(
                x=[tasks[index]["x0"], tasks[index]["x1"]],
                y=[groupID, groupID],
                name="",
                marker={"color": "white"},
            )
            if "description" in tasks[index]:
                entry["text"] = tasks[index]["description"]
                del tasks[index]["description"]
            data.append(entry)

        if show_colorbar is True:
            # generate dummy data for colorscale visibility
            data.append(
                dict(
                    x=[tasks[index]["x0"], tasks[index]["x0"]],
                    y=[index, index],
                    name="",
                    marker={
                        "color": "white",
                        "colorscale": [[0, colors[0]], [1, colors[1]]],
                        "showscale": True,
                        "cmax": 100,
                        "cmin": 0,
                    },
                ))

    if isinstance(chart[0][index_col], str):
        index_vals = []
        for row in range(len(tasks)):
            if chart[row][index_col] not in index_vals:
                index_vals.append(chart[row][index_col])

        index_vals.sort()

        if len(colors) < len(index_vals):
            raise exceptions.PlotlyError(
                "Error. The number of colors in 'colors' must be no less "
                "than the number of unique index values in your group "
                "column.")

        # make a dictionary assignment to each index value
        index_vals_dict = {}
        # define color index
        c_index = 0
        for key in index_vals:
            if c_index > len(colors) - 1:
                c_index = 0
            index_vals_dict[key] = colors[c_index]
            c_index += 1

        # create the list of task names
        for index in range(len(tasks)):
            tn = tasks[index]["name"]
            # Is added to task_names if group_tasks is set to False,
            # or if the option is used (True) it only adds them if the
            # name is not already in the list
            if not group_tasks or tn not in task_names:
                task_names.append(tn)
        # Guarantees that for grouped tasks the tasks that are inserted
        # first are shown at the top
        if group_tasks:
            task_names.reverse()

        for index in range(len(tasks)):
            tn = tasks[index]["name"]
            del tasks[index]["name"]
            tasks[index].update(shape_template)
            # If group_tasks is True, all tasks with the same name belong
            # to the same row.
            groupID = index
            if group_tasks:
                groupID = task_names.index(tn)
            tasks[index]["y0"] = groupID - bar_width
            tasks[index]["y1"] = groupID + bar_width

            tasks[index]["fillcolor"] = index_vals_dict[chart[index]
                                                        [index_col]]

            # add a line for hover text and autorange
            entry = dict(
                x=[tasks[index]["x0"], tasks[index]["x1"]],
                y=[groupID, groupID],
                name="",
                marker={"color": "white"},
            )
            if "description" in tasks[index]:
                entry["text"] = tasks[index]["description"]
                del tasks[index]["description"]
            data.append(entry)

        if show_colorbar is True:
            # generate dummy data to generate legend
            showlegend = True
            for k, index_value in enumerate(index_vals):
                data.append(
                    dict(
                        x=[tasks[index]["x0"], tasks[index]["x0"]],
                        y=[k, k],
                        showlegend=True,
                        name=str(index_value),
                        hoverinfo="none",
                        marker=dict(color=colors[k], size=1),
                    ))

    layout = dict(
        title=title,
        showlegend=showlegend,
        height=height,
        width=width,
        shapes=[],
        hovermode="closest",
        yaxis=dict(
            showgrid=showgrid_y,
            ticktext=task_names,
            tickvals=list(range(len(task_names))),
            range=[-1, len(task_names) + 1],
            autorange=False,
            zeroline=False,
        ),
        xaxis=dict(
            showgrid=showgrid_x,
            zeroline=False,
            rangeselector=dict(buttons=list([
                dict(count=7, label="1w", step="day", stepmode="backward"),
                dict(count=1, label="1m", step="month", stepmode="backward"),
                dict(count=6, label="6m", step="month", stepmode="backward"),
                dict(count=1, label="YTD", step="year", stepmode="todate"),
                dict(count=1, label="1y", step="year", stepmode="backward"),
                dict(step="all"),
            ])),
            type="date",
        ),
    )
    layout["shapes"] = tasks

    fig = graph_objs.Figure(data=data, layout=layout)
    return fig
Example #17
0
def create_choropleth(fips, values, scope=['usa'], binning_endpoints=None,
                      colorscale=None, order=None, simplify_county=0.02,
                      simplify_state=0.02, asp=None, show_hover=True,
                      show_state_data=True, state_outline=None,
                      county_outline=None, centroid_marker=None,
                      round_legend_values=False, exponent_format=False,
                      legend_title='', **layout_options):
    """
    Returns figure for county choropleth. Uses data from package_data.

    :param (list) fips: list of FIPS values which correspond to the con
        catination of state and county ids. An example is '01001'.
    :param (list) values: list of numbers/strings which correspond to the
        fips list. These are the values that will determine how the counties
        are colored.
    :param (list) scope: list of states and/or states abbreviations. Fits
        all states in the camera tightly. Selecting ['usa'] is the equivalent
        of appending all 50 states into your scope list. Selecting only 'usa'
        does not include 'Alaska', 'Puerto Rico', 'American Samoa',
        'Commonwealth of the Northern Mariana Islands', 'Guam',
        'United States Virgin Islands'. These must be added manually to the
        list.
        Default = ['usa']
    :param (list) binning_endpoints: ascending numbers which implicitly define
        real number intervals which are used as bins. The colorscale used must
        have the same number of colors as the number of bins and this will
        result in a categorical colormap.
    :param (list) colorscale: a list of colors with length equal to the
        number of categories of colors. The length must match either all
        unique numbers in the 'values' list or if endpoints is being used, the
        number of categories created by the endpoints.\n
        For example, if binning_endpoints = [4, 6, 8], then there are 4 bins:
        [-inf, 4), [4, 6), [6, 8), [8, inf)
    :param (list) order: a list of the unique categories (numbers/bins) in any
        desired order. This is helpful if you want to order string values to
        a chosen colorscale.
    :param (float) simplify_county: determines the simplification factor
        for the counties. The larger the number, the fewer vertices and edges
        each polygon has. See
        http://toblerity.org/shapely/manual.html#object.simplify for more
        information.
        Default = 0.02
    :param (float) simplify_state: simplifies the state outline polygon.
        See http://toblerity.org/shapely/manual.html#object.simplify for more
        information.
        Default = 0.02
    :param (float) asp: the width-to-height aspect ratio for the camera.
        Default = 2.5
    :param (bool) show_hover: show county hover and centroid info
    :param (bool) show_state_data: reveals state boundary lines
    :param (dict) state_outline: dict of attributes of the state outline
        including width and color. See
        https://plot.ly/python/reference/#scatter-marker-line for all valid
        params
    :param (dict) county_outline: dict of attributes of the county outline
        including width and color. See
        https://plot.ly/python/reference/#scatter-marker-line for all valid
        params
    :param (dict) centroid_marker: dict of attributes of the centroid marker.
        The centroid markers are invisible by default and appear visible on
        selection. See https://plot.ly/python/reference/#scatter-marker for
        all valid params
    :param (bool) round_legend_values: automatically round the numbers that
        appear in the legend to the nearest integer.
        Default = False
    :param (bool) exponent_format: if set to True, puts numbers in the K, M,
        B number format. For example 4000.0 becomes 4.0K
        Default = False
    :param (str) legend_title: title that appears above the legend
    :param **layout_options: a **kwargs argument for all layout parameters


    Example 1: Florida
    ```
    import plotly.plotly as py
    import plotly.figure_factory as ff

    import numpy as np
    import pandas as pd

    df_sample = pd.read_csv(
        'https://raw.githubusercontent.com/plotly/datasets/master/minoritymajority.csv'
    )
    df_sample_r = df_sample[df_sample['STNAME'] == 'Florida']

    values = df_sample_r['TOT_POP'].tolist()
    fips = df_sample_r['FIPS'].tolist()

    binning_endpoints = list(np.mgrid[min(values):max(values):4j])
    colorscale = ["#030512","#1d1d3b","#323268","#3d4b94","#3e6ab0",
                  "#4989bc","#60a7c7","#85c5d3","#b7e0e4","#eafcfd"]
    fig = ff.create_choropleth(
        fips=fips, values=values, scope=['Florida'], show_state_data=True,
        colorscale=colorscale, binning_endpoints=binning_endpoints,
        round_legend_values=True, plot_bgcolor='rgb(229,229,229)',
        paper_bgcolor='rgb(229,229,229)', legend_title='Florida Population',
        county_outline={'color': 'rgb(255,255,255)', 'width': 0.5},
        exponent_format=True,
    )
    py.iplot(fig, filename='choropleth_florida')
    ```

    Example 2: New England
    ```
    import plotly.plotly as py
    import plotly.figure_factory as ff

    import pandas as pd

    NE_states = ['Connecticut', 'Maine', 'Massachusetts',
                 'New Hampshire', 'Rhode Island']
    df_sample = pd.read_csv(
        'https://raw.githubusercontent.com/plotly/datasets/master/minoritymajority.csv'
    )
    df_sample_r = df_sample[df_sample['STNAME'].isin(NE_states)]
    colorscale = ['rgb(68.0, 1.0, 84.0)',
     'rgb(66.0, 64.0, 134.0)',
     'rgb(38.0, 130.0, 142.0)',
     'rgb(63.0, 188.0, 115.0)',
     'rgb(216.0, 226.0, 25.0)']

    values = df_sample_r['TOT_POP'].tolist()
    fips = df_sample_r['FIPS'].tolist()
    fig = ff.create_choropleth(
        fips=fips, values=values, scope=NE_states, show_state_data=True
    )
    py.iplot(fig, filename='choropleth_new_england')
    ```

    Example 3: California and Surrounding States
    ```
    import plotly.plotly as py
    import plotly.figure_factory as ff

    import pandas as pd

    df_sample = pd.read_csv(
        'https://raw.githubusercontent.com/plotly/datasets/master/minoritymajority.csv'
    )
    df_sample_r = df_sample[df_sample['STNAME'] == 'California']

    values = df_sample_r['TOT_POP'].tolist()
    fips = df_sample_r['FIPS'].tolist()

    colorscale = [
        'rgb(193, 193, 193)',
        'rgb(239,239,239)',
        'rgb(195, 196, 222)',
        'rgb(144,148,194)',
        'rgb(101,104,168)',
        'rgb(65, 53, 132)'
    ]

    fig = ff.create_choropleth(
        fips=fips, values=values, colorscale=colorscale,
        scope=['CA', 'AZ', 'Nevada', 'Oregon', ' Idaho'],
        binning_endpoints=[14348, 63983, 134827, 426762, 2081313],
        county_outline={'color': 'rgb(255,255,255)', 'width': 0.5},
        legend_title='California Counties',
        title='California and Nearby States'
    )
    py.iplot(fig, filename='choropleth_california_and_surr_states_outlines')
    ```

    Example 4: USA
    ```
    import plotly.plotly as py
    import plotly.figure_factory as ff

    import numpy as np
    import pandas as pd

    df_sample = pd.read_csv(
        'https://raw.githubusercontent.com/plotly/datasets/master/laucnty16.csv'
    )
    df_sample['State FIPS Code'] = df_sample['State FIPS Code'].apply(
        lambda x: str(x).zfill(2)
    )
    df_sample['County FIPS Code'] = df_sample['County FIPS Code'].apply(
        lambda x: str(x).zfill(3)
    )
    df_sample['FIPS'] = (
        df_sample['State FIPS Code'] + df_sample['County FIPS Code']
    )

    binning_endpoints = list(np.linspace(1, 12, len(colorscale) - 1))
    colorscale = ["#f7fbff", "#ebf3fb", "#deebf7", "#d2e3f3", "#c6dbef",
                  "#b3d2e9", "#9ecae1", "#85bcdb", "#6baed6", "#57a0ce",
                  "#4292c6", "#3082be", "#2171b5", "#1361a9", "#08519c",
                  "#0b4083","#08306b"]
    fips = df_sample['FIPS']
    values = df_sample['Unemployment Rate (%)']
    fig = ff.create_choropleth(
        fips=fips, values=values, scope=['usa'],
        binning_endpoints=binning_endpoints, colorscale=colorscale,
        show_hover=True, centroid_marker={'opacity': 0},
        asp=2.9, title='USA by Unemployment %',
        legend_title='Unemployment %'
    )

    py.iplot(fig, filename='choropleth_full_usa')
    ```
    """
    # ensure optional modules imported
    if not gp or not shapefile or not shapely:
        raise ImportError(
            "geopandas, pyshp and shapely must be installed for this figure "
            "factory.\n\nRun the following commands to install the correct "
            "versions of the following modules:\n\n"
            "```\n"
            "pip install geopandas==0.3.0\n"
            "pip install pyshp==1.2.10\n"
            "pip install shapely==1.6.3\n"
            "```\n"
            "If you are using Windows, follow this post to properly "
            "install geopandas and dependencies:"
            "http://geoffboeing.com/2014/09/using-geopandas-windows/\n\n"
            "If you are using Anaconda, do not use PIP to install the "
            "packages above. Instead use conda to install them:\n\n"
            "```\n"
            "conda install plotly\n"
            "conda install geopandas\n"
            "```"
        )

    df, df_state = _create_us_counties_df(st_to_state_name_dict,
                                          state_to_st_dict)

    fips_polygon_map = dict(
        zip(
            df['FIPS'].tolist(),
            df['geometry'].tolist()
        )
    )

    if not state_outline:
        state_outline = {'color': 'rgb(240, 240, 240)',
                         'width': 1}
    if not county_outline:
        county_outline = {'color': 'rgb(0, 0, 0)',
                          'width': 0}
    if not centroid_marker:
        centroid_marker = {'size': 3, 'color': 'white', 'opacity': 1}

    # ensure centroid markers appear on selection
    if 'opacity' not in centroid_marker:
        centroid_marker.update({'opacity': 1})

    if len(fips) != len(values):
        raise 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]])
            y = ([poly.simplify(simplify_state).exterior.xy[1].tolist() for
                  poly in df_state['geometry'][index]])
            for segment in range(len(x)):
                x_states = x_states + x[segment]
                y_states = y_states + y[segment]
                x_states.append(np.nan)
                y_states.append(np.nan)
        x_states.append(np.nan)
        y_states.append(np.nan)

    for lev in LEVELS:
        county_data = dict(
            type='scatter',
            mode='lines',
            x=x_traces[lev],
            y=y_traces[lev],
            line=county_outline,
            fill='toself',
            fillcolor=color_lookup[lev],
            name=lev,
            hoverinfo='none',
        )
        plot_data.append(county_data)

    if show_hover:
        hover_points = dict(
            type='scatter',
            showlegend=False,
            legendgroup='centroids',
            x=x_centroids,
            y=y_centroids,
            text=centroid_text,
            name='US Counties',
            mode='markers',
            marker={'color': 'white', 'opacity': 0},
            hoverinfo='text'
        )
        centroids_on_select = dict(
            selected=dict(marker=centroid_marker),
            unselected=dict(marker=dict(opacity=0))
        )
        hover_points.update(centroids_on_select)
        plot_data.append(hover_points)

    if show_state_data:
        state_data = dict(
            type='scatter',
            legendgroup='States',
            line=state_outline,
            x=x_states,
            y=y_states,
            hoverinfo='text',
            showlegend=False,
            mode='lines'
        )
        plot_data.append(state_data)

    DEFAULT_LAYOUT = dict(
        hovermode='closest',
        xaxis=dict(
            autorange=False,
            range=USA_XRANGE,
            showgrid=False,
            zeroline=False,
            fixedrange=True,
            showticklabels=False
        ),
        yaxis=dict(
            autorange=False,
            range=USA_YRANGE,
            showgrid=False,
            zeroline=False,
            fixedrange=True,
            showticklabels=False
        ),
        margin=dict(t=40, b=20, r=20, l=20),
        width=900,
        height=450,
        dragmode='select',
        legend=dict(
            traceorder='reversed',
            xanchor='right',
            yanchor='top',
            x=1,
            y=1
        ),
        annotations=[]
    )
    fig = dict(data=plot_data, layout=DEFAULT_LAYOUT)
    fig['layout'].update(layout_options)
    fig['layout']['annotations'].append(
        dict(
            x=1,
            y=1.05,
            xref='paper',
            yref='paper',
            xanchor='right',
            showarrow=False,
            text='<b>' + legend_title + '</b>'
        )
    )

    if len(scope) == 1 and scope[0].lower() == 'usa':
        xaxis_range_low = -125.0
        xaxis_range_high = -55.0
        yaxis_range_low = 25.0
        yaxis_range_high = 49.0
    else:
        xaxis_range_low = float('inf')
        xaxis_range_high = float('-inf')
        yaxis_range_low = float('inf')
        yaxis_range_high = float('-inf')
        for trace in fig['data']:
            if all(isinstance(n, Number) for n in trace['x']):
                calc_x_min = min(trace['x'] or [float('inf')])
                calc_x_max = max(trace['x'] or [float('-inf')])
                if calc_x_min < xaxis_range_low:
                    xaxis_range_low = calc_x_min
                if calc_x_max > xaxis_range_high:
                    xaxis_range_high = calc_x_max
            if all(isinstance(n, Number) for n in trace['y']):
                calc_y_min = min(trace['y'] or [float('inf')])
                calc_y_max = max(trace['y'] or [float('-inf')])
                if calc_y_min < yaxis_range_low:
                    yaxis_range_low = calc_y_min
                if calc_y_max > yaxis_range_high:
                    yaxis_range_high = calc_y_max

    # camera zoom
    fig['layout']['xaxis']['range'] = [xaxis_range_low, xaxis_range_high]
    fig['layout']['yaxis']['range'] = [yaxis_range_low, yaxis_range_high]

    # aspect ratio
    if asp is None:
        usa_x_range = USA_XRANGE[1] - USA_XRANGE[0]
        usa_y_range = USA_YRANGE[1] - USA_YRANGE[0]
        asp = usa_x_range / usa_y_range

    # based on your figure
    width = float(fig['layout']['xaxis']['range'][1] -
                  fig['layout']['xaxis']['range'][0])
    height = float(fig['layout']['yaxis']['range'][1] -
                   fig['layout']['yaxis']['range'][0])

    center = (sum(fig['layout']['xaxis']['range']) / 2.,
              sum(fig['layout']['yaxis']['range']) / 2.)

    if height / width > (1 / asp):
        new_width = asp * height
        fig['layout']['xaxis']['range'][0] = center[0] - new_width * 0.5
        fig['layout']['xaxis']['range'][1] = center[0] + new_width * 0.5
    else:
        new_height = (1 / asp) * width
        fig['layout']['yaxis']['range'][0] = center[1] - new_height * 0.5
        fig['layout']['yaxis']['range'][1] = center[1] + new_height * 0.5

    return fig