Skip to content

Commit bdafae8

Browse files
Kullyjonmmease
authored andcommitted
No colors functions in ff utils (#1301)
* correct PLOTLY_SCALES in utils.py and ensure gantt/scatter work with new scales being referenced * move all colors functions stricktly into colors.py and leave the rest in figure_factory.utils.py * change utils.validate_colorsc_dict to clrs.validate_colors_dict * reference is_sequence in _bullet.py to already existing function in figure_factory/utils.py * add validate_colorscale back to colors.py (accidentally deleted) and add imports to functions that got moved from utils to colors
1 parent 558aaff commit bdafae8

11 files changed

+207
-472
lines changed

Diff for: plotly/colors.py

+102-45
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777

7878
import decimal
7979
from numbers import Number
80+
import six
8081

8182
from plotly import exceptions
8283

@@ -203,19 +204,17 @@
203204
[0.8784313725490196, '#addc30'], [0.9411764705882353, '#d8e219'],
204205
[1, '#fde725']
205206
],
206-
207207
'Cividis': [
208-
[0.000000, 'rgb(0,32,76)'], [0.058824, 'rgb(0,42,102)'],
209-
[0.117647, 'rgb(0,52,110)'], [0.176471, 'rgb(39,63,108)'],
210-
[0.235294, 'rgb(60,74,107)'], [0.294118, 'rgb(76,85,107)'],
211-
[0.352941, 'rgb(91,95,109)'], [0.411765, 'rgb(104,106,112)'],
212-
[0.470588, 'rgb(117,117,117)'], [0.529412, 'rgb(131,129,120)'],
213-
[0.588235, 'rgb(146,140,120)'], [0.647059, 'rgb(161,152,118)'],
214-
[0.705882, 'rgb(176,165,114)'], [0.764706, 'rgb(192,177,109)'],
215-
[0.823529, 'rgb(209,191,102)'], [0.882353, 'rgb(225,204,92)'],
208+
[0.000000, 'rgb(0,32,76)'], [0.058824, 'rgb(0,42,102)'],
209+
[0.117647, 'rgb(0,52,110)'], [0.176471, 'rgb(39,63,108)'],
210+
[0.235294, 'rgb(60,74,107)'], [0.294118, 'rgb(76,85,107)'],
211+
[0.352941, 'rgb(91,95,109)'], [0.411765, 'rgb(104,106,112)'],
212+
[0.470588, 'rgb(117,117,117)'], [0.529412, 'rgb(131,129,120)'],
213+
[0.588235, 'rgb(146,140,120)'], [0.647059, 'rgb(161,152,118)'],
214+
[0.705882, 'rgb(176,165,114)'], [0.764706, 'rgb(192,177,109)'],
215+
[0.823529, 'rgb(209,191,102)'], [0.882353, 'rgb(225,204,92)'],
216216
[0.941176, 'rgb(243,219,79)'], [1.000000, 'rgb(255,233,69)']
217217
]
218-
219218
}
220219

221220

@@ -245,62 +244,105 @@ def color_parser(colors, function):
245244
return new_color_list
246245

247246

248-
def validate_colors(colors):
247+
def validate_colors(colors, colortype='tuple'):
249248
"""
250-
Validates color(s) and returns an error for invalid color(s)
251-
252-
:param (str|tuple|list) colors: either a plotly scale name, an rgb or hex
253-
color, a color tuple or a list/tuple of colors
249+
Validates color(s) and returns a list of color(s) of a specified type
254250
"""
255-
colors_list = []
251+
from numbers import Number
252+
if colors is None:
253+
colors = DEFAULT_PLOTLY_COLORS
256254

257-
# if colors is a single color, put into colors_list
258255
if isinstance(colors, str):
259256
if colors in PLOTLY_SCALES:
260-
return
257+
colors_list = colorscale_to_colors(PLOTLY_SCALES[colors])
258+
# TODO: fix _gantt.py/_scatter.py so that they can accept the
259+
# actual colorscale and not just a list of the first and last
260+
# color in the plotly colorscale. In resolving this issue we
261+
# will be removing the immediate line below
262+
colors = [colors_list[0]] + [colors_list[-1]]
261263
elif 'rgb' in colors or '#' in colors:
262-
colors_list.append(colors)
264+
colors = [colors]
263265
else:
264266
raise exceptions.PlotlyError(
265-
'If your colors variable is a string, it must be a '
266-
'Plotly scale, an rgb color or a hex color.'
267-
)
267+
"If your colors variable is a string, it must be a "
268+
"Plotly scale, an rgb color or a hex color.")
268269

