lavavu 1.9.6__cp313-cp313-macosx_11_0_arm64.whl → 1.9.7__cp313-cp313-macosx_11_0_arm64.whl

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.
Binary file
lavavu/html/control.js CHANGED
@@ -87,7 +87,7 @@ function WindowInteractor(id, uid, port) {
87
87
 
88
88
  //Several possible modes to try
89
89
  //Modern JupyterHub lab URL
90
- var regex = /\/lab\//;
90
+ var regex = /\/lab(\/|\?|$)/; //Match "/lab" at end of url or "/lab/" or "/lab?" anywhere
91
91
  var parsed = regex.exec(loc.href);
92
92
  if (parsed && parsed.length > 0) {
93
93
  connect(loc.href.substring(0,parsed.index) + "/proxy/" + port);
lavavu/html/webview.html CHANGED
@@ -27,7 +27,7 @@
27
27
 
28
28
  <input id="fileinput" type="file" style="visibility:hidden" onchange="useFileInput(this)" />
29
29
 
30
- <script async src="https://cdn.jsdelivr.net/gh/lavavu/lavavu.github.io@1.9.6/LavaVu-amalgamated.min.js"></script>
30
+ <script async src="https://cdn.jsdelivr.net/gh/lavavu/lavavu.github.io@1.9.7/LavaVu-amalgamated.min.js"></script>
31
31
  <!--script src="dat.gui.min.js"></script>
32
32
  <script src="OK-min.js"></script>
33
33
 
lavavu/lavavu.py CHANGED
@@ -23,7 +23,7 @@ __all__ = ['Viewer', 'Object', 'Properties', 'ColourMap', 'DrawData', 'Figure',
23
23
  import os
24
24
  #must be an object or won't be referenced from __init__.py import
25
25
  #(enures values are passed on when set externally)
26
- settings = {"default_args" : [], "echo_fails" : False, "quality_override" : None}
26
+ settings = {"default_args" : [], "echo_fails" : False, "quality_override" : None, "test_mode" : False}
27
27
  #Default arguments for viewer creation
28
28
  _val = os.environ.get('LV_ARGS')
29
29
  if _val:
@@ -36,6 +36,10 @@ if _val:
36
36
  _val = os.environ.get('LV_QUALITY')
37
37
  if _val:
38
38
  settings["quality_override"] = int(_val)
39
+ #Test mode - changes some behaviour to support automated testing
40
+ _val = os.environ.get('LV_TEST')
41
+ if _val:
42
+ settings["test_mode"] = bool(_val)
39
43
 
40
44
  import json
41
45
  import math
@@ -54,6 +58,7 @@ import asyncio
54
58
  import quaternion as quat
55
59
  import platform
56
60
  import matplotlib
61
+ from pathlib import Path
57
62
 
58
63
  if sys.version_info[0] < 3:
59
64
  print("Python 3 required. LavaVu no longer supports Python 2.7.")
@@ -3562,7 +3567,6 @@ class Viewer(dict):
3562
3567
  ll = len(self.objects.list) #Save list length before load
3563
3568
  if not self.app.loadFile(filename):
3564
3569
  #Support trimesh formats
3565
- from pathlib import Path
3566
3570
  path = Path(filename)
3567
3571
  ext = path.suffix.lower()[1:]
3568
3572
  import convert
@@ -3876,6 +3880,9 @@ class Viewer(dict):
3876
3880
  """
3877
3881
  Render a new frame, explicit display update
3878
3882
  """
3883
+ if settings["test_mode"] and self.recording and self.recording.framecount != 0:
3884
+ #Skip rendering all except first and last frames when testing
3885
+ return
3879
3886
  self.app.render()
3880
3887
  #Video recording?
3881
3888
  if self.recording:
@@ -4305,7 +4312,7 @@ class Viewer(dict):
4305
4312
  #This is thread safe as doesn't load texture
4306
4313
  return self.app.imageFromFile(filename)
4307
4314
 
4308
- def testimages(self, imagelist=None, tolerance=TOL_DEFAULT, expectedPath='expected/', outputPath='./', clear=True):
4315
+ def testimages(self, imagelist=None, tolerance=TOL_DEFAULT, expectedPath='expected/', outputPath='./', png=True, jpg=False, clear=True):
4309
4316
  """
4310
4317
  Compare a list of images to expected images for testing
4311
4318
 
@@ -4320,6 +4327,10 @@ class Viewer(dict):
4320
4327
  Where to find the expected result images (should have the same filenames as output images)
4321
4328
  outputPath : str
4322
4329
  Where to find the output images
4330
+ png : boolean
4331
+ Check png image outputs, defaults to True
4332
+ jpng : boolean
4333
+ Check jpg image outputs, defaults to False
4323
4334
  clear : boolean
4324
4335
  If the test passes the output images will be deleted, set to False to disable deletion
4325
4336
  """
@@ -4333,14 +4344,17 @@ class Viewer(dict):
4333
4344
  #No expected images yet, just get images in cwd
4334
4345
  #will be copied in to expected in testimage()
4335
4346
  pass
4336
- imagelist = glob.glob("*.png")
4337
- imagelist += glob.glob("*.jpg")
4347
+ imagelist = []
4348
+ if png:
4349
+ imagelist += glob.glob("*.png")
4350
+ if jpg:
4351
+ imagelist += glob.glob("*.jpg")
4338
4352
  imagelist.sort(key=os.path.getmtime)
4339
4353
  os.chdir(cwd)
4340
4354
 
4341
4355
  for f in sorted(imagelist):
4342
- outfile = outputPath+f
4343
- expfile = expectedPath+f
4356
+ outfile = os.path.join(outputPath, f)
4357
+ expfile = os.path.join(expectedPath, f)
4344
4358
  results.append(self.testimage(expfile, outfile, tolerance, clear))
4345
4359
 
4346
4360
  #Combined result
@@ -5504,9 +5518,6 @@ class Video(object):
5504
5518
  **kwargs :
5505
5519
  Any additional keyword args will also be passed as options to the encoder
5506
5520
  """
5507
- if av is None:
5508
- raise(ImportError("Video output not supported without pyAV - pip install av"))
5509
- return
5510
5521
  self.resolution = list(resolution)
5511
5522
  if self.resolution[0] == 0 or self.resolution[1] == 0:
5512
5523
  self.resolution = (viewer.app.viewer.width, viewer.app.viewer.height)
@@ -5515,7 +5526,20 @@ class Video(object):
5515
5526
  self.framerate = framerate
5516
5527
  self.quality = quality
5517
5528
  self.viewer = viewer
5518
- self.filename = filename
5529
+ self.filename = Path(filename)
5530
+ if settings["test_mode"]:
5531
+ #Force png output when testing
5532
+ encoder = 'png'
5533
+ if av is None or encoder == 'png' or encoder == 'jpg':
5534
+ if av is None:
5535
+ print("Video output not supported without pyAV - pip install av, writing image frames instead")
5536
+ self.encoder = 'png' if encoder == 'png' else 'jpg'
5537
+ p = self.filename
5538
+ self.basename = p.stem
5539
+ self.filename = p.parent / p.stem
5540
+ self.framecount = 0
5541
+ return
5542
+
5519
5543
  self.player = player
5520
5544
  if self.player is None:
5521
5545
  #Default player is half output resolution, unless < 900 then full
@@ -5547,6 +5571,12 @@ class Video(object):
5547
5571
  #Compression level, lower = high quality
5548
5572
  #See also: https://github.com/PyAV-Org/PyAV/blob/main/tests/test_encode.py
5549
5573
  options = {}
5574
+ if self.encoder == 'jpg' or self.encoder == 'png':
5575
+ if not settings["test_mode"]:
5576
+ self.filename.mkdir(exist_ok=True)
5577
+ self.viewer.recording = self
5578
+ return
5579
+
5550
5580
  if self.encoder == 'h264' or self.encoder == 'libx265':
5551
5581
  #Only have default options for h264/265 for now
5552
5582
  if self.quality == 1:
@@ -5576,7 +5606,7 @@ class Video(object):
5576
5606
  options.update(self.options)
5577
5607
 
5578
5608
  #print(options)
5579
- self.container = av.open(self.filename, mode="w")
5609
+ self.container = av.open(str(self.filename), mode="w")
5580
5610
  self.stream = self.container.add_stream(self.encoder, rate=self.framerate, options=options)
5581
5611
  self.stream.width = self.resolution[0]
5582
5612
  self.stream.height = self.resolution[1]
@@ -5602,10 +5632,19 @@ class Video(object):
5602
5632
  Write a frame, called when viewer.render() is called
5603
5633
  while a recording is in progress
5604
5634
  """
5605
- img = self.viewer.rawimage(resolution=self.resolution, channels=3)
5606
- frame = av.VideoFrame.from_ndarray(img.data, format="rgb24")
5607
- for packet in self.stream.encode(frame):
5608
- self.container.mux(packet)
5635
+ if self.encoder == 'jpg' or self.encoder == 'png':
5636
+ if settings["test_mode"]:
5637
+ #Don't output in subdir
5638
+ fn = f"{self.framecount:06}_{self.basename}.{self.encoder}"
5639
+ else:
5640
+ fn = self.filename / f"{self.framecount:06}_{self.basename}.{self.encoder}"
5641
+ self.framecount += 1
5642
+ self.viewer.image(str(fn), resolution=self.resolution)
5643
+ else:
5644
+ img = self.viewer.rawimage(resolution=self.resolution, channels=3)
5645
+ frame = av.VideoFrame.from_ndarray(img.data, format="rgb24")
5646
+ for packet in self.stream.encode(frame):
5647
+ self.container.mux(packet)
5609
5648
 
5610
5649
  def pause(self):
5611
5650
  """
@@ -5621,6 +5660,15 @@ class Video(object):
5621
5660
  Stop recording, final frames will be written and file closed, ready to play.
5622
5661
  No further frames will be added to the video
5623
5662
  """
5663
+ if self.encoder == 'jpg' or self.encoder == 'png':
5664
+ self.viewer.recording = None
5665
+ if settings["test_mode"]:
5666
+ #Render the last frame for tests
5667
+ self.viewer.app.render()
5668
+ fn = f"{self.framecount:06}_{self.basename}.{self.encoder}"
5669
+ self.viewer.image(str(fn), resolution=self.resolution)
5670
+ self.framecount = 0
5671
+ return
5624
5672
  # Flush stream
5625
5673
  for packet in self.stream.encode():
5626
5674
  self.container.mux(packet)
@@ -5648,7 +5696,14 @@ class Video(object):
5648
5696
  if image.size == self.resolution[0] * self.resolution[1] * 4:
5649
5697
  image = image.reshape(self.resolution[0], self.resolution[1], 4)
5650
5698
  image = image[::,::,:3] #Remove alpha channel
5651
- #self.encoder.copyframe(image.ravel())
5699
+
5700
+ if self.encoder == 'jpg' or self.encoder == 'png':
5701
+ from PIL import Image as PILImage
5702
+ img = PILImage.fromarray(image)
5703
+ fn = self.filename / f"{self.framecount:06}_{self.basename}.{self.encoder}"
5704
+ self.framecount += 1
5705
+ img.save(fn)
5706
+ return
5652
5707
 
5653
5708
  frame = av.VideoFrame.from_ndarray(image, format="rgb24")
5654
5709
  for packet in self.stream.encode(frame):
@@ -5658,7 +5713,11 @@ class Video(object):
5658
5713
  """
5659
5714
  Show the video in an inline player if in an interactive notebook
5660
5715
  """
5661
- player(self.filename, **self.player)
5716
+ if self.encoder == 'jpg' or self.encoder == 'png':
5717
+ from IPython.display import display,HTML
5718
+ display(HTML('<p>Video written to images, no player available</p>'))
5719
+ else:
5720
+ player(self.filename, **self.player)
5662
5721
 
5663
5722
  def __enter__(self):
5664
5723
  self.start()
@@ -5671,6 +5730,8 @@ class Video(object):
5671
5730
  self.play()
5672
5731
  else:
5673
5732
  print('Recording failed: ', exc_value)
5733
+ import traceback
5734
+ print(traceback.format_exc())
5674
5735
  return True
5675
5736
 
5676
5737
  #Wrapper class for raw image data
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lavavu
3
- Version: 1.9.6
3
+ Version: 1.9.7
4
4
  Summary: Python interface to LavaVu OpenGL 3D scientific visualisation utilities
5
5
  Author-email: Owen Kaluza <owen@kaluza.id.au>
6
6
  License: ### Licensing
@@ -224,7 +224,7 @@ Dynamic: license-file
224
224
  [![Build Status](https://github.com/lavavu/LavaVu/workflows/Test/badge.svg)](https://github.com/lavavu/LavaVu/actions?query=workflow:Test)
225
225
  [![Deploy Status](https://github.com/lavavu/LavaVu/workflows/Deploy/badge.svg?branch=1.7.3)](https://github.com/lavavu/LavaVu/actions?query=workflow:Deploy)
226
226
  [![DOI](https://zenodo.org/badge/45163055.svg)](https://zenodo.org/badge/latestdoi/45163055)
227
- [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/lavavu/LavaVu/1.9.6)
227
+ [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/lavavu/LavaVu/1.9.7)
228
228
 
229
229
  A scientific visualisation tool with a python interface for fast and flexible visual analysis.
230
230
 
@@ -1,4 +1,4 @@
1
- lavavu/lavavu.py,sha256=I64ioPwTN1eyZcZEaF9RfdxncfLuihl-7VqqqJDFLCw,218528
1
+ lavavu/lavavu.py,sha256=v7tXwp6gQzu1F05hHyALng8FXznv4rVwdCJ3sO65O8o,221223
2
2
  lavavu/vutils.py,sha256=6Vm_xl1bp9mWlfk7jgLDwbRw-tdE_oxin77YkLel3_4,5437
3
3
  lavavu/dict.json,sha256=lsZEHc7Bb6_lt7tkSBQMgkq7AEn_2hnhWzzdokmvIY8,52729
4
4
  lavavu/server.py,sha256=L-_yPCbNfwYxJCPjDQtr_lxPnDp4oMNVFyxXhBERYrQ,12468
@@ -9,12 +9,12 @@ lavavu/convert.py,sha256=tbYRjLE2l1hI4d6tsW41Lia1JXmrWSc0-JAYCiMrjys,35516
9
9
  lavavu/control.py,sha256=s32rtLPXXYtxpeXd6-iHdupmaMTJ3KhK6Vq-CLjf9OQ,66755
10
10
  lavavu/__init__.py,sha256=JroZQiUbuVN7ifixk2zNDGlyLGaM8bqfRbw4D_F9qIQ,191
11
11
  lavavu/amalgamate.py,sha256=Xloq1IZ4VUvYiROzQtwKcQIWC65c7EZrdiGVhZdolL8,586
12
- lavavu/_LavaVuPython.cpython-313-darwin.so,sha256=lI093WT-d3OL1N2RhS-HH50DJYjTHRJwjdXYiLpkeNI,3927376
12
+ lavavu/_LavaVuPython.cpython-313-darwin.so,sha256=7BX8bLplJs0YG-UIabUasfipkxPCMXkE7N9w9K_csxY,3927376
13
13
  lavavu/aserver.py,sha256=SfFvLeDTcx1XtS8fY_HIrDmh3q9HicCBRSAriY5yyOE,12003
14
14
  lavavu/font.bin,sha256=fvi5zkvmq6gh9v3jXedBVuxNJWKmHtbjECzv6eT9wb4,225360
15
15
  lavavu/__main__.py,sha256=EbDetijCjyoiNxmExqnDGoRVs996tSVave5DML9zuMY,235
16
16
  lavavu/html/control.css,sha256=PVLwmle00ciEckUV5ZIRmI3Whxhl7-mlVexnyyxoU70,3259
17
- lavavu/html/control.js,sha256=oV24eJZ0vfuCxF3fO60eeJSkNFJ9hUkSCThHGJS1Wvc,11652
17
+ lavavu/html/control.js,sha256=dBjFHgDal3aixVWoQuMOt_ZyhiGSAcEUFJJx9I_ndOQ,11719
18
18
  lavavu/html/gui.css,sha256=PRDLsYwM6cgLC9zZsEAG0dnnSd-HYH6oSEfsdEBkuxk,582
19
19
  lavavu/html/favicon.ico,sha256=OrIWwvxOSnOCuynrGRUyEIVQng0ZwA9Rrz89S9eiog0,1150
20
20
  lavavu/html/LavaVu-amalgamated.css,sha256=iE2xrxFcwmY0AcASrXxNa_RpvFEbS_YO4H5OILbPteE,8640
@@ -27,7 +27,7 @@ lavavu/html/dat.gui.min.js,sha256=S4_QjoXe4IOpU0f0Sj5jEQLTWPoX9uRl1ohB91jyhuw,56
27
27
  lavavu/html/OK-min.js,sha256=-4Gc1-dWfxP_w6r9ZOHa8u-X2BlGUoSQbX68lwCxQ3E,39115
28
28
  lavavu/html/emscripten.css,sha256=wkaIJhXaxuMchinQX9Z8c12cJomyvFQMeIZ62WGQEPQ,1813
29
29
  lavavu/html/drawbox.js,sha256=SJxFSmWd7QVFI5__66hFkKzLKeqg1JPcx-gJuqdMkXw,34590
30
- lavavu/html/webview.html,sha256=8eilGjX8y_I5OjCvTm-ZAQDNOSCaT1yvogKFqK4lCS0,1521
30
+ lavavu/html/webview.html,sha256=Tjv9TWx1k6ovHY8xxaG_NGwHwuiDC0Hz5Npm39afHAU,1521
31
31
  lavavu/html/emscripten-template.js,sha256=h63mzl3Lv7aQT1wMOiOucPOvHTJjpKkzsL-SFVYaZlA,6135
32
32
  lavavu/html/draw.js,sha256=57LlHlYRh0IvWVwzGDnF6PaCxYLzokpokLNCuZlG1ds,84108
33
33
  lavavu/html/dat-gui-light-theme.css,sha256=uPhvJs-1IAsdxudItyOw8lZy8Hrih0zmFM1u-xRwZ-M,1142
@@ -47,9 +47,9 @@ lavavu/shaders/fontShader.vert,sha256=yCBmRugaPUeUQUdIh62-AK_5KELiJqVS2M82iyIqPw
47
47
  lavavu/shaders/pointShader.frag,sha256=3zREBdsimlL9fAXBPjhzomGaFUWmlG_QYkhwMTVURHQ,3291
48
48
  lavavu/shaders/volumeShader.vert,sha256=uGdQjGqi7V5kE6V7nxymfugtU4cbf6u570xBy13RgmY,78
49
49
  lavavu/shaders/default.frag,sha256=5XLYVfLwzN0sFT3aMYGmxbyquA_cmndp55YCOuy1t4E,180
50
- lavavu-1.9.6.dist-info/RECORD,,
51
- lavavu-1.9.6.dist-info/WHEEL,sha256=Cxq5pla4scSj9raD9htoFbIhfTk0lSQlQLVCyAjgIi4,136
52
- lavavu-1.9.6.dist-info/entry_points.txt,sha256=LC2qXR6EMe45Cb7zGAF99R9HFrAECP6Qkp_YuG6HZB0,44
53
- lavavu-1.9.6.dist-info/top_level.txt,sha256=JptS0k1nlBumjLs_0hITr3_XUJhxqvKBXD2jGho3E3A,7
54
- lavavu-1.9.6.dist-info/METADATA,sha256=EHgjIlNax60denK4kKXeAJziT1zFhX8e-9OqQUVd9WE,17877
55
- lavavu-1.9.6.dist-info/licenses/LICENSE.md,sha256=EhfNgC6BYh5gDEaq4tcrN3S0wbO4CtJO46botJnCF8c,8603
50
+ lavavu-1.9.7.dist-info/RECORD,,
51
+ lavavu-1.9.7.dist-info/WHEEL,sha256=89IgJaLF6X8hMUjC4DKLcrcADd48Z33aA8odPAkCuhg,136
52
+ lavavu-1.9.7.dist-info/entry_points.txt,sha256=LC2qXR6EMe45Cb7zGAF99R9HFrAECP6Qkp_YuG6HZB0,44
53
+ lavavu-1.9.7.dist-info/top_level.txt,sha256=JptS0k1nlBumjLs_0hITr3_XUJhxqvKBXD2jGho3E3A,7
54
+ lavavu-1.9.7.dist-info/METADATA,sha256=pDV89WKg6njzJArxsKbduk1rcj2NHSb75oV1lUtNx30,17877
55
+ lavavu-1.9.7.dist-info/licenses/LICENSE.md,sha256=EhfNgC6BYh5gDEaq4tcrN3S0wbO4CtJO46botJnCF8c,8603
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (78.1.0)
2
+ Generator: setuptools (80.4.0)
3
3
  Root-Is-Purelib: false
4
4
  Tag: cp313-cp313-macosx_11_0_arm64
5
5
  Generator: delocate 0.13.0