Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit bef62ef

Browse filesBrowse files
committed
Merge pull request #486 from plotly/choldgraf-custom_colors_trisurf
Choldgraf custom colors trisurf
2 parents cf48f62 + 1ae5545 commit bef62ef
Copy full SHA for bef62ef

File tree

Expand file treeCollapse file tree

2 files changed

+53
-21
lines changed
Filter options
Expand file treeCollapse file tree

2 files changed

+53
-21
lines changed

‎plotly/tests/test_optional/test_figure_factory.py

Copy file name to clipboardExpand all lines: plotly/tests/test_optional/test_figure_factory.py
+20Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -913,6 +913,26 @@ def test_trisurf_all_args(self):
913913
self.assert_dict_equal(test_trisurf_plot['data'][1],
914914
exp_trisurf_plot['data'][1])
915915

916+
# Test passing custom colors
917+
colors_raw = np.random.randn(simplices.shape[0])
918+
colors_str = ['rgb(%s, %s, %s)' % (i, j, k)
919+
for i, j, k in np.random.randn(simplices.shape[0], 3)]
920+
921+
# Color == strings should be kept the same
922+
test_colors_plot = tls.FigureFactory.create_trisurf(
923+
x, y, z, simplices, color_func=colors_str)
924+
self.assertListEqual(list(test_colors_plot['data'][0]['facecolor']),
925+
list(colors_str))
926+
# Colors must match length of simplices
927+
colors_bad = colors_str[:-1]
928+
self.assertRaises(ValueError, tls.FigureFactory.create_trisurf, x, y,
929+
z, simplices, color_func=colors_bad)
930+
# Check converting custom colors to strings
931+
test_colors_plot = tls.FigureFactory.create_trisurf(
932+
x, y, z, simplices, color_func=colors_raw)
933+
self.assertTrue(isinstance(test_colors_plot['data'][0]['facecolor'][0],
934+
str))
935+
916936

917937
class TestScatterPlotMatrix(NumpyTestUtilsMixin, TestCase):
918938

‎plotly/tools.py

Copy file name to clipboardExpand all lines: plotly/tools.py
+33-21Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1503,11 +1503,11 @@ def _unconvert_from_RGB_255(colors):
15031503
return un_rgb_colors
15041504