269270
elif isinstance(colors, tuple):
270271
if isinstance(colors[0], Number):
271-
colors_list = [colors]
272+
colors = [colors]
272273
else:
273-
colors_list = list(colors)
274-
275-
if isinstance(colors, dict):
276-
colors_list.extend(colors.values())
277-
278-
elif isinstance(colors, list):
279-
colors_list = colors
274+
colors = list(colors)
280275

281-
# Validate colors in colors_list
282-
for j, each_color in enumerate(colors_list):
276+
# convert color elements in list to tuple color
277+
for j, each_color in enumerate(colors):
283278
if 'rgb' in each_color:
284-
each_color = color_parser(
285-
each_color, unlabel_rgb
286-
)
279+
each_color = color_parser(each_color, unlabel_rgb)
287280
for value in each_color:
288281
if value > 255.0:
289282
raise exceptions.PlotlyError(
290-
'Whoops! The elements in your rgb colors '
291-
'tuples cannot exceed 255.0.'
283+
"Whoops! The elements in your rgb colors "
284+
"tuples cannot exceed 255.0."
292285
)
293-
elif '#' in each_color:
294-
each_color = color_parser(
295-
each_color, hex_to_rgb
296-
)
297-
elif isinstance(each_color, tuple):
286+
each_color = color_parser(each_color, unconvert_from_RGB_255)
287+
colors[j] = each_color
288+
289+
if '#' in each_color:
290+
each_color = color_parser(each_color, hex_to_rgb)
291+
each_color = color_parser(each_color, unconvert_from_RGB_255)
292+
293+
colors[j] = each_color
294+
295+
if isinstance(each_color, tuple):
298296
for value in each_color:
299297
if value > 1.0:
300298
raise exceptions.PlotlyError(
301-
'Whoops! The elements in your colors tuples '
302-
'cannot exceed 1.0.'
299+
"Whoops! The elements in your colors tuples "
300+
"cannot exceed 1.0."
301+
)
302+
colors[j] = each_color
303+
304+
if colortype == 'rgb' and not isinstance(colors, six.string_types):
305+
for j, each_color in enumerate(colors):
306+
rgb_color = color_parser(each_color, convert_to_RGB_255)
307+
colors[j] = color_parser(rgb_color, label_rgb)
308+
309+
return colors
310+
311+
312+
def validate_colors_dict(colors, colortype='tuple'):
313+
"""
314+
Validates dictioanry of color(s)
315+
"""
316+
# validate each color element in the dictionary
317+
for key in colors:
318+
if 'rgb' in colors[key]:
319+
colors[key] = color_parser(colors[key], unlabel_rgb)
320+
for value in colors[key]:
321+
if value > 255.0:
322+
raise exceptions.PlotlyError(
323+
"Whoops! The elements in your rgb colors "
324+
"tuples cannot exceed 255.0."
303325
)
326+
colors[key] = color_parser(colors[key], unconvert_from_RGB_255)
327+
328+
if '#' in colors[key]:
329+
colors[key] = color_parser(colors[key], hex_to_rgb)
330+
colors[key] = color_parser(colors[key], unconvert_from_RGB_255)
331+
332+
if isinstance(colors[key], tuple):
333+
for value in colors[key]:
334+
if value > 1.0:
335+
raise exceptions.PlotlyError(
336+
"Whoops! The elements in your colors tuples "
337+
"cannot exceed 1.0."
338+
)
339+
340+
if colortype == 'rgb':
341+
for key in colors:
342+
colors[key] = color_parser(colors[key], convert_to_RGB_255)
343+
colors[key] = color_parser(colors[key], label_rgb)
344+
345+
return colors
304346

305347

