From 7a150954cbcea63aa34c43f60f72ac1468d1b4cc Mon Sep 17 00:00:00 2001 From: Chris Holdgraf Date: Fri, 20 May 2016 10:15:40 -0700 Subject: [PATCH 1/6] vectorizing some trisurf functions for performance improvement --- plotly/tools.py | 90 +++++++++++++++++++++++-------------------------- 1 file changed, 43 insertions(+), 47 deletions(-) diff --git a/plotly/tools.py b/plotly/tools.py index 0f71d950e85..e8fe75443d3 100644 --- a/plotly/tools.py +++ b/plotly/tools.py @@ -1464,11 +1464,10 @@ def _find_intermediate_color(lowcolor, highcolor, intermed): diff_1 = float(highcolor[1] - lowcolor[1]) diff_2 = float(highcolor[2] - lowcolor[2]) - new_tuple = (lowcolor[0] + intermed*diff_0, - lowcolor[1] + intermed*diff_1, - lowcolor[2] + intermed*diff_2) - - return new_tuple + inter_colors = np.array([lowcolor[0] + intermed * diff_0, + lowcolor[1] + intermed * diff_1, + lowcolor[2] + intermed * diff_2]) + return inter_colors @staticmethod def _unconvert_from_RGB_255(colors): @@ -1491,7 +1490,7 @@ def _unconvert_from_RGB_255(colors): return un_rgb_colors @staticmethod - def _map_z2color(zval, colormap, vmin, vmax): + def _map_z2color(zvals, colormap, vmin, vmax): """ Returns the color corresponding zval's place between vmin and vmax @@ -1508,21 +1507,14 @@ def _map_z2color(zval, 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 = (zval - vmin)/float((vmax - vmin)) - t_color = FigureFactory._find_intermediate_color(colormap[0], - colormap[1], - t) - t_color = (t_color[0]*255.0, t_color[1]*255.0, t_color[2]*255.0) - labelled_color = 'rgb{}'.format(t_color) - - return labelled_color - - @staticmethod - def _tri_indices(simplices): - """ - Returns a triplet of lists containing simplex coordinates - """ - return ([triplet[c] for triplet in simplices] for c in range(3)) + t = (zvals - 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 @staticmethod def _trisurf(x, y, z, simplices, colormap=None, dist_func=None, @@ -1539,11 +1531,11 @@ def _trisurf(x, y, z, simplices, colormap=None, dist_func=None, points3D = np.vstack((x, y, z)).T # vertices of the surface triangles - tri_vertices = list(map(lambda index: points3D[index], simplices)) + tri_vertices = points3D[simplices] if not dist_func: # mean values of z-coordinates of triangle vertices - mean_dists = [np.mean(tri[:, 2]) for tri in tri_vertices] + mean_dists = tri_vertices[:, :, 2].mean(-1) else: # apply user inputted function to calculate # custom coloring for triangle vertices @@ -1559,38 +1551,43 @@ def _trisurf(x, y, z, simplices, colormap=None, dist_func=None, min_mean_dists = np.min(mean_dists) max_mean_dists = np.max(mean_dists) - facecolor = ([FigureFactory._map_z2color(zz, colormap, min_mean_dists, - max_mean_dists) for zz in mean_dists]) - ii, jj, kk = FigureFactory._tri_indices(simplices) + facecolor = FigureFactory._map_z2color(mean_dists, colormap, + min_mean_dists, max_mean_dists) + ii, jj, kk = zip(*simplices) triangles = graph_objs.Mesh3d(x=x, y=y, z=z, facecolor=facecolor, i=ii, j=jj, k=kk, name='') - if plot_edges is None: # the triangle sides are not plotted + if plot_edges is not True: # the triangle sides are not plotted return graph_objs.Data([triangles]) # define the lists x_edge, y_edge and z_edge, of x, y, resp z # coordinates of edge end points for each triangle # None separates data corresponding to two consecutive triangles - lists_coord = ([[[T[k % 3][c] for k in range(4)]+[None] - for T in tri_vertices] for c in range(3)]) - if x_edge is None: - x_edge = [] - for array in lists_coord[0]: - for item in array: - x_edge.append(item) - - if y_edge is None: - y_edge = [] - for array in lists_coord[1]: - for item in array: - y_edge.append(item) - - if z_edge is None: - z_edge = [] - for array in lists_coord[2]: - for item in array: - z_edge.append(item) + is_none = [ii is None for ii in [x_edge, y_edge, z_edge]] + if any(is_none): + if not all(is_none): + raise ValueError('If any (x_edge, y_edge, z_edge) is None,' + ' all must be None') + else: + x_edge = [] + y_edge = [] + z_edge = [] + + # Pull indices we care about, then add a None column to separate tris + ixs_triangles = [0, 1, 2, 0] + pull_edges = tri_vertices[:, ixs_triangles, :] + x_edge_pull = np.hstack([pull_edges[:, :, 0], + np.tile(None, [pull_edges.shape[0], 1])]) + y_edge_pull = np.hstack([pull_edges[:, :, 1], + np.tile(None, [pull_edges.shape[0], 1])]) + z_edge_pull = np.hstack([pull_edges[:, :, 2], + np.tile(None, [pull_edges.shape[0], 1])]) + + # Now unravel the edges into a 1-d vector for plotting + x_edge = np.hstack([x_edge, x_edge_pull.reshape([1, -1])[0]]) + y_edge = np.hstack([y_edge, y_edge_pull.reshape([1, -1])[0]]) + z_edge = np.hstack([z_edge, z_edge_pull.reshape([1, -1])[0]]) # define the lines for plotting lines = graph_objs.Scatter3d( @@ -5621,4 +5618,3 @@ def make_table_annotations(self): font=dict(color=font_color), showarrow=False)) return annotations - From 694b8aa92b61bbdca8c59b017d2cbbec0830cb9b Mon Sep 17 00:00:00 2001 From: Adam Kulidjian Date: Wed, 25 May 2016 10:56:11 -0400 Subject: [PATCH 2/6] Updated test_trisurf_all_args to pass --- .../test_optional/test_figure_factory.py | 23 ++++++++++++++----- plotly/tools.py | 4 ++-- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/plotly/tests/test_optional/test_figure_factory.py b/plotly/tests/test_optional/test_figure_factory.py index 5eff6b2c16a..0dd849d266c 100644 --- a/plotly/tests/test_optional/test_figure_factory.py +++ b/plotly/tests/test_optional/test_figure_factory.py @@ -689,14 +689,14 @@ def test_trisurf_all_args(self): exp_trisurf_plot = { 'data': [ { - 'facecolor': ['rgb(143.0, 123.0, 97.000000000000014)', - 'rgb(255.0, 127.0, 14.000000000000007)', - 'rgb(143.0, 123.0, 97.000000000000014)', + 'facecolor': ['rgb(143.0, 123.0, 97.0)', + 'rgb(255.0, 127.0, 14.0)', + 'rgb(143.0, 123.0, 97.0)', 'rgb(31.0, 119.0, 180.0)', - 'rgb(143.0, 123.0, 97.000000000000014)', + 'rgb(143.0, 123.0, 97.0)', 'rgb(31.0, 119.0, 180.0)', - 'rgb(143.0, 123.0, 97.000000000000014)', - 'rgb(255.0, 127.0, 14.000000000000007)'], + 'rgb(143.0, 123.0, 97.0)', + 'rgb(255.0, 127.0, 14.0)'], 'i': [3, 1, 1, 5, 7, 3, 5, 7], 'j': [1, 3, 5, 1, 3, 7, 7, 5], 'k': [4, 0, 4, 2, 4, 6, 4, 8], @@ -753,6 +753,17 @@ def test_trisurf_all_args(self): self.assert_dict_equal(test_trisurf_plot['data'][1], exp_trisurf_plot['data'][1]) + def test_optimize_trisurf(self): + + # check that trisurf will give warnings if the plotting will take + # a long time + + pass + + + + + class TestScatterPlotMatrix(NumpyTestUtilsMixin, TestCase): diff --git a/plotly/tools.py b/plotly/tools.py index e8fe75443d3..4f02a6b36da 100644 --- a/plotly/tools.py +++ b/plotly/tools.py @@ -1567,8 +1567,8 @@ def _trisurf(x, y, z, simplices, colormap=None, dist_func=None, is_none = [ii is None for ii in [x_edge, y_edge, z_edge]] if any(is_none): if not all(is_none): - raise ValueError('If any (x_edge, y_edge, z_edge) is None,' - ' all must be None') + raise ValueError("If any (x_edge, y_edge, z_edge) is None, " + "all must be None") else: x_edge = [] y_edge = [] From 84a65cd8e7c14502650ea8621f4db861ac20f924 Mon Sep 17 00:00:00 2001 From: Adam Kulidjian Date: Wed, 25 May 2016 11:19:56 -0400 Subject: [PATCH 3/6] Updated version number --- plotly/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plotly/version.py b/plotly/version.py index 52af183e57d..ff987d280a1 100644 --- a/plotly/version.py +++ b/plotly/version.py @@ -1 +1 @@ -__version__ = '1.10.0' +__version__ = '1.10.1' From 8e1fa81a9a7f486404e7be00afb71f6e4c5e380b Mon Sep 17 00:00:00 2001 From: Adam Kulidjian Date: Wed, 25 May 2016 11:21:16 -0400 Subject: [PATCH 4/6] Fixed version back --- plotly/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plotly/version.py b/plotly/version.py index ff987d280a1..52af183e57d 100644 --- a/plotly/version.py +++ b/plotly/version.py @@ -1 +1 @@ -__version__ = '1.10.1' +__version__ = '1.10.0' From 09d04f9cbad521580a99516002ff7d17d108b8fb Mon Sep 17 00:00:00 2001 From: Adam Kulidjian Date: Wed, 25 May 2016 11:25:45 -0400 Subject: [PATCH 5/6] Changed version number to '1.10.1' --- plotly/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plotly/version.py b/plotly/version.py index 52af183e57d..ff987d280a1 100644 --- a/plotly/version.py +++ b/plotly/version.py @@ -1 +1 @@ -__version__ = '1.10.0' +__version__ = '1.10.1' From d13420f7ce0782403cab9761750fd3b96ddce9fc Mon Sep 17 00:00:00 2001 From: Adam Kulidjian Date: Wed, 25 May 2016 12:17:54 -0400 Subject: [PATCH 6/6] Removed empty optimize test//added check for x, y, z_edges all same length --- plotly/tests/test_optional/test_figure_factory.py | 11 ----------- plotly/tools.py | 4 ++++ 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/plotly/tests/test_optional/test_figure_factory.py b/plotly/tests/test_optional/test_figure_factory.py index 0dd849d266c..9c038c540d2 100644 --- a/plotly/tests/test_optional/test_figure_factory.py +++ b/plotly/tests/test_optional/test_figure_factory.py @@ -753,17 +753,6 @@ def test_trisurf_all_args(self): self.assert_dict_equal(test_trisurf_plot['data'][1], exp_trisurf_plot['data'][1]) - def test_optimize_trisurf(self): - - # check that trisurf will give warnings if the plotting will take - # a long time - - pass - - - - - class TestScatterPlotMatrix(NumpyTestUtilsMixin, TestCase): diff --git a/plotly/tools.py b/plotly/tools.py index 4f02a6b36da..98f12e83992 100644 --- a/plotly/tools.py +++ b/plotly/tools.py @@ -1589,6 +1589,10 @@ def _trisurf(x, y, z, simplices, colormap=None, dist_func=None, y_edge = np.hstack([y_edge, y_edge_pull.reshape([1, -1])[0]]) z_edge = np.hstack([z_edge, z_edge_pull.reshape([1, -1])[0]]) + if not (len(x_edge) == len(y_edge) == len(z_edge)): + raise exceptions.PlotlyError("The lengths of x_edge, y_edge and " + "z_edge are not the same.") + # define the lines for plotting lines = graph_objs.Scatter3d( x=x_edge, y=y_edge, z=z_edge, mode='lines',