Skip to content

Custom colors trisurf #484

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

Merged
merged 2 commits into from
May 27, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions plotly/tests/test_optional/test_figure_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -753,6 +753,26 @@ def test_trisurf_all_args(self):
self.assert_dict_equal(test_trisurf_plot['data'][1],
exp_trisurf_plot['data'][1])

# Test passing custom colors
colors_raw = np.random.randn(simplices.shape[0])
colors_str = ['rgb(%s, %s, %s)' % (i, j, k)
for i, j, k in np.random.randn(simplices.shape[0], 3)]

# Color == strings should be kept the same
test_colors_plot = tls.FigureFactory.create_trisurf(
x, y, z, simplices, color_func=colors_str)
self.assertListEqual(list(test_colors_plot['data'][0]['facecolor']),
list(colors_str))
# Colors must match length of simplices
colors_bad = colors_str[:-1]
self.assertRaises(ValueError, tls.FigureFactory.create_trisurf, x, y,
z, simplices, color_func=colors_bad)
# Check converting custom colors to strings
test_colors_plot = tls.FigureFactory.create_trisurf(
x, y, z, simplices, color_func=colors_raw)
self.assertTrue(isinstance(test_colors_plot['data'][0]['facecolor'][0],
str))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for adding these 😺



class TestScatterPlotMatrix(NumpyTestUtilsMixin, TestCase):

Expand Down
42 changes: 27 additions & 15 deletions plotly/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -1490,11 +1490,11 @@ def _unconvert_from_RGB_255(colors):
return un_rgb_colors

@staticmethod
def _map_z2color(zvals, colormap, vmin, vmax):
def _map_array2color(array, colormap, vmin, vmax):
"""
Returns the color corresponding zval's place between vmin and vmax
Normalize values in array by vmin/vmax and return plotly color strings.

This function takes a z value (zval) along with a colormap and a
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
Expand All @@ -1507,7 +1507,7 @@ def _map_z2color(zvals, colormap, vmin, vmax):
"of vmax.")
# find distance t of zval from vmin to vmax where the distance
# is normalized to be between 0 and 1
t = (zvals - vmin) / float((vmax - vmin))
t = (array - vmin) / float((vmax - vmin))
t_colors = FigureFactory._find_intermediate_color(colormap[0],
colormap[1],
t)
Expand All @@ -1529,34 +1529,46 @@ def _trisurf(x, y, z, simplices, colormap=None, color_func=None,
import numpy as np
from plotly.graph_objs import graph_objs
points3D = np.vstack((x, y, z)).T
simplices = np.atleast_2d(simplices)

# vertices of the surface triangles
tri_vertices = points3D[simplices]

if not color_func:
# Define colors for the triangle faces
if color_func is None:
# mean values of z-coordinates of triangle vertices
mean_dists = tri_vertices[:, :, 2].mean(-1)
elif isinstance(color_func, (list, np.ndarray)):
# Pre-computed list / array of values to map onto color
if len(color_func) != len(simplices):
raise ValueError('If color_func is a list/array, must'
' be the same length as simplices')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🐐 (grammar goat), sorry we rely heavily on emojis for code reviews at Plotly.

'If color_func is a list/array, it must be the same length as simplices.'

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

haha, will do. I think I left off the it because I was trying to keep the line under PEP8 max, but ended up splitting it anyway. I had a PR last week where someone got me for including a dangling participle :D

mean_dists = np.asarray(color_func)
else:
# apply user inputted function to calculate
# custom coloring for triangle vertices
mean_dists = []

for triangle in tri_vertices:
dists = []
for vertex in triangle:
dist = color_func(vertex[0], vertex[1], vertex[2])
dists.append(dist)

mean_dists.append(np.mean(dists))
mean_dists = np.asarray(mean_dists)

min_mean_dists = np.min(mean_dists)
max_mean_dists = np.max(mean_dists)
facecolor = FigureFactory._map_z2color(mean_dists,
colormap,
min_mean_dists,
max_mean_dists)

ii, jj, kk = zip(*simplices)
# Check if facecolors are already strings and can be skipped
if isinstance(mean_dists[0], str):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this fail if folks are using python 2.7 with unicode? can we check against basestring here or use six?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's a good question....I'm open to another way of doing it, you might be right

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we check against basestring here or use six

I don't know if this is relevant/has been answered, but I know for sure that basestring won't work between 2 and 3. str works fine though.

I'll have a look tomorrow though at the rest.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cool so then it's OK as is?

On Thu, May 26, 2016 at 6:44 PM, Adam Kulidjian [email protected]
wrote:

In plotly/tools.py
#484 (comment):

  •    min_mean_dists = np.min(mean_dists)
    
  •    max_mean_dists = np.max(mean_dists)
    
  •    facecolor = FigureFactory._map_z2color(mean_dists,
    
  •                                           colormap,
    
  •                                           min_mean_dists,
    

- max_mean_dists)

  •    ii, jj, kk = zip(*simplices)
    
  •    # Check if facecolors are already strings and can be skipped
    
  •    if isinstance(mean_dists[0], str):
    

can we check against basestring here or use six

I don't know if this is relevant/has been answered, but I know for sure
that basestring won't work between 2 and 3. str works fine though.

I'll have a look tomorrow though at the rest.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/plotly/plotly.py/pull/484/files/bed542d3a268a2c469a724570ed03965903ff115#r64847443,
or mute the thread
https://github.com/notifications/unsubscribe/ABwSHQyT6EFye1WR84zJeb13l3SEMAwvks5qFkyYgaJpZM4Invo8
.

facecolor = mean_dists
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)
# Make sure we have arrays to speed up plotting
facecolor = np.asarray(facecolor)
ii, jj, kk = simplices.T
triangles = graph_objs.Mesh3d(x=x, y=y, z=z, facecolor=facecolor,
i=ii, j=jj, k=kk, name='')

Expand Down