sympy-plot-backends 2.0.2__tar.gz → 2.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/PKG-INFO +1 -1
  2. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/setup.py +1 -1
  3. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/spb/__init__.py +4 -6
  4. sympy_plot_backends-2.2.0/spb/_version.py +1 -0
  5. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/spb/backends/base_backend.py +14 -18
  6. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/spb/backends/bokeh.py +77 -24
  7. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/spb/backends/k3d.py +20 -15
  8. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/spb/backends/matplotlib.py +105 -56
  9. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/spb/backends/plotly.py +92 -38
  10. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/spb/ccomplex/complex.py +546 -71
  11. sympy_plot_backends-2.2.0/spb/ccomplex/wegert.py +449 -0
  12. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/spb/defaults.py +5 -4
  13. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/spb/functions.py +182 -101
  14. sympy_plot_backends-2.2.0/spb/plotgrid.py +376 -0
  15. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/spb/series.py +214 -91
  16. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/spb/utils.py +24 -7
  17. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/spb/vectors.py +9 -12
  18. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/sympy_plot_backends.egg-info/PKG-INFO +1 -1
  19. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/tests/backends/make_tests.py +63 -0
  20. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/tests/backends/test_bokeh.py +104 -0
  21. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/tests/backends/test_k3d.py +9 -1
  22. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/tests/backends/test_matplotlib.py +177 -1
  23. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/tests/backends/test_plotly.py +174 -3
  24. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/tests/test_complex.py +112 -2
  25. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/tests/test_functions.py +644 -5
  26. sympy_plot_backends-2.2.0/tests/test_plotgrid.py +326 -0
  27. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/tests/test_series.py +89 -3
  28. sympy_plot_backends-2.2.0/tests/test_utils.py +167 -0
  29. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/tests/test_vectors.py +35 -0
  30. sympy_plot_backends-2.0.2/spb/_version.py +0 -1
  31. sympy_plot_backends-2.0.2/spb/ccomplex/wegert.py +0 -281
  32. sympy_plot_backends-2.0.2/spb/plotgrid.py +0 -223
  33. sympy_plot_backends-2.0.2/tests/test_plotgrid.py +0 -221
  34. sympy_plot_backends-2.0.2/tests/test_utils.py +0 -623
  35. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/LICENSE +0 -0
  36. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/MANIFEST.in +0 -0
  37. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/README.md +0 -0
  38. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/setup.cfg +0 -0
  39. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/spb/backends/__init__.py +0 -0
  40. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/spb/backends/mayavi.py +0 -0
  41. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/spb/backends/utils.py +0 -0
  42. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/spb/ccomplex/__init__.py +0 -0
  43. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/spb/doc_utils.py +0 -0
  44. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/spb/interactive/__init__.py +0 -0
  45. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/spb/interactive/bootstrap_spb/__init__.py +0 -0
  46. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/spb/interactive/bootstrap_spb/bootstrap.css +0 -0
  47. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/spb/interactive/bootstrap_spb/bootstrap.html +0 -0
  48. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/spb/interactive/bootstrap_spb/dark.css +0 -0
  49. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/spb/interactive/ipywidgets.py +0 -0
  50. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/spb/interactive/panel.py +0 -0
  51. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/sympy_plot_backends.egg-info/SOURCES.txt +0 -0
  52. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/sympy_plot_backends.egg-info/dependency_links.txt +0 -0
  53. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/sympy_plot_backends.egg-info/not-zip-safe +0 -0
  54. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/sympy_plot_backends.egg-info/requires.txt +0 -0
  55. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/sympy_plot_backends.egg-info/top_level.txt +0 -0
  56. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/tests/backends/__init__.py +0 -0
  57. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/tests/backends/test_base_backend.py +0 -0
  58. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/tests/test_color_utils.py +0 -0
  59. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/tests/test_defaults.py +0 -0
  60. {sympy_plot_backends-2.0.2 → sympy_plot_backends-2.2.0}/tests/test_doc_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sympy_plot_backends
3
- Version: 2.0.2
3
+ Version: 2.2.0
4
4
  Summary: Backends for plotting with SymPy