15051505
@staticmethod
1506-
def _map_z2color(zvals, colormap, vmin, vmax):
1506+
def _map_array2color(array, colormap, vmin, vmax):
15071507
"""
1508-
Returns the color corresponding zval's place between vmin and vmax
1508+
Normalize values in array by vmin/vmax and return plotly color strings.
15091509
1510-
This function takes a z value (zval) along with a colormap and a
1510+
This function takes an array of values along with a colormap and a
15111511
minimum (vmin) and maximum (vmax) range of possible z values for the
15121512
given parametrized surface. It returns an rgb color based on the
15131513
relative position of zval between vmin and vmax
@@ -1520,7 +1520,7 @@ def _map_z2color(zvals, colormap, vmin, vmax):
15201520
"of vmax.")
15211521
# find distance t of zval from vmin to vmax where the distance
15221522
# is normalized to be between 0 and 1
1523-
t = (zvals - vmin) / float((vmax - vmin))
1523+
t = (array - vmin) / float((vmax - vmin))
15241524
t_colors = FigureFactory._find_intermediate_color(colormap[0],
15251525
colormap[1],
15261526
t)
@@ -1542,34 +1542,46 @@ def _trisurf(x, y, z, simplices, colormap=None, color_func=None,
15421542
import numpy as np
15431543
from plotly.graph_objs import graph_objs
15441544
points3D = np.vstack((x, y, z)).T
1545+
simplices = np.atleast_2d(simplices)
15451546

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

1549-
if not color_func:
1550+
# Define colors for the triangle faces
1551+
if color_func is None:
15501552
# mean values of z-coordinates of triangle vertices
15511553
mean_dists = tri_vertices[:, :, 2].mean(-1)
1554+
elif isinstance(color_func, (list, np.ndarray)):
1555+
# Pre-computed list / array of values to map onto color
1556+
if len(color_func) != len(simplices):
1557+
raise ValueError("If color_func is a list/array, it must "
1558+
"be the same length as simplices.")
1559+
mean_dists = np.asarray(color_func)
15521560
else:
15531561
# apply user inputted function to calculate
15541562
# custom coloring for triangle vertices
15551563
mean_dists = []
1556-
15571564
for triangle in tri_vertices:
15581565
dists = []
15591566
for vertex in triangle:
15601567
dist = color_func(vertex[0], vertex[1], vertex[2])
15611568
dists.append(dist)
1562-
15631569
mean_dists.append(np.mean(dists))
1570+
mean_dists = np.asarray(mean_dists)
15641571

1565-
min_mean_dists = np.min(mean_dists)
1566-
max_mean_dists = np.max(mean_dists)
1567-
facecolor = FigureFactory._map_z2color(mean_dists,
1568-
colormap,
1569-
min_mean_dists,
1570-
max_mean_dists)
1571-
1572-
ii, jj, kk = zip(*simplices)
1572+
# Check if facecolors are already strings and can be skipped
1573+
if isinstance(mean_dists[0], str):
1574+
facecolor = mean_dists
1575+
else:
1576+
min_mean_dists = np.min(mean_dists)
1577+
max_mean_dists = np.max(mean_dists)
1578+
facecolor = FigureFactory._map_array2color(mean_dists,
1579+
colormap,
1580+
min_mean_dists,
1581+
max_mean_dists)
1582+
# Make sure we have arrays to speed up plotting
1583+
facecolor = np.asarray(facecolor)
1584+
ii, jj, kk = simplices.T
15731585
triangles = graph_objs.Mesh3d(x=x, y=y, z=z, facecolor=facecolor,
15741586
i=ii, j=jj, k=kk, name='')
15751587

@@ -1634,30 +1646,30 @@ def create_trisurf(x, y, z, simplices, colormap=None, color_func=None,
16341646
:param (array) z: data values of z in a 1D array
16351647
:param (array) simplices: an array of shape (ntri, 3) where ntri is
16361648
the number of triangles in the triangularization. Each row of the
1637-
array contains the indicies of the verticies of each triangle.
1649+
array contains the indicies of the verticies of each triangle
16381650
:param (str|list) colormap: either a plotly scale name, or a list
16391651
containing 2 triplets. These triplets must be of the form (a,b,c)
16401652
or 'rgb(x,y,z)' where a,b,c belong to the interval [0,1] and x,y,z
16411653
belong to [0,255]
16421654
:param (function|list) color_func: The parameter that determines the
16431655
coloring of the surface. Takes either a function with 3 arguments
16441656
x, y, z or a list/array of color values the same length as
1645-
simplices. If set to None, color will only depend on the z axis.
1657+
simplices. If set to None, color will only depend on the z axis
16461658
:param (str) title: title of the plot
16471659
:param (bool) plot_edges: determines if the triangles on the trisurf
16481660
are visible
16491661
:param (bool) showbackground: makes background in plot visible
16501662
:param (str) backgroundcolor: color of background. Takes a string of
1651-
the form 'rgb(x,y,z)' x,y,z are between 0 and 255 inclusive.
1663+
the form 'rgb(x,y,z)' x,y,z are between 0 and 255 inclusive
16521664
:param (str) gridcolor: color of the gridlines besides the axes. Takes
16531665
a string of the form 'rgb(x,y,z)' x,y,z are between 0 and 255
1654-
inclusive.
1666+
inclusive
16551667
:param (str) zerolinecolor: color of the axes. Takes a string of the
1656-
form 'rgb(x,y,z)' x,y,z are between 0 and 255 inclusive.
1668+
form 'rgb(x,y,z)' x,y,z are between 0 and 255 inclusive
16571669
:param (int|float) height: the height of the plot (in pixels)
16581670
:param (int|float) width: the width of the plot (in pixels)
16591671
:param (dict) aspectratio: a dictionary of the aspect ratio values for
1660-
the x, y and z axes. 'x', 'y' and 'z' take (int|float) values.
1672+
the x, y and z axes. 'x', 'y' and 'z' take (int|float) values
16611673
16621674
Example 1: Sphere
16631675
```

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.