-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Allow more than 2 colormaps again #493
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1468,9 +1468,9 @@ def _find_intermediate_color(lowcolor, highcolor, intermed): | |
diff_1 = float(highcolor[1] - lowcolor[1]) | ||
diff_2 = float(highcolor[2] - lowcolor[2]) | ||
|
||
inter_colors = np.array([lowcolor[0] + intermed * diff_0, | ||
lowcolor[1] + intermed * diff_1, | ||
lowcolor[2] + intermed * diff_2]) | ||
inter_colors = (lowcolor[0] + intermed * diff_0, | ||
lowcolor[1] + intermed * diff_1, | ||
lowcolor[2] + intermed * diff_2) | ||
return inter_colors | ||
|
||
@staticmethod | ||
|
@@ -1503,35 +1503,52 @@ def _unconvert_from_RGB_255(colors): | |
return un_rgb_colors | ||
|
||
@staticmethod | ||
def _map_array2color(array, colormap, vmin, vmax): | ||
def _map_face2color(face, colormap, vmin, vmax): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is support for multiple colormaps mentioned in the docstring for trisurf anywhere? (or is it supported in a different function that calls this function?) I didn't see any mention of multiple colormaps. What's the usecase for including multiple colormaps in the call to trisurf, e.g., how would people specify which colormap goes with which datapoint? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Kully and @choldgraf did you guys resolve this one? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I see now what @Kully was getting at, though it took a fair bit of digging for me to figure it out. I wanted to ask - in terms of interpolating between points of a list of multiple colormaps, why not use |
||
""" | ||
Normalize values in array by vmin/vmax and return plotly color strings. | ||
Normalize facecolor values by vmin/vmax and return rgb-color strings | ||
|
||
This function takes an array of values along with a colormap and a | ||
minimum (vmin) and maximum (vmax) range of possible z values for the | ||
given parametrized surface. It returns an rgb color based on the | ||
relative position of zval between vmin and vmax | ||
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.") | ||
# find distance t of zval from vmin to vmax where the distance | ||
# is normalized to be between 0 and 1 | ||
t = (array - vmin) / float((vmax - vmin)) | ||
t_colors = FigureFactory._find_intermediate_color(colormap[0], | ||
colormap[1], | ||
t) | ||
t_colors = t_colors * 255. | ||
labelled_colors = ['rgb(%s, %s, %s)' % (i, j, k) | ||
for i, j, k in t_colors.T] | ||
return labelled_colors | ||
|
||
if len(colormap) == 1: | ||
# color each triangle face with the same color in colormap | ||
face_color = colormap[0] | ||
face_color = FigureFactory._convert_to_RGB_255(face_color) | ||
face_color = FigureFactory._label_rgb(face_color) | ||
else: | ||
if face == vmax: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is even clearer than what I was suggesting. thanks :) |
||
# pick last color in colormap | ||
face_color = colormap[-1] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎉 🔔 🎆 |
||
face_color = FigureFactory._convert_to_RGB_255(face_color) | ||
face_color = FigureFactory._label_rgb(face_color) | ||
else: | ||
# 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 = FigureFactory._find_intermediate_color( | ||
colormap[low_color_index], | ||
colormap[low_color_index + 1], | ||
t * (len(colormap) - 1) - low_color_index) | ||
face_color = FigureFactory._convert_to_RGB_255(face_color) | ||
face_color = FigureFactory._label_rgb(face_color) | ||
|
||
return face_color | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💥 so much more readable! thanks! |
||
|
||
@staticmethod | ||
def _trisurf(x, y, z, simplices, colormap=None, color_func=None, | ||
plot_edges=False, x_edge=None, y_edge=None, z_edge=None): | ||
plot_edges=False, x_edge=None, y_edge=None, z_edge=None, | ||
facecolor=None): | ||
""" | ||
Refer to FigureFactory.create_trisurf() for docstring | ||
""" | ||
|
@@ -1556,8 +1573,10 @@ def _trisurf(x, y, z, simplices, colormap=None, color_func=None, | |
if len(color_func) != len(simplices): | ||
raise ValueError("If color_func is a list/array, it must " | ||
"be the same length as simplices.") | ||
# convert all colors to rgb | ||
for index in range(len(color_func)): | ||
|
||
# convert all colors to rgb | ||
for index in range(len(color_func)): | ||
if isinstance(color_func[index], str): | ||
if '#' in color_func[index]: | ||
foo = FigureFactory._hex_to_rgb(color_func[index]) | ||
color_func[index] = FigureFactory._label_rgb(foo) | ||
|
@@ -1581,10 +1600,16 @@ def _trisurf(x, y, z, simplices, colormap=None, color_func=None, | |
else: | ||
min_mean_dists = np.min(mean_dists) | ||
max_mean_dists = np.max(mean_dists) | ||
facecolor = FigureFactory._map_array2color(mean_dists, | ||
colormap, | ||
min_mean_dists, | ||
max_mean_dists) | ||
|
||
if facecolor is None: | ||
facecolor = [] | ||
for index in range(len(mean_dists)): | ||
color = FigureFactory._map_face2color(mean_dists[index], | ||
colormap, | ||
min_mean_dists, | ||
max_mean_dists) | ||
facecolor.append(color) | ||
|
||
# Make sure we have arrays to speed up plotting | ||
facecolor = np.asarray(facecolor) | ||
ii, jj, kk = simplices.T | ||
|
@@ -1653,10 +1678,12 @@ def create_trisurf(x, y, z, simplices, colormap=None, color_func=None, | |
:param (array) simplices: an array of shape (ntri, 3) where ntri is | ||
the number of triangles in the triangularization. Each row of the | ||
array contains the indicies of the verticies of each triangle | ||
:param (str|list) colormap: either a plotly scale name, or a list | ||
containing 2 triplets. These triplets must be of the form (a,b,c) | ||
or 'rgb(x,y,z)' where a,b,c belong to the interval [0,1] and x,y,z | ||
belong to [0,255] | ||
:param (str|tuple|list) colormap: either a plotly scale name, an rgb | ||
or hex color, a color tuple or a list of colors. An rgb color is | ||
of the form 'rgb(x, y, z)' where x, y, z belong to the interval | ||
[0, 255] and a color tuple is a tuple of the form (a, b, c) where | ||
a, b and c belong to [0, 1]. If colormap is a list, it must | ||
contain the valid color types aforementioned as its members. | ||
:param (function|list) color_func: The parameter that determines the | ||
coloring of the surface. Takes either a function with 3 arguments | ||
x, y, z or a list/array of color values the same length as | ||
|
@@ -2931,11 +2958,13 @@ def _label_rgb(colors): | |
|
||
""" | ||
if isinstance(colors, tuple): | ||
return 'rgb{}'.format(colors) | ||
return ('rgb(%s, %s, %s)' % (colors[0], colors[1], colors[2])) | ||
else: | ||
colors_label = [] | ||
for color in colors: | ||
color_label = 'rgb{}'.format(color) | ||
color_label = ('rgb(%s, %s, %s)' % (color[0], | ||
color[1], | ||
color[2])) | ||
colors_label.append(color_label) | ||
|
||
return colors_label | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the benefit gained by making it a list and looping through? IME using arrays instead of lists almost always makes things much faster.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't necessarily think it's faster or anything like that. I actually just switched it back to this because I wanted it to work with my FF converting code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm wondering if there's a benefit other than speed. E.g., if you thought the user might pass in tuples of variable shapes then it's probably better for the input to be a list or tuple or something (since arrays require consistency across dimensions). If you like, maybe I can take a pass through and make it work w/ arrays similar to the last PR. I don't think the syntax would be any different, and it'll likely be an order of magnitude faster to use arrays.