5
5
  Home-page: https://github.com/Davide-sd/sympy-plot-backends
6
6
  Author: Davide Sandona
@@ -62,7 +62,7 @@ setup(
62
62
  "appdirs>=1.4.4",
63
63
  "numpy>=1.21.1",
64
64
  "sympy>=1.10.1",
65
- "matplotlib>3.4.2", # v3.4.2 is required for tests to pass
65
+ "matplotlib>3.4.2",
66
66
  "mergedeep>=1.3.4",
67
67
  ],
68
68
  extras_require={
@@ -20,14 +20,11 @@ from spb.functions import (
20
20
  from spb.vectors import plot_vector
21
21
  from spb.ccomplex.complex import (
22
22
  plot_complex, plot_complex_list,
23
- plot_real_imag, plot_complex_vector
23
+ plot_real_imag, plot_complex_vector, plot_riemann_sphere
24
24
  )
25
25
  from spb.utils import prange
26
26
 
27
- from spb.plotgrid import plotgrid
28
- # NOTE: it would be nice to have `iplot` readily available, however loading
29
- # `panel` is a slow operation.
30
- # from spb.interactive import iplot
27
+ from spb.plotgrid import plotgrid, PlotGrid
31
28
 
32
29
  from spb.backends.matplotlib import MB
33
30
  from spb.backends.bokeh import BB
@@ -42,5 +39,6 @@ __all__ = [
42
39
  "plot3d_revolution", "plot_implicit", "plot_polar", "plot_geometry",
43
40
  "plot_list", "plot_piecewise", "plot_vector", "plot_complex",
44
41
  "plot_complex_list", "plot_real_imag", "plot_complex_vector", "plotgrid",
45
- "MB", "BB", "PB", "KB", "MAB", "plot3d_list", "prange"
42
+ "MB", "BB", "PB", "KB", "MAB", "plot3d_list", "prange",
43
+ "plot_riemann_sphere", "PlotGrid"
46
44
  ]
@@ -0,0 +1 @@
1
+ __version__ = "2.2.0"
@@ -177,9 +177,9 @@ class Plot:
177
177
  ranges over [-pi, pi]).
178
178
  """
179
179
 
180
- _allowed_keys = ["aspect", "axis", "axis_center", "backend",
180
+ _allowed_keys = ["aspect", "axis", "axis_center", "backend", "aouc",
181
181
  "detect_poles", "grid", "legend", "show", "size", "title", "use_latex",
182
- "xlabel", "ylabel", "zlabel", "xlim", "ylim", "zlim",
182
+ "xlabel", "ylabel", "zlabel", "xlim", "ylim", "zlim", "show_axis",
183
183
  "xscale", "yscale", "zscale", "process_piecewise", "polar_axis", "imodule"]
184
184
  """contains a list of public keyword arguments supported by the series.
185
185
  It will be used to validate the user-provided keyword arguments.
@@ -249,6 +249,8 @@ class Plot:
249
249
  # backend might need to create different types of figure depending on
250
250
  # the interactive module being used
251
251
  self.imodule = kwargs.get("imodule", None)
252
+ # add annotations on unit circle in the complex plane.
253
+ self.aouc = kwargs.get("aouc", None)
252
254
 
253
255
  # Contains the data objects to be plotted. The backend should be smart
254
256
  # enough to iterate over this list.
@@ -269,18 +271,15 @@ class Plot:
269
271
  # Automatic legend: if more than 1 data series has been provided
270
272
  # and the user has not set legend=False, then show the legend for
271
273
  # better clarity.
272
- self.legend = _legend = kwargs.get("legend", None)
273
- if not self.legend:
274
- self.legend = False
275
- if (len([s for s in self._series if s.show_in_legend]) > 1) or (
276
- any(s.is_parametric and s.use_cm for s in self._series)):
274
+ self.legend = kwargs.get("legend", None)
275
+ if self.legend is None:
276
+ # if len([s for s in self._series if s.show_in_legend]) > 1:
277
+ if len([s for s in self._series
278
+ if s.show_in_legend and (not s.use_cm)]) > 1:
277
279
  # don't show the legend if `plot_piecewise` created this
278
280
  # backend
279
- if ((not ("process_piecewise" in kwargs.keys())) and
280
- ((_legend is True) or (_legend is None))):
281
+ if not ("process_piecewise" in kwargs.keys()):
281
282
  self.legend = True
282
- if self.legend and (len([s for s in self._series if s.is_3Dsurface and not s.use_cm]) > 1):
283
- self.legend = False
284
283
 
285
284
  # Objects used to render/display the plots, which depends on the
286
285
  # plotting library.
@@ -308,6 +307,7 @@ class Plot:
308
307
  check_and_set("zlim", kwargs.get("zlim", None))
309
308
  self.size = None
310
309
  check_and_set("size", kwargs.get("size", None))
310
+ self.show_axis = kwargs.get("show_axis", True)
311
311
 
312
312
  def _copy_kwargs(self):
313
313
  """Copy the values of the plot attributes into a dictionary which will
@@ -333,7 +333,9 @@ class Plot:
333
333
  is_iplot=self.is_iplot,
334
334
  use_latex=self._use_latex,
335
335
  camera=self.camera,
336
- polar_axis=self.polar_axis
336
+ polar_axis=self.polar_axis,
337
+ aouc=self.aouc,
338
+ show_axis=self.show_axis,
337
339
  )
338
340
 
339
341
  def _init_cyclers(self):
@@ -476,12 +478,6 @@ class Plot:
476
478
  series.extend(self.series)
477
479
  series.extend(other.series)
478
480
  kwargs = self._do_sum_kwargs(self, other)
479
- # If the first plot (`p1`) of the summation has been created without
480
- # specifying `legend`, then `p1.legend` might be False, hence
481
- # `kwargs["legend"]` might be False. But when adding multiple plots
482
- # it is very likely that user expect a legend to be shown. Hence,
483
- # reset legend and let the backend decide if it needs one or not.
484
- kwargs["legend"] = None
485
481
  return type(self)(*series, **kwargs)
486
482
 
487
483
  def append(self, arg):
@@ -1,6 +1,7 @@
1
1
  import os
2
2
  from spb.defaults import cfg
3
3
  from spb.backends.base_backend import Plot
4
+ from spb.series import GenericDataSeries, List2DSeries
4
5
  from sympy.external import import_module
5
6
  import warnings
6
7
 
@@ -214,6 +215,10 @@ class BokehBackend(Plot):
214
215
  * Default options for streamline plots:
215
216
  ``dict(line_width=2, line_alpha=0.8)``
216
217
 
218
+ show_axis : boolean, optional
219
+ Turns on/off the axis visibility (and associated tick labels).
220
+ Default to True (axis are visible).
221
+
217
222
  theme : str, optional
218
223
  Set the theme. Find more Bokeh themes at [#fn2]_ .
219
224
 
@@ -349,6 +354,7 @@ class BokehBackend(Plot):
349
354
  if self.ylim:
350
355
  kw["y_range"] = self.ylim
351
356
  self._fig = self.bokeh.plotting.figure(**kw)
357
+ self._fig.axis.visible = self.show_axis
352
358
  self.grid = kwargs.get("grid", cfg["bokeh"]["grid"])
353
359
  self._fig.grid.visible = self.grid
354
360
  if cfg["bokeh"]["show_minor_grid"]:
@@ -356,6 +362,33 @@ class BokehBackend(Plot):
356
362
  self._fig.grid.minor_grid_line_color = self._fig.grid.grid_line_color[0]
357
363
  self._fig.grid.minor_grid_line_dash = cfg["bokeh"]["minor_grid_line_dash"]
358
364
 
365
+ if self.aouc:
366
+ pixel_offset = 15
367
+ # assumption: there is only one data series being plotted.
368
+ sign = 1
369
+ labels = ["0", "i", "-i", "1"]
370
+ if self.series[0].at_infinity:
371
+ labels[0] = "inf"
372
+ sign = -1
373
+ source = self.bokeh.models.ColumnDataSource(data={
374
+ "x": [0, 0, 0, 1], "y": [0, 1, -1, 0], "labels": labels,
375
+ "x_offset": [pixel_offset, 0, 0, sign * pixel_offset],
376
+ "y_offset": [0, pixel_offset, -pixel_offset, 0]
377
+ })
378
+ new_series = [
379
+ List2DSeries([1, 0, 0], [0, 1, -1], is_point=True,
380
+ is_filled=False, show_in_legend=False,
381
+ rendering_kw={"color": "#000000", "marker": "circle", "size": 6}),
382
+ List2DSeries([0], [0], is_point=True,
383
+ is_filled=(not self.series[0].at_infinity), show_in_legend=False,
384
+ rendering_kw={"color": "#000000", "marker": "circle", "size": 6}),
385
+ GenericDataSeries("annotations", x="x", y="y", text="labels",
386
+ x_offset="x_offset", y_offset="y_offset", source=source,
387
+ text_baseline="middle", text_align="center",
388
+ text_font_style="bold", text_color="#000000"),
389
+ ]
390
+ self._series = self._series + new_series
391
+
359
392
  @property
360
393
  def fig(self):
361
394
  """Returns the figure."""
@@ -408,7 +441,7 @@ class BokehBackend(Plot):
408
441
  x, y, param, colormap, s.get_label(self._use_latex),
409
442
  s.rendering_kw, s.is_point)
410
443
  self._fig.add_glyph(ds, line)
411
- if self.legend:
444
+ if s.colorbar:
412
445
  self._handles[i] = cb
413
446
  self._fig.add_layout(cb, "right")
414
447
  else:
@@ -422,10 +455,12 @@ class BokehBackend(Plot):
422
455
  "ys": y if not s.is_polar else y * np.sin(x)
423
456
  }
424
457
 
425
- color = next(self._cl) if s.line_color is None else s.line_color
426
- lkw = dict(line_width=2,
427
- legend_label=s.get_label(self._use_latex),
428
- color=color)
458
+ if s.get_label(False) != "__k__":
459
+ color = next(self._cl) if s.line_color is None else s.line_color
460
+ else:
461
+ color = "#000000"
462
+ lkw = dict(line_width=2, color=color,
463
+ legend_label=s.get_label(self._use_latex))
429
464
  if not s.is_point:
430
465
  kw = merge({}, lkw, s.rendering_kw)
431
466
  self._fig.line("xs", "ys", source=source, **kw)
@@ -461,13 +496,14 @@ class BokehBackend(Plot):
461
496
  **kw
462
497
  )
463
498
 
464
- colormapper = self.bokeh.models.LinearColorMapper(
465
- palette=cm, low=minz, high=maxz)
466
- cbkw = dict(width=8, title=s.get_label(self._use_latex))
467
- colorbar = self.bokeh.models.ColorBar(
468
- color_mapper=colormapper, **cbkw)
469
- self._fig.add_layout(colorbar, "right")
470
- self._handles[i] = colorbar
499
+ if s.colorbar:
500
+ colormapper = self.bokeh.models.LinearColorMapper(
501
+ palette=cm, low=minz, high=maxz)
502
+ cbkw = dict(width=8, title=s.get_label(self._use_latex))
503
+ colorbar = self.bokeh.models.ColorBar(
504
+ color_mapper=colormapper, **cbkw)
505
+ self._fig.add_layout(colorbar, "right")
506
+ self._handles[i] = colorbar
471
507
 
472
508
  elif s.is_2Dvector:
473
509
  if s.is_streamlines:
@@ -509,7 +545,7 @@ class BokehBackend(Plot):
509
545
  glyph = self.bokeh.models.Segment(
510
546
  x0="x0", y0="y0", x1="x1", y1="y1", **kw)
511
547
  self._fig.add_glyph(source, glyph)
512
- if isinstance(line_color, dict):
548
+ if isinstance(line_color, dict) and s.colorbar:
513
549
  colorbar = self.bokeh.models.ColorBar(
514
550
  color_mapper=color_mapper, width=8, title=s.get_label(self._use_latex))
515
551
  self._fig.add_layout(colorbar, "right")
@@ -519,6 +555,10 @@ class BokehBackend(Plot):
519
555
  x, y, mag, angle, img, colors = s.get_data()
520
556
  img = self._get_img(img)
521
557
 
558
+ self._fig.x_range.flipped = s.at_infinity
559
+ if s.at_infinity:
560
+ mag, angle, img = [np.flip(np.flip(t, axis=0),
561
+ axis=1) for t in [mag, angle, img]]
522
562
  source = self.bokeh.models.ColumnDataSource(
523
563
  {
524
564
  "image": [img],
@@ -535,7 +575,7 @@ class BokehBackend(Plot):
535
575
  dh=y.max() - y.min(),
536
576
  )
537
577
 
538
- if colors is not None:
578
+ if (colors is not None) and s.colorbar:
539
579
  # chroma/phase-colorbar
540
580
  cm1 = self.bokeh.models.LinearColorMapper(
541
581
  palette=[tuple(c) for c in colors],
@@ -544,7 +584,7 @@ class BokehBackend(Plot):
544
584
  labels = ["-π", "-π / 2", "0", "π / 2", "π"]
545
585
  colorbar1 = self.bokeh.models.ColorBar(
546
586
  color_mapper=cm1,
547
- title="Argument",
587
+ title="Argument" if s.get_label(False) == str(s.expr) else s.get_label(self._use_latex),
548
588
  ticker=self.bokeh.models.tickers.FixedTicker(ticks=ticks),
549
589
  major_label_overrides={k: v for k, v in zip(ticks, labels)})
550
590
  self._fig.add_layout(colorbar1, "right")
@@ -578,10 +618,21 @@ class BokehBackend(Plot):
578
618
  )
579
619
 
580
620
  if len(self._fig.legend) > 0:
581
- self._fig.legend.visible = self.legend
582
- # interactive legend
583
- self._fig.legend.click_policy = "hide"
584
- self._fig.add_layout(self._fig.legend[0], "right")
621
+ # hide default legend
622
+ self._fig.legend.visible = False
623
+ # add a new legend only showing the appropriate items
624
+ legend_items = []
625
+ for s, r in zip(self.series, self._fig.renderers):
626
+ if (s.show_in_legend and (s.is_2Dline or s.is_geometry) and
627
+ (not s.use_cm)):
628
+ legend_items.append(
629
+ self.bokeh.models.LegendItem(
630
+ label=s.get_label(self._use_latex), renderers=[r]))
631
+ if self.legend and (len(legend_items) > 0):
632
+ legend = self.bokeh.models.Legend(items=legend_items)
633
+ # interactive legend
634
+ legend.click_policy = "hide"
635
+ self._fig.add_layout(legend, "right")
585
636
 
586
637
  def _get_img(self, img):
587
638
  np = import_module('numpy')
@@ -675,13 +726,14 @@ class BokehBackend(Plot):
675
726
  x, y, z = s.get_data()
676
727
  minx, miny, minz = x.min(), y.min(), z.min()
677
728
  maxx, maxy, maxz = x.max(), y.max(), z.max()
678
- cb = self._handles[i]
679
729
  rend[i].data_source.data.update({"image": [z]})
680
730
  rend[i].glyph.x = minx
681
731
  rend[i].glyph.y = miny
682
732
  rend[i].glyph.dw = abs(maxx - minx)
683
733
  rend[i].glyph.dh = abs(maxy - miny)
684
- cb.color_mapper.update(low=minz, high=maxz)
734
+ if s.colorbar:
735
+ cb = self._handles[i]
736
+ cb.color_mapper.update(low=minz, high=maxz)
685
737
 
686
738
  elif s.is_2Dvector:
687
739
  x, y, u, v = s.get_data()
@@ -723,9 +775,10 @@ class BokehBackend(Plot):
723
775
  },
724
776
  )
725
777
  rend[i].glyph.line_color = line_color
726
- cb = self._handles[i]
727
- cb.color_mapper.update(
728
- low=min(color_val), high=max(color_val))
778
+ if s.colorbar:
779
+ cb = self._handles[i]
780
+ cb.color_mapper.update(
781
+ low=min(color_val), high=max(color_val))
729
782
 
730
783
  elif s.is_complex and s.is_domain_coloring and not s.is_3Dsurface:
731
784
  x, y, mag, angle, img, _ = s.get_data()
@@ -38,9 +38,10 @@ class K3DBackend(Plot):
38
38
  - ``scale``: a float number acting as a scale multiplier.
39
39
  - ``pivot``: indicates the part of the arrow that is anchored to the
40
40
  X, Y, Z grid. It can be ``"tail", "mid", "middle", "tip"``.
41
- - ``color``: set a solid color by specifying an integer color. If this
42
- key is not provided, a default color or colormap is used, depenging
43
- on the value of ``use_cm``.
41
+ - ``color``: set a solid color by specifying an integer color, or
42
+ a colormap by specifying one of k3d's colormaps.
43
+ If this key is not provided, a default color or colormap is used,
44
+ depending on the value of ``use_cm``.
44
45
 
45
46
  Set ``use_cm=False`` to switch to a default solid color.
46
47
 
@@ -297,13 +298,13 @@ class K3DBackend(Plot):
297
298
  indices = Triangulation(x, y).triangles.astype(np.uint32)
298
299
  attribute = s.eval_color_func(vertices[:, 0], vertices[:, 1], vertices[:, 2])
299
300
 
300
- # self._high_aspect_ratio(x, y, z)
301
301
  a = dict(
302
302
  name=s.get_label(self._use_latex, "%s") if self._show_label else None,
303
303
  side="double",
304
304
  flat_shading=False,
305
305
  wireframe=False,
306
306
  color=self._convert_to_int(next(self._cl)) if s.surface_color is None else s.surface_color,
307
+ colorLegend=self.legend or s.use_cm,
307
308
  )
308
309
  if s.use_cm:
309
310
  a["color_map"] = next(self._cm)
@@ -344,8 +345,8 @@ class K3DBackend(Plot):
344
345
 
345
346
  stream_kw = s.rendering_kw.copy()
346
347
  skw = dict(width=0.1, shader="mesh")
347
- if s.use_cm and ("color" not in stream_kw.keys()):
348
- skw["color_map"] = next(self._cm)
348
+ if s.use_cm:
349
+ skw["color_map"] = stream_kw.get("color", next(self._cm))
349
350
  skw["color_range"] = [float(np.nanmin(color_val)), float(np.nanmax(color_val))]
350
351
  skw["attribute"] = color_val
351
352
  else:
@@ -363,8 +364,8 @@ class K3DBackend(Plot):
363
364
  qkw = dict(scale=1)
364
365
  qkw = merge(qkw, s.rendering_kw)
365
366
  quiver_kw = s.rendering_kw
366
- if s.use_cm and ("color" not in quiver_kw.keys()):
367
- colormap = next(self._cm)
367
+ if s.use_cm:
368
+ colormap = quiver_kw.get("color", next(self._cm))
368
369
  # store useful info for interactive vector plots
369
370
  self._handles[ii] = [qkw, colormap]
370
371
  else:
@@ -413,18 +414,22 @@ class K3DBackend(Plot):
413
414
  flat_shading=False,
414
415
  wireframe=False,
415
416
  color=self._convert_to_int(next(self._cl)),
416
- color_range=[-np.pi, np.pi],
417
+ colorLegend=self.legend or s.use_cm,
417
418
  )
418
419
  if s.use_cm:
419
420
  colors = colors.reshape((-1, 3))
420
421
  a["colors"] = [self._rgb_to_int(c) for c in colors]
421
422
 
422
- r = []
423
- loc = np.linspace(0, 1, colorscale.shape[0])
424
- colorscale = colorscale / 255
425
- for l, c in zip(loc, colorscale):
426
- r.append(l)
427
- r += list(c)
423
+ if colorscale is None:
424
+ # grayscale colormap
425
+ r = [0, 0, 0, 0, 1, 1, 1, 1]
426
+ else:
427
+ r = []
428
+ loc = np.linspace(0, 1, colorscale.shape[0])
429
+ colorscale = colorscale / 255
430
+ for l, c in zip(loc, colorscale):
431
+ r.append(l)
432
+ r += list(c)
428
433
 
429
434
  a["color_map"] = r
430
435
  a["color_range"] = [-np.pi, np.pi]