306348
def convert_colors_to_same_type(colors, colortype='rgb', scale=None,
@@ -324,7 +366,6 @@ def convert_colors_to_same_type(colors, colortype='rgb', scale=None,
324366
:rtype (tuple) (colors_list, scale) if scale is None in the function call,
325367
then scale will remain None in the returned tuple
326368
"""
327-
#if colors_list is None:
328369
colors_list = []
329370

330371
if colors is None and return_default_colors is True:
@@ -462,6 +503,22 @@ def validate_scale_values(scale):
462503
)
463504

464505

506+
def validate_colorscale(colorscale):
507+
"""Validate the structure, scale values and colors of colorscale."""
508+
if not isinstance(colorscale, list):
509+
# TODO Write tests for these exceptions
510+
raise exceptions.PlotlyError("A valid colorscale must be a list.")
511+
if not all(isinstance(innerlist, list) for innerlist in colorscale):
512+
raise exceptions.PlotlyError(
513+
"A valid colorscale must be a list of lists."
514+
)
515+
colorscale_colors = colorscale_to_colors(colorscale)
516+
scale_values = colorscale_to_scale(colorscale)
517+
518+
validate_scale_values(scale_values)
519+
validate_colors(colorscale_colors)
520+
521+
465522
def make_colorscale(colors, scale=None):
466523
"""
467524
Makes a colorscale from a list of colors and a scale

Diff for: plotly/figure_factory/_2d_density.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from numbers import Number
44

55
from plotly import exceptions
6+
import plotly.colors as clrs
67
from plotly.figure_factory import utils
78
from plotly.graph_objs import graph_objs
89

@@ -100,12 +101,12 @@ def create_2d_density(x, y, colorscale='Earth', ncontours=20,
100101
"Both lists 'x' and 'y' must be the same length."
101102
)
102103

103-
colorscale = utils.validate_colors(colorscale, 'rgb')
104+
colorscale = clrs.validate_colors(colorscale, 'rgb')
104105
colorscale = make_linear_colorscale(colorscale)
105106

106107
# validate hist_color and point_color
107-
hist_color = utils.validate_colors(hist_color, 'rgb')
108-
point_color = utils.validate_colors(point_color, 'rgb')
108+
hist_color = clrs.validate_colors(hist_color, 'rgb')
109+
point_color = clrs.validate_colors(point_color, 'rgb')
109110

110111
trace1 = graph_objs.Scatter(
111112
x=x, y=y, mode='markers', name='points',

Diff for: plotly/figure_factory/_annotated_heatmap.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import absolute_import
22

33
from plotly import exceptions, optional_imports
4+
import plotly.colors as clrs
45
from plotly.figure_factory import utils
56
from plotly.graph_objs import graph_objs
67
from plotly.validators.heatmap import ColorscaleValidator
@@ -123,7 +124,7 @@ def to_rgb_color_list(color_str, default):
123124
if 'rgb' in color_str:
124125
return [int(v) for v in color_str.strip('rgb()').split(',')]
125126
elif '#' in color_str:
126-
return utils.hex_to_rgb(color_str)
127+
return clrs.hex_to_rgb(color_str)
127128
else:
128129
return default
129130

Diff for: plotly/figure_factory/_bullet.py

+8-13
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
import collections
44
import math
55

6-
from plotly import colors, exceptions, optional_imports
6+
from plotly import exceptions, optional_imports
7+
import plotly.colors as clrs
78
from plotly.figure_factory import utils
89

910
import plotly
@@ -12,15 +13,9 @@
1213
pd = optional_imports.get_module('pandas')
1314

1415

15-
def is_sequence(obj):
16-
return (isinstance(obj, collections.Sequence) and
17-
not isinstance(obj, str))
18-
19-
2016
def _bullet(df, markers, measures, ranges, subtitles, titles, orientation,
2117
range_colors, measure_colors, horizontal_spacing,
2218
vertical_spacing, scatter_options, layout_options):
23-
2419
num_of_lanes = len(df)
2520
num_of_rows = num_of_lanes if orientation == 'h' else 1
2621
num_of_cols = 1 if orientation == 'h' else num_of_lanes
@@ -78,7 +73,7 @@ def _bullet(df, markers, measures, ranges, subtitles, titles, orientation,
7873
for row in range(num_of_lanes):
7974
# ranges bars
8075
for idx in range(len(df.iloc[row]['ranges'])):
81-
inter_colors = colors.n_colors(
76+
inter_colors = clrs.n_colors(
8277
range_colors[0], range_colors[1],
8378
len(df.iloc[row]['ranges']), 'rgb'
8479
)
@@ -104,7 +99,7 @@ def _bullet(df, markers, measures, ranges, subtitles, titles, orientation,
10499

105100
# measures bars
106101
for idx in range(len(df.iloc[row]['measures'])):
107-
inter_colors = colors.n_colors(
102+
inter_colors = clrs.n_colors(
108103
measure_colors[0], measure_colors[1],
109104
len(df.iloc[row]['measures']), 'rgb'
110105
)
@@ -261,7 +256,7 @@ def create_bullet(data, markers=None, measures=None, ranges=None,
261256
"'pandas' must be installed for this figure factory."
262257
)
263258

264-
if is_sequence(data):
259+
if utils.is_sequence(data):
265260
if not all(isinstance(item, dict) for item in data):
266261
raise exceptions.PlotlyError(
267262
'Every entry of the data argument list, tuple, etc must '
@@ -275,7 +270,7 @@ def create_bullet(data, markers=None, measures=None, ranges=None,
275270

276271
# make DataFrame from data with correct column headers
277272
col_names = ['titles', 'subtitle', 'markers', 'measures', 'ranges']
278-
if is_sequence(data):
273+
if utils.is_sequence(data):
279274
df = pd.DataFrame(
280275
[
281276
[d[titles] for d in data] if titles else [''] * len(data),
@@ -317,8 +312,8 @@ def create_bullet(data, markers=None, measures=None, ranges=None,
317312
"Both 'range_colors' or 'measure_colors' must be a list "
318313
"of two valid colors."
319314
)
320-
colors.validate_colors(colors_list)
321-
colors_list = colors.convert_colors_to_same_type(colors_list,
315+
clrs.validate_colors(colors_list)
316+
colors_list = clrs.convert_colors_to_same_type(colors_list,
322317
'rgb')[0]
323318

324319
# default scatter options

Diff for: plotly/figure_factory/_county_choropleth.py

+13-12
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
from plotly import colors, exceptions, optional_imports
1+
from plotly import exceptions, optional_imports
2+
import plotly.colors as clrs
23

34
from plotly.figure_factory import utils
45

@@ -641,14 +642,14 @@ def create_choropleth(fips, values, scope=['usa'], binning_endpoints=None,
641642

642643
if not colorscale:
643644
colorscale = []
644-
viridis_colors = colors.colorscale_to_colors(
645-
colors.PLOTLY_SCALES['Viridis']
645+
viridis_colors = clrs.colorscale_to_colors(
646+
clrs.PLOTLY_SCALES['Viridis']
646647
)
647-
viridis_colors = colors.color_parser(
648-
viridis_colors, colors.hex_to_rgb
648+
viridis_colors = clrs.color_parser(
649+
viridis_colors, clrs.hex_to_rgb
649650
)
650-
viridis_colors = colors.color_parser(
651-
viridis_colors, colors.label_rgb
651+
viridis_colors = clrs.color_parser(
652+
viridis_colors, clrs.label_rgb
652653
)
653654
viri_len = len(viridis_colors) + 1
654655
viri_intervals = utils.endpts_to_intervals(
@@ -665,18 +666,18 @@ def create_choropleth(fips, values, scope=['usa'], binning_endpoints=None,
665666
intermed = ((L - viri_intervals[idx][0]) /
666667
(viri_intervals[idx][1] - viri_intervals[idx][0]))
667668

668-
float_color = colors.find_intermediate_color(
669+
float_color = clrs.find_intermediate_color(
669670
viridis_colors[idx],
670671
viridis_colors[idx],
671672
intermed,
672673
colortype='rgb'
673674
)
674675

675676
# make R,G,B into int values
676-
float_color = colors.unlabel_rgb(float_color)
677-
float_color = colors.unconvert_from_RGB_255(float_color)
678-
int_rgb = colors.convert_to_RGB_255(float_color)
679-
int_rgb = colors.label_rgb(int_rgb)
677+
float_color = clrs.unlabel_rgb(float_color)
678+
float_color = clrs.unconvert_from_RGB_255(float_color)
679+
int_rgb = clrs.convert_to_RGB_255(float_color)
680+
int_rgb = clrs.label_rgb(int_rgb)
680681

681682
colorscale.append(int_rgb)
682683

0 commit comments

Comments
 (0)