lavavu 1.9.0__cp311-cp311-macosx_11_0_arm64.whl → 1.9.6__cp311-cp311-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.
- lavavu/_LavaVuPython.cpython-311-darwin.so +0 -0
- lavavu/control.py +18 -5
- lavavu/html/menu.js +9 -4
- lavavu/html/webview.html +1 -1
- lavavu/lavavu.py +111 -86
- lavavu/tracers.py +180 -110
- {lavavu-1.9.0.dist-info → lavavu-1.9.6.dist-info}/METADATA +20 -16
- {lavavu-1.9.0.dist-info → lavavu-1.9.6.dist-info}/RECORD +12 -12
- {lavavu-1.9.0.dist-info → lavavu-1.9.6.dist-info}/WHEEL +2 -1
- {lavavu-1.9.0.dist-info → lavavu-1.9.6.dist-info}/entry_points.txt +0 -0
- {lavavu-1.9.0.dist-info → lavavu-1.9.6.dist-info/licenses}/LICENSE.md +0 -0
- {lavavu-1.9.0.dist-info → lavavu-1.9.6.dist-info}/top_level.txt +0 -0
Binary file
|
lavavu/control.py
CHANGED
@@ -1689,13 +1689,26 @@ class _ControlFactory(object):
|
|
1689
1689
|
"""
|
1690
1690
|
if not is_notebook():
|
1691
1691
|
return
|
1692
|
-
|
1692
|
+
from IPython.display import display,HTML,Javascript
|
1693
|
+
display(Javascript(self.redisplay_call()))
|
1694
|
+
|
1695
|
+
def redisplay_call(self):
|
1696
|
+
"""Update the active viewer image if any
|
1697
|
+
Applies changes made in python to the viewer and forces a redisplay
|
1698
|
+
"""
|
1699
|
+
#Find matching viewer id, redisplay first match
|
1700
|
+
ids = self.active_viewers()
|
1701
|
+
return ';'.join('_wi["{0}"].redisplay()'.format(i) for i in ids)
|
1702
|
+
|
1703
|
+
def active_viewers(self):
|
1704
|
+
"""Return matching active viewer IDs
|
1705
|
+
"""
|
1706
|
+
#Find matching viewer ids, all that match
|
1707
|
+
ids = []
|
1693
1708
|
for idx,obj in enumerate(windows):
|
1694
1709
|
if obj == self._target():
|
1695
|
-
|
1696
|
-
|
1697
|
-
#display(Javascript('_wi["{0}"].redisplay();'.format(viewerid)))
|
1698
|
-
display(HTML('<script>_wi["{0}"].redisplay();</script>'.format(viewerid)))
|
1710
|
+
ids.append(winids[idx])
|
1711
|
+
return ids
|
1699
1712
|
|
1700
1713
|
def update(self):
|
1701
1714
|
"""Update the control values from current viewer data
|
lavavu/html/menu.js
CHANGED
@@ -123,7 +123,12 @@ function menu_addctrls(menu, obj, viewer, onchange) {
|
|
123
123
|
//Check if it has been set on the target object
|
124
124
|
if (prop in obj) {
|
125
125
|
//console.log(prop + " ==> " + JSON.stringify(viewer.dict[prop]));
|
126
|
-
|
126
|
+
try {
|
127
|
+
//Catch errors and continue gracefully
|
128
|
+
menu_addctrl(menu, obj, viewer, prop, onchange);
|
129
|
+
} catch(e) {
|
130
|
+
console.log("Error adding control to menu: " + e);
|
131
|
+
}
|
127
132
|
|
128
133
|
} else {
|
129
134
|
//Save list of properties without controls
|
@@ -159,9 +164,9 @@ function menu_addctrls(menu, obj, viewer, onchange) {
|
|
159
164
|
|
160
165
|
function menu_addcmaps(menu, obj, viewer, onchange) {
|
161
166
|
//Colourmap editing menu
|
162
|
-
if (viewer.cgui.prmenu) viewer.cgui.
|
163
|
-
if (viewer.cgui.cmenu) viewer.cgui.
|
164
|
-
if (viewer.cgui.pomenu) viewer.cgui.
|
167
|
+
if (viewer.cgui.prmenu) viewer.cgui.remove(viewer.cgui.prmenu);
|
168
|
+
if (viewer.cgui.cmenu) viewer.cgui.remove(viewer.cgui.cmenu);
|
169
|
+
if (viewer.cgui.pomenu) viewer.cgui.remove(viewer.cgui.pomenu);
|
165
170
|
viewer.cgui.prmenu = viewer.cgui.addFolder("Properties");
|
166
171
|
viewer.cgui.cmenu = viewer.cgui.addFolder("Colours");
|
167
172
|
viewer.cgui.pomenu = viewer.cgui.addFolder("Positions");
|
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.
|
30
|
+
<script async src="https://cdn.jsdelivr.net/gh/lavavu/lavavu.github.io@1.9.6/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
@@ -53,6 +53,7 @@ import weakref
|
|
53
53
|
import asyncio
|
54
54
|
import quaternion as quat
|
55
55
|
import platform
|
56
|
+
import matplotlib
|
56
57
|
|
57
58
|
if sys.version_info[0] < 3:
|
58
59
|
print("Python 3 required. LavaVu no longer supports Python 2.7.")
|
@@ -610,12 +611,12 @@ class Object(dict):
|
|
610
611
|
return key in self.dict
|
611
612
|
|
612
613
|
def __repr__(self):
|
613
|
-
return
|
614
|
+
return self.__str__()
|
614
615
|
|
615
616
|
def __str__(self):
|
616
617
|
#Default string representation
|
617
618
|
self.parent._get() #Ensure in sync
|
618
|
-
return '{\n' + str('\n'.join([' %s=%s' % (k,json.dumps(v)) for k,v in self.dict.items()])) + '\n}
|
619
|
+
return '{\n' + str('\n'.join([' %s=%s' % (k,json.dumps(v)) for k,v in self.dict.items()])) + '\n}'
|
619
620
|
|
620
621
|
#Interface for setting filters
|
621
622
|
def include(self, *args, **kwargs):
|
@@ -1144,7 +1145,12 @@ class Object(dict):
|
|
1144
1145
|
#Re-arrange to array of [r,g,b,a] values
|
1145
1146
|
data = numpy.dstack((data[0],data[1],data[2]))
|
1146
1147
|
|
1147
|
-
|
1148
|
+
#Use the shape as dims for texture image data
|
1149
|
+
if len(data.shape) > 1:
|
1150
|
+
width, height = data.shape[1], data.shape[0]
|
1151
|
+
depth = 4 #4 channel RGBA
|
1152
|
+
|
1153
|
+
self._loadScalar(data, LavaVuPython.lucRGBAData, width, height, depth)
|
1148
1154
|
|
1149
1155
|
|
1150
1156
|
def luminance(self, data):
|
@@ -1166,7 +1172,7 @@ class Object(dict):
|
|
1166
1172
|
|
1167
1173
|
self._loadScalar(data, LavaVuPython.lucLuminanceData, width, height, depth)
|
1168
1174
|
|
1169
|
-
def texture(self, data=None, flip=
|
1175
|
+
def texture(self, data=None, flip=None, filter=2, bgr=False, label=""):
|
1170
1176
|
"""
|
1171
1177
|
Load or clear texture data for object
|
1172
1178
|
|
@@ -1186,7 +1192,7 @@ class Object(dict):
|
|
1186
1192
|
If not provided, will use the default/primary texture for the object
|
1187
1193
|
flip : boolean
|
1188
1194
|
flip the texture vertically after loading
|
1189
|
-
(default is
|
1195
|
+
(default is to load value from "fliptexture" property)
|
1190
1196
|
filter : int
|
1191
1197
|
type of filtering, 0=None/nearest, 1=linear, 2=mipmap linear
|
1192
1198
|
bgr : boolean
|
@@ -1196,6 +1202,11 @@ class Object(dict):
|
|
1196
1202
|
#Clear texture
|
1197
1203
|
self.parent.app.clearTexture(self.ref)
|
1198
1204
|
return
|
1205
|
+
if flip is None:
|
1206
|
+
if "fliptexture" in self:
|
1207
|
+
flip = self["fliptexture"]
|
1208
|
+
else:
|
1209
|
+
flip = self.parent["fliptexture"]
|
1199
1210
|
if isinstance(data, str):
|
1200
1211
|
self.parent.app.setTexture(self.ref, data, flip, filter, bgr, label)
|
1201
1212
|
return
|
@@ -1266,6 +1277,8 @@ class Object(dict):
|
|
1266
1277
|
self.ref.colourMap = data.ref
|
1267
1278
|
data = None
|
1268
1279
|
else:
|
1280
|
+
if isinstance(data, matplotlib.colors.Colormap):
|
1281
|
+
data = matplotlib_cmap(data)
|
1269
1282
|
if data is None:
|
1270
1283
|
self.parent._get() #Ensure in sync
|
1271
1284
|
cmid = self["colourmap"]
|
@@ -2734,7 +2747,7 @@ class Viewer(dict):
|
|
2734
2747
|
|
2735
2748
|
"""
|
2736
2749
|
|
2737
|
-
def __init__(self, *args, resolution=None, binpath=None, context=
|
2750
|
+
def __init__(self, *args, resolution=None, binpath=None, context=None, port=8080, threads=False, **kwargs):
|
2738
2751
|
"""
|
2739
2752
|
Create and init viewer instance
|
2740
2753
|
|
@@ -2771,7 +2784,9 @@ class Viewer(dict):
|
|
2771
2784
|
self._collections = {}
|
2772
2785
|
self.validate = True #Property validation flag
|
2773
2786
|
self.recording = None
|
2774
|
-
self.context =
|
2787
|
+
self.context = context
|
2788
|
+
if self.context is None:
|
2789
|
+
self.context = os.environ.get('LV_CONTEXT', 'default')
|
2775
2790
|
|
2776
2791
|
#Exit handler to clean up threads
|
2777
2792
|
#(__del__ does not always seem to get called on termination)
|
@@ -3249,10 +3264,12 @@ class Viewer(dict):
|
|
3249
3264
|
self.validate = self.state["properties"]["validate"]
|
3250
3265
|
self._objects._sync()
|
3251
3266
|
|
3252
|
-
def _set(self):
|
3267
|
+
def _set(self, reload=None):
|
3253
3268
|
#Export state to lavavu
|
3254
3269
|
#(include current object list state)
|
3255
3270
|
#self.state["objects"] = [obj.dict for obj in self._objects.list]
|
3271
|
+
if reload is not None:
|
3272
|
+
self.state["reload"] = reload
|
3256
3273
|
self.app.setState(json.dumps(self.state))
|
3257
3274
|
|
3258
3275
|
def commands(self, cmds, queue=False):
|
@@ -3732,7 +3749,7 @@ class Viewer(dict):
|
|
3732
3749
|
else:
|
3733
3750
|
return c.tolist()
|
3734
3751
|
|
3735
|
-
def texture(self, label, data=None, flip=
|
3752
|
+
def texture(self, label, data=None, flip=None, filter=2, bgr=False):
|
3736
3753
|
"""
|
3737
3754
|
Load or clear global/shared texture data
|
3738
3755
|
|
@@ -3751,7 +3768,7 @@ class Viewer(dict):
|
|
3751
3768
|
Pass a string to load a texture from given filename
|
3752
3769
|
flip : boolean
|
3753
3770
|
flip the texture vertically after loading
|
3754
|
-
(default is
|
3771
|
+
(default is to load value from "fliptexture" property)
|
3755
3772
|
filter : int
|
3756
3773
|
type of filtering, 0=None/nearest, 1=linear, 2=mipmap linear
|
3757
3774
|
bgr : boolean
|
@@ -3761,6 +3778,8 @@ class Viewer(dict):
|
|
3761
3778
|
#Clear texture
|
3762
3779
|
self.app.clearTexture(None, label)
|
3763
3780
|
return
|
3781
|
+
if flip is None:
|
3782
|
+
flip = self["fliptexture"]
|
3764
3783
|
if isinstance(data, str):
|
3765
3784
|
self.app.setTexture(None, data, flip, filter, bgr, label)
|
3766
3785
|
return
|
@@ -4168,7 +4187,7 @@ class Viewer(dict):
|
|
4168
4187
|
from IPython.display import display,HTML,Javascript
|
4169
4188
|
display(Javascript(js + code))
|
4170
4189
|
|
4171
|
-
def video(self, filename="", resolution=(0,0), fps=30, quality=
|
4190
|
+
def video(self, filename="", resolution=(0,0), fps=30, quality=2, encoder="h264", embed=False, player=None, options={}, **kwargs):
|
4172
4191
|
"""
|
4173
4192
|
Record and show the generated video inline within an ipython notebook.
|
4174
4193
|
|
@@ -4195,6 +4214,9 @@ class Viewer(dict):
|
|
4195
4214
|
If omitted will use default settings, can fine tune settings in kwargs
|
4196
4215
|
encoder : str
|
4197
4216
|
Name of encoder to use, eg: "h264" (default), "mpeg"
|
4217
|
+
embed : bool
|
4218
|
+
Set to true to embed the video file rather than link to url
|
4219
|
+
Not recommended for large videos, default is False
|
4198
4220
|
player : dict
|
4199
4221
|
Args to pass to the player when the video is finished, eg:
|
4200
4222
|
{"width" : 800, "height", 400, "params": "controls autoplay"}
|
@@ -4209,12 +4231,11 @@ class Viewer(dict):
|
|
4209
4231
|
recorder : Video(object)
|
4210
4232
|
Context manager object that controls the video recording
|
4211
4233
|
"""
|
4212
|
-
return Video(self, filename, resolution, fps, quality, encoder, player, options, **kwargs)
|
4234
|
+
return Video(self, filename, resolution, fps, quality, encoder, embed, player, options, **kwargs)
|
4213
4235
|
|
4214
|
-
def video_steps(self, filename="", start=0, end=0, fps=
|
4236
|
+
def video_steps(self, filename="", start=0, end=0, resolution=(0,0), fps=30, quality=2, encoder="h264", embed=False, player=None, options={}, **kwargs):
|
4237
|
+
my_func.__doc__
|
4215
4238
|
"""
|
4216
|
-
TODO: Fix to use pyAV
|
4217
|
-
|
4218
4239
|
Record a video of the model by looping through all time steps
|
4219
4240
|
|
4220
4241
|
Shows the generated video inline within an ipython notebook.
|
@@ -4226,26 +4247,23 @@ class Viewer(dict):
|
|
4226
4247
|
|
4227
4248
|
Parameters
|
4228
4249
|
----------
|
4229
|
-
filename : str
|
4230
|
-
Name of the file to save, if not provided a default will be used
|
4231
4250
|
start : int
|
4232
4251
|
First timestep to record, if not specified will use first available
|
4233
4252
|
end : int
|
4234
4253
|
Last timestep to record, if not specified will use last available
|
4235
|
-
|
4236
|
-
|
4237
|
-
quality : int
|
4238
|
-
Encoding quality, 1=low(default), 2=medium, 3=high, higher quality reduces
|
4239
|
-
encoding artifacts at cost of larger file size
|
4240
|
-
resolution : list or tuple
|
4241
|
-
Video resolution in pixels [x,y]
|
4242
|
-
**kwargs :
|
4243
|
-
Any additional keyword args will be passed to lavavu.player()
|
4254
|
+
|
4255
|
+
All other parameters same as video()
|
4244
4256
|
"""
|
4245
4257
|
|
4246
4258
|
try:
|
4247
|
-
|
4248
|
-
|
4259
|
+
steps = self.steps
|
4260
|
+
if end == 0: end = len(steps)
|
4261
|
+
steps = steps[start:end]
|
4262
|
+
from tqdm.notebook import tqdm
|
4263
|
+
with Video(self, filename, resolution, fps, quality, encoder, embed, player, options, **kwargs):
|
4264
|
+
for s in tqdm(steps, desc='Rendering loop'):
|
4265
|
+
self.timestep(s)
|
4266
|
+
self.render()
|
4249
4267
|
except (Exception) as e:
|
4250
4268
|
print("Video output error: " + str(e))
|
4251
4269
|
pass
|
@@ -4461,10 +4479,10 @@ class Viewer(dict):
|
|
4461
4479
|
for key in ["translate", "rotate", "xyzrotate", "fov", "focus"]:
|
4462
4480
|
if key in src:
|
4463
4481
|
dst[key] = copy.copy(src[key])
|
4464
|
-
#Round down arrays to max
|
4482
|
+
#Round down arrays to max 6 decimal places
|
4465
4483
|
try:
|
4466
4484
|
for r in range(len(dst[key])):
|
4467
|
-
dst[key][r] = round(dst[key][r],
|
4485
|
+
dst[key][r] = round(dst[key][r], 6)
|
4468
4486
|
except:
|
4469
4487
|
#Not a list/array
|
4470
4488
|
pass
|
@@ -4478,7 +4496,7 @@ class Viewer(dict):
|
|
4478
4496
|
#Set
|
4479
4497
|
if data is not None:
|
4480
4498
|
copyview(self.state["views"][0], data)
|
4481
|
-
self._set()
|
4499
|
+
self._set(reload=False)
|
4482
4500
|
|
4483
4501
|
#Return
|
4484
4502
|
return vdat
|
@@ -4501,7 +4519,7 @@ class Viewer(dict):
|
|
4501
4519
|
if at is None:
|
4502
4520
|
at = self["focus"]
|
4503
4521
|
else:
|
4504
|
-
self
|
4522
|
+
self.focus(*at)
|
4505
4523
|
|
4506
4524
|
# Default to Y-axis up vector
|
4507
4525
|
if up is None:
|
@@ -4545,7 +4563,7 @@ class Viewer(dict):
|
|
4545
4563
|
res = res / numpy.linalg.norm(res)
|
4546
4564
|
final[key] = res.tolist()
|
4547
4565
|
|
4548
|
-
self.camera(final)
|
4566
|
+
self.camera(final, quiet=True)
|
4549
4567
|
|
4550
4568
|
def flyto(self, pos, steps, stop=False, callback=None):
|
4551
4569
|
# Fly using current camera orientation as start point
|
@@ -4553,7 +4571,7 @@ class Viewer(dict):
|
|
4553
4571
|
return self.fly(pos0, pos, steps, stop, callback)
|
4554
4572
|
|
4555
4573
|
def fly(self, pos0, pos1, steps, stop=False, callback=None):
|
4556
|
-
self.camera(pos0)
|
4574
|
+
self.camera(pos0, quiet=True)
|
4557
4575
|
self.render()
|
4558
4576
|
|
4559
4577
|
for i in range(steps):
|
@@ -5390,49 +5408,44 @@ def player(filename, params="controls autoplay loop", **kwargs):
|
|
5390
5408
|
|
5391
5409
|
if is_notebook():
|
5392
5410
|
from IPython.display import display,HTML,Video,Javascript
|
5393
|
-
import uuid
|
5394
|
-
vid = 'video_' + str(uuid.uuid4())[:8]
|
5395
|
-
|
5396
|
-
'''
|
5397
|
-
def get_fn(filename):
|
5398
|
-
import os
|
5399
|
-
#This is unreliable, path incorrect on NCI
|
5400
|
-
nbpath = os.getenv('JPY_SESSION_NAME')
|
5401
|
-
if nbpath is not None:
|
5402
|
-
import os.path
|
5403
|
-
relpath = os.path.relpath(os.getcwd(), start=os.path.dirname(nbpath))
|
5404
|
-
return relpath + '/' + filename
|
5405
|
-
return filename
|
5406
|
-
''';
|
5407
|
-
|
5408
|
-
#Embed player
|
5409
|
-
filename = os.path.relpath(filename)
|
5410
|
-
display(Video(url=filename, html_attributes=f"id='{vid}' " + params, **kwargs))
|
5411
|
-
|
5412
|
-
#Add download link
|
5413
|
-
display(HTML(f'<a id="link_{vid}" href="{filename}" download>Download Video</a>'))
|
5414
5411
|
|
5415
5412
|
# Fallback - replace url on gadi and similar jupyterhub installs with
|
5416
5413
|
# fixed working directory that doesn't match notebook dir
|
5417
5414
|
# check the video tag url and remove subpath on 404 error
|
5418
|
-
|
5419
|
-
|
5420
|
-
|
5421
|
-
|
5422
|
-
|
5423
|
-
|
5424
|
-
|
5425
|
-
|
5426
|
-
|
5427
|
-
|
5428
|
-
|
5429
|
-
|
5430
|
-
|
5431
|
-
|
5432
|
-
|
5433
|
-
|
5434
|
-
|
5435
|
-
|
5415
|
+
onerror = """{
|
5416
|
+
let url = this.src;
|
5417
|
+
console.log('Error in video url: ' + url);
|
5418
|
+
var urlp = new window.URL(url);
|
5419
|
+
let toppath = '/files/home/';
|
5420
|
+
let startidx = urlp.pathname.indexOf(toppath);
|
5421
|
+
if (startidx < 0) {
|
5422
|
+
toppath = '/files/';
|
5423
|
+
startidx = urlp.pathname.indexOf(toppath);
|
5424
|
+
}
|
5425
|
+
if (startidx >= 0) {
|
5426
|
+
let filename = urlp.pathname.split('/').pop();
|
5427
|
+
let base = urlp.pathname.substring(0, startidx+toppath.length);
|
5428
|
+
urlp.pathname = base + filename;
|
5429
|
+
if (url != urlp.href) {
|
5430
|
+
console.log('Replaced video url: ' + urlp.href);
|
5431
|
+
this.src = urlp.href;
|
5432
|
+
//Also fix download link
|
5433
|
+
let link = document.getElementById('link_' + this.id);
|
5434
|
+
if (link) link.href = urlp.href;
|
5435
|
+
}
|
5436
|
+
}
|
5437
|
+
}"""
|
5438
|
+
|
5439
|
+
if "embed" in kwargs:
|
5440
|
+
#Not needed if embedding
|
5441
|
+
onerror = ""
|
5442
|
+
|
5443
|
+
#Display player and download link
|
5444
|
+
import uuid
|
5445
|
+
vid = 'video_' + str(uuid.uuid4())[:8]
|
5446
|
+
filename = os.path.relpath(filename)
|
5447
|
+
display(Video(filename=filename, html_attributes=f'id="{vid}" onerror="{onerror}" ' + params, **kwargs),
|
5448
|
+
HTML(f'<a id="link_{vid}" href="{filename}" download>Download Video</a>'))
|
5436
5449
|
|
5437
5450
|
#Class for managing video animation recording
|
5438
5451
|
class Video(object):
|
@@ -5452,7 +5465,7 @@ class Video(object):
|
|
5452
5465
|
... lv.rotate('y', 10) # doctest: +SKIP
|
5453
5466
|
... lv.render() # doctest: +SKIP
|
5454
5467
|
"""
|
5455
|
-
def __init__(self, viewer
|
5468
|
+
def __init__(self, viewer, filename="output.mp4", resolution=(0,0), framerate=30, quality=2, encoder="h264", embed=False, player=None, options={}, **kwargs):
|
5456
5469
|
"""
|
5457
5470
|
Record and show the generated video inline within an ipython notebook.
|
5458
5471
|
|
@@ -5472,13 +5485,16 @@ class Video(object):
|
|
5472
5485
|
fps : int
|
5473
5486
|
Frames to output per second of video
|
5474
5487
|
quality : int
|
5475
|
-
Encoding quality, 1=low, 2=medium, 3=high, higher quality reduces
|
5488
|
+
Encoding quality, 1=low, 2=medium(default), 3=high, higher quality reduces
|
5476
5489
|
encoding artifacts at cost of larger file size
|
5477
5490
|
If omitted will use default settings, can fine tune settings in kwargs
|
5478
5491
|
resolution : list or tuple
|
5479
5492
|
Video resolution in pixels [x,y]
|
5480
5493
|
encoder : str
|
5481
5494
|
Name of encoder to use, eg: "h264" (default), "mpeg"
|
5495
|
+
embed : bool
|
5496
|
+
Set to true to embed the video file rather than link to url
|
5497
|
+
Not recommended for large videos, default is False
|
5482
5498
|
player : dict
|
5483
5499
|
Args to pass to the player when the video is finished, eg:
|
5484
5500
|
{"width" : 800, "height", 400, "params": "controls autoplay"}
|
@@ -5491,21 +5507,30 @@ class Video(object):
|
|
5491
5507
|
if av is None:
|
5492
5508
|
raise(ImportError("Video output not supported without pyAV - pip install av"))
|
5493
5509
|
return
|
5494
|
-
self.resolution = resolution
|
5495
|
-
if self.resolution[0] == 0:
|
5496
|
-
self.resolution = viewer.width
|
5497
|
-
|
5498
|
-
|
5510
|
+
self.resolution = list(resolution)
|
5511
|
+
if self.resolution[0] == 0 or self.resolution[1] == 0:
|
5512
|
+
self.resolution = (viewer.app.viewer.width, viewer.app.viewer.height)
|
5513
|
+
#Ensure resolution values are even or encoder fails
|
5514
|
+
self.resolution = (2 * int(self.resolution[0]//2), 2 * int(self.resolution[1] // 2))
|
5499
5515
|
self.framerate = framerate
|
5500
5516
|
self.quality = quality
|
5501
5517
|
self.viewer = viewer
|
5502
5518
|
self.filename = filename
|
5503
|
-
if len(self.filename) == 0:
|
5504
|
-
self.filename = "lavavu.mp4"
|
5505
5519
|
self.player = player
|
5506
5520
|
if self.player is None:
|
5507
|
-
#Default player is half output resolution
|
5508
|
-
|
5521
|
+
#Default player is half output resolution, unless < 900 then full
|
5522
|
+
if "width" in kwargs or "height" in kwargs or "params" in kwargs:
|
5523
|
+
#Back compatibility with old args
|
5524
|
+
self.player = {}
|
5525
|
+
self.player.update(kwargs)
|
5526
|
+
kwargs = {}
|
5527
|
+
elif self.resolution[0] > 900:
|
5528
|
+
#Larger output res - default to half size player
|
5529
|
+
self.player = {"width": self.resolution[0]//2, "height": self.resolution[1]//2}
|
5530
|
+
else:
|
5531
|
+
self.player = {}
|
5532
|
+
if embed:
|
5533
|
+
self.player["embed"] = True
|
5509
5534
|
self.encoder = encoder
|
5510
5535
|
self.options = options
|
5511
5536
|
#Also include extra args
|
@@ -5603,6 +5628,7 @@ class Video(object):
|
|
5603
5628
|
self.container.close()
|
5604
5629
|
self.container = None
|
5605
5630
|
self.stream = None
|
5631
|
+
self.viewer.recording = None
|
5606
5632
|
|
5607
5633
|
def write(self, image):
|
5608
5634
|
"""
|
@@ -5630,9 +5656,8 @@ class Video(object):
|
|
5630
5656
|
|
5631
5657
|
def play(self):
|
5632
5658
|
"""
|
5633
|
-
Show the video in an inline player if in an
|
5659
|
+
Show the video in an inline player if in an interactive notebook
|
5634
5660
|
"""
|
5635
|
-
print(self.player)
|
5636
5661
|
player(self.filename, **self.player)
|
5637
5662
|
|
5638
5663
|
def __enter__(self):
|
lavavu/tracers.py
CHANGED
@@ -1,124 +1,194 @@
|
|
1
1
|
"""
|
2
|
-
Warning! EXPERIMENTAL:
|
3
|
-
these features and functions are under development, will have bugs,
|
4
|
-
and may be heavily modified in the future
|
5
|
-
|
6
2
|
Tracer particles in a vector field
|
7
|
-
Uses a KDTree to find nearest vector to advect the particles
|
8
3
|
|
9
|
-
- Requires scipy.
|
4
|
+
- Requires scipy.interpolate
|
10
5
|
"""
|
11
6
|
import numpy
|
12
7
|
import os
|
13
8
|
import sys
|
14
9
|
import random
|
15
|
-
import
|
16
|
-
from scipy import spatial
|
17
|
-
|
18
|
-
#Necessary? for large trees, detect?
|
19
|
-
#sys.setrecursionlimit(10000)
|
10
|
+
from scipy.interpolate import RegularGridInterpolator
|
20
11
|
|
21
|
-
|
22
|
-
def __init__(self, verts, N=5000):
|
23
|
-
self.tree = spatial.cKDTree(verts)
|
24
|
-
self.tracers = None
|
25
|
-
self.steps = [0]*N
|
26
|
-
self.values = None
|
27
|
-
self.positions = None
|
28
|
-
self.velocities = None
|
29
|
-
|
30
|
-
def trace_particles(state, verts, vecs, N=5000, limit=0.5, speed=1.0, noise=0.0, height=None):
|
12
|
+
def random_particles(count, lowerbound=[0,0,0], upperbound=[1,1,1], dims=3):
|
31
13
|
"""
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
- find the nearest velocity grid point
|
36
|
-
- if within max dist: Multiply position by velocity vector
|
37
|
-
- otherwise: Generate a new start position for tracer
|
38
|
-
|
39
|
-
Parameters
|
40
|
-
----------
|
41
|
-
state : TracerState
|
42
|
-
Object returned from first call, pass None on first pass
|
43
|
-
verts : array or list
|
44
|
-
vertices of the vector field
|
45
|
-
vecs : array or list
|
46
|
-
vector values of the vector field
|
47
|
-
N : int
|
48
|
-
Number of particles to seed
|
49
|
-
limit : float
|
50
|
-
Distance limit over which tracers are not connected,
|
51
|
-
For example if using a periodic boundary, setting limit to
|
52
|
-
half the bounding box size will prevent tracer lines being
|
53
|
-
connected when passing through the boundary
|
54
|
-
speed : float
|
55
|
-
Speed multiplier, scaling factor for the velocity taken from the vector values
|
56
|
-
noise : float
|
57
|
-
A noise factor, if set a random value is generated, multiplied by noise factor
|
58
|
-
and added to each new position
|
59
|
-
height : float
|
60
|
-
A fixed height value, all positions will be given this height as their Z component
|
61
|
-
|
62
|
-
Returns
|
63
|
-
-------
|
64
|
-
TracerState
|
65
|
-
Object to hold the tracer state and track particles
|
66
|
-
Pass this as first paramter on subsequent calls
|
14
|
+
Return an array of *count* 3d vertices of random particle positions
|
15
|
+
Minimum and maximum values defined by lowerbound and upperbound
|
67
16
|
"""
|
17
|
+
p = [None] * dims
|
18
|
+
for c in range(dims):
|
19
|
+
if lowerbound[c] == upperbound[c]:
|
20
|
+
p[c] = numpy.zeros(shape=(count)) + lowerbound[c]
|
21
|
+
else:
|
22
|
+
p[c] = numpy.random.uniform(low=lowerbound[c], high=upperbound[c], size=count)
|
23
|
+
|
24
|
+
return numpy.stack(p).T
|
68
25
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
26
|
+
class Tracers():
|
27
|
+
def __init__(self, grid, count=1000, lowerbound=None, upperbound=None, limit=None, age=4, respawn_chance=0.2, speed_multiply=1.0, height=0.0, viewer=None):
|
28
|
+
"""
|
29
|
+
Seed random particles into a vector field and trace their positions
|
30
|
+
|
31
|
+
Parameters
|
32
|
+
----------
|
33
|
+
grid : list of coord arrays for each dimension as expected by RegularGridInterpolator,
|
34
|
+
or a numpy array of 2d or 3d vertices, which will be converted before being sent to the interpolator
|
35
|
+
Object returned from first call, pass None on first pass
|
36
|
+
count : int
|
37
|
+
Number of particles to seed and track
|
38
|
+
lowerbound : optional minimum vertex point defining particle bounding box,
|
39
|
+
if not provided will be taken from grid lower corner
|
40
|
+
upperbound : optional maximum vertex point defining particle bounding box,
|
41
|
+
if not provided will be taken from grid upper corner
|
42
|
+
limit : float
|
43
|
+
Distance limit over which tracers are not connected,
|
44
|
+
For example if using a periodic boundary, setting limit to
|
45
|
+
half the bounding box size will prevent tracer lines being
|
46
|
+
connected when passing through the boundary
|
47
|
+
age : int
|
48
|
+
Minimum particle age in steps after which particle can be deleted and respawned, defaults to 4
|
49
|
+
respawn : float
|
50
|
+
Probability of respawning, after age reached, default 0.2 ==> 1 in 5 chance of deletion
|
51
|
+
speed_multiply : float
|
52
|
+
Speed multiplier, scaling factor for the velocity taken from the vector values
|
53
|
+
height : float
|
54
|
+
A fixed height value, all positions will be given this height as their Z component
|
55
|
+
viewer : lavavu.Viewer
|
56
|
+
Viewer object for plotting functions
|
57
|
+
"""
|
58
|
+
if len(grid) == 2:
|
59
|
+
self.gridx = grid[0]
|
60
|
+
self.gridy = grid[1]
|
61
|
+
self.gridz = numpy.array((height, height))
|
62
|
+
self.dims = 2
|
63
|
+
elif len(grid) == 3:
|
64
|
+
self.gridx = grid[0]
|
65
|
+
self.gridy = grid[1]
|
66
|
+
self.gridz = grid[2]
|
67
|
+
self.dims = 3
|
68
|
+
elif isinstance(grid, numpy.ndarray) and grid.shape[1] == 3:
|
69
|
+
self.gridx = grid[::,0]
|
70
|
+
self.gridy = grid[::,1]
|
71
|
+
self.gridz = grid[::,2]
|
72
|
+
self.dims = 3
|
73
|
+
elif isinstance(grid, numpy.ndarray) and grid.shape[1] == 2:
|
74
|
+
self.gridx = grid[::,0]
|
75
|
+
self.gridy = grid[::,1]
|
76
|
+
self.gridz = numpy.array((height, height))
|
77
|
+
self.dims = 2
|
114
78
|
else:
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
79
|
+
raise(ValueError('Grid needs to be array of 2d/3d vertices, or arrays of vertex coords (x, y, [z])'))
|
80
|
+
|
81
|
+
self.count = count
|
82
|
+
if lowerbound is None:
|
83
|
+
lowerbound = (self.gridx[0], self.gridy[0], self.gridz[0])
|
84
|
+
if upperbound is None:
|
85
|
+
upperbound = (self.gridx[-1], self.gridy[-1], self.gridz[-1])
|
86
|
+
self.positions = random_particles(self.count, lowerbound, upperbound, self.dims)
|
87
|
+
self.old_pos = numpy.zeros_like(self.positions)
|
88
|
+
self.lowerbound = lowerbound
|
89
|
+
self.upperbound = upperbound
|
90
|
+
self.velocities = None
|
91
|
+
self.steps = [0]*count
|
92
|
+
self.speed = numpy.zeros(shape=(count))
|
93
|
+
self.ages = numpy.zeros(shape=(count))
|
94
|
+
self.interp = None
|
95
|
+
if limit is None:
|
96
|
+
limit = 0.1 * (abs(self.gridx[-1] - self.gridx[0]) + abs(self.gridy[-1] - self.gridy[0]))
|
97
|
+
self.limit = limit
|
98
|
+
self.age = age
|
99
|
+
self.respawn_chance = respawn_chance
|
100
|
+
self.speed_multiply = speed_multiply
|
101
|
+
self.height = height
|
102
|
+
|
103
|
+
self.lv = viewer
|
104
|
+
self.points = None
|
105
|
+
self.arrows = None
|
106
|
+
self.tracers = None
|
107
|
+
|
108
|
+
|
109
|
+
def respawn(self, r):
|
110
|
+
#Dead or out of bounds particle, start at new position
|
111
|
+
#Loop until new position further from current position than limit
|
112
|
+
old_pos = self.positions[r]
|
113
|
+
pos = numpy.array([0.] * self.dims)
|
114
|
+
for i in range(10):
|
115
|
+
pos = random_particles(1, self.lowerbound, self.upperbound, self.dims)
|
116
|
+
dist = numpy.linalg.norm(old_pos - pos)
|
117
|
+
if dist > self.limit*1.01:
|
118
|
+
break
|
119
|
+
|
120
|
+
self.ages[r] = 0
|
121
|
+
self.positions[r] = pos
|
122
|
+
|
123
|
+
def update(self, vectors=None):
|
124
|
+
#Interpolate velocity at all positions,
|
125
|
+
#If vectors not passed, will use previous values
|
126
|
+
if vectors is not None:
|
127
|
+
if self.dims == 2:
|
128
|
+
self.interp = RegularGridInterpolator((self.gridx, self.gridy), vectors, bounds_error=False, fill_value=0.0)
|
129
|
+
else:
|
130
|
+
self.interp = RegularGridInterpolator((self.gridx, self.gridy, self.gridz), vectors, bounds_error=False, fill_value=0.0)
|
131
|
+
|
132
|
+
if self.interp is None:
|
133
|
+
raise(ValueError("No velocity grid, must pass vectors for first call of update()"))
|
134
|
+
|
135
|
+
self.velocities = self.interp(self.positions)
|
136
|
+
self.old_pos = numpy.copy(self.positions)
|
137
|
+
|
138
|
+
for r in range(len(self.velocities)):
|
139
|
+
#Lookup velocity at this index, multiply by position to get delta and add
|
140
|
+
self.speed[r] = numpy.linalg.norm(self.velocities[r])
|
141
|
+
if numpy.isnan(self.speed[r]): self.speed[r] = 0.0
|
142
|
+
if self.speed[r] == 0.0: #numpy.any(numpy.isinf(self.old_pos[r])) or numpy.any(numpy.isinf(self.positions[r])):
|
143
|
+
self.respawn(r)
|
144
|
+
else:
|
145
|
+
self.positions[r] = self.positions[r] + self.speed_multiply * self.velocities[r]
|
146
|
+
self.ages[r] += 1
|
147
|
+
|
148
|
+
#Bounds checks
|
149
|
+
#Chance of killing particle when over age, default 1 in 5 (0.2)
|
150
|
+
if (any(self.positions[r] < self.lowerbound[0:self.dims]) or any(self.positions[r] > self.upperbound[0:self.dims])
|
151
|
+
or (self.ages[r] > self.age and numpy.random.uniform() <= self.respawn_chance)):
|
152
|
+
#if r < 20: print("Kill", r, self.speed[r], numpy.isnan(self.speed[r])) # [0] == numpy.nan)
|
153
|
+
#self.positions[r] = numpy.array([numpy.inf] * self.dims)
|
154
|
+
#self.positions[r] = numpy.array([numpy.nan] * self.dims)
|
155
|
+
self.respawn(r)
|
156
|
+
self.velocities[r] = numpy.array([0.0] * self.dims)
|
157
|
+
self.speed[r] = 0.0
|
158
|
+
|
159
|
+
if self.lv:
|
160
|
+
positions = self.positions
|
161
|
+
if self.dims == 2 and self.height != 0:
|
162
|
+
#Convert to 3d and set z coord to height
|
163
|
+
shape = list(positions.shape)
|
164
|
+
shape[-1] = 3
|
165
|
+
positions = numpy.zeros(shape)
|
166
|
+
positions[::,0:2] = self.positions
|
167
|
+
positions[::,2] = numpy.array([self.height] * shape[0])
|
168
|
+
if self.points:
|
169
|
+
self.points.vertices(positions)
|
170
|
+
if len(self.points["colourmap"]):
|
171
|
+
self.points.values(self.speed)
|
172
|
+
if self.arrows:
|
173
|
+
self.arrows.vectors(self.velocities)
|
174
|
+
self.arrows.vertices(positions)
|
175
|
+
if len(self.arrows["colourmap"]):
|
176
|
+
self.arrows.values(self.speed)
|
177
|
+
|
178
|
+
if self.tracers:
|
179
|
+
self.tracers.vertices(positions)
|
180
|
+
if len(self.tracers["colourmap"]):
|
181
|
+
self.tracers.values(self.speed)
|
182
|
+
|
183
|
+
def plot_points(self, **kwargs):
|
184
|
+
if self.lv is not None and self.points is None:
|
185
|
+
self.points = self.lv.points('tracer_points', **kwargs)
|
186
|
+
|
187
|
+
def plot_arrows(self, **kwargs):
|
188
|
+
if self.lv is not None and self.arrows is None:
|
189
|
+
self.arrows = self.lv.vectors('tracer_arrows', **kwargs)
|
190
|
+
|
191
|
+
def plot_tracers(self, **kwargs):
|
192
|
+
if self.lv is not None and self.tracers is None:
|
193
|
+
self.tracers = self.lv.tracers('tracers', dims=self.count, limit=self.limit, **kwargs)
|
124
194
|
|
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: lavavu
|
3
|
-
Version: 1.9.
|
3
|
+
Version: 1.9.6
|
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
|
@@ -215,14 +215,16 @@ License-File: LICENSE.md
|
|
215
215
|
Requires-Dist: numpy>=1.18
|
216
216
|
Requires-Dist: aiohttp
|
217
217
|
Requires-Dist: jupyter_server_proxy
|
218
|
+
Requires-Dist: matplotlib
|
218
219
|
Requires-Dist: numpy-quaternion
|
220
|
+
Dynamic: license-file
|
219
221
|
|
220
222
|

|
221
223
|
|
222
224
|
[](https://github.com/lavavu/LavaVu/actions?query=workflow:Test)
|
223
225
|
[](https://github.com/lavavu/LavaVu/actions?query=workflow:Deploy)
|
224
226
|
[](https://zenodo.org/badge/latestdoi/45163055)
|
225
|
-
[](https://mybinder.org/v2/gh/lavavu/LavaVu/1.9.
|
227
|
+
[](https://mybinder.org/v2/gh/lavavu/LavaVu/1.9.6)
|
226
228
|
|
227
229
|
A scientific visualisation tool with a python interface for fast and flexible visual analysis.
|
228
230
|
|
@@ -230,11 +232,12 @@ Documentation available here [LavaVu Documentation](https://lavavu.github.io/Doc
|
|
230
232
|
|
231
233
|

|
232
234
|
|
233
|
-
LavaVu development is supported by
|
235
|
+
LavaVu development is supported by [ACCESS-NRI](https://www.access-nri.org.au/).
|
236
|
+
Prior development was funded by the Monash Immersive Visualisation Plaform at [Monash eResearch](https://www.monash.edu/researchinfrastructure/eresearch) and the Simulation, Analysis & Modelling component of the [NCRIS AuScope](http://www.auscope.org.au/ncris/) capability.
|
234
237
|
|
235
238
|
The acronym stands for: lightweight, automatable visualisation and analysis viewing utility, but "lava" is also a reference to its primary application as a viewer for geophysical simulations. It was also chosen to be unique enough to find the repository with google.
|
236
239
|
|
237
|
-
The project started
|
240
|
+
The project started as a replacement rendering library for the gLucifer<sup>1</sup> framework, visualising geodynamics simulations. The new OpenGL visualisation code was re-implemented as a more general purpose visualisation tool. gLucifer continues as a set of sampling tools for Underworld simulations as part of the [Underworld2](https://github.com/underworldcode/underworld2/) code. LavaVu provides the rendering library for creating 2d and 3d visualisations to view this sampled data, inline within interactive Jupyter notebooks and offline through saved visualisation databases and images/movies.
|
238
241
|
|
239
242
|
As a standalone tool it is a scriptable 3D visualisation tool capable of producing publication quality high res images and video output from time varying data sets along with HTML5 3D visualisations in WebGL.
|
240
243
|
Rendering features include correctly and efficiently rendering large numbers of opaque and transparent points and surfaces and volume rendering by GPU ray-marching. There are also features for drawing vector fields and tracers (streamlines).
|
@@ -242,12 +245,11 @@ Rendering features include correctly and efficiently rendering large numbers of
|
|
242
245
|
Control is via python and a set of simple verbose scripting commands along with mouse/keyboard interaction.
|
243
246
|
GUI components can be generated for use from a web browser via the python "control" module and a built in web server.
|
244
247
|
|
248
|
+
Widgets for interactive use in the Jupyter notebook environment allow use for remote visualisation, eg: on supercomputing environments.
|
249
|
+
|
245
250
|
A native data format called GLDB is used to store and visualisations in a compact single file, using SQLite for storage and fast loading. A small number of other data formats are supported for import (OBJ surfaces, TIFF stacks etc).
|
246
251
|
Further data import formats are supported with python scripts, with the numpy interface allowing rapid loading and manipulation of data.
|
247
252
|
|
248
|
-
A CAVE2 virtual reality mode is provided by utilising Omegalib (http://github.com/uic-evl/omegalib) to allow use in Virtual Reality and Immersive Visualisation facilities, such as the CAVE2 at Monash, see (https://github.com/mivp/LavaVR).
|
249
|
-
Side-by-side and quad buffer stereoscopic 3D support is also provided for other 3D displays.
|
250
|
-
|
251
253
|
### This repository ###
|
252
254
|
|
253
255
|
This is the public source code repository for all development on the project.
|
@@ -258,13 +260,10 @@ Development happens in the "master" branch with stable releases tagged, so if yo
|
|
258
260
|
It's now in the python package index, so you can install with *pip*:
|
259
261
|
|
260
262
|
```
|
261
|
-
pip install
|
263
|
+
python -m pip install lavavu
|
262
264
|
```
|
263
265
|
|
264
|
-
>
|
265
|
-
|
266
|
-
> Currently no binaries are provided and the installer needs to compile the library, so on Linux you may need some developer tools and headers first, eg: for Ubuntu:
|
267
|
-
`sudo apt install build-essential libgl1-mesa-dev libx11-dev zlib1g-dev`
|
266
|
+
> Currently binary wheels are provided for Linux x86_64, MacOS x86_64 and ARM64 and Windows x86_64.
|
268
267
|
|
269
268
|
To try it out:
|
270
269
|
|
@@ -281,7 +280,12 @@ Alternatively, clone this repository with *git* and build from source:
|
|
281
280
|
```
|
282
281
|
git clone https://github.com/lavavu/LavaVu
|
283
282
|
cd LavaVu
|
283
|
+
python -m pip install .
|
284
|
+
```
|
285
|
+
or
|
286
|
+
```
|
284
287
|
make -j4
|
288
|
+
|
285
289
|
```
|
286
290
|
|
287
291
|
If all goes well the viewer will be built, try running with:
|
@@ -290,14 +294,14 @@ If all goes well the viewer will be built, try running with:
|
|
290
294
|
### Dependencies ###
|
291
295
|
|
292
296
|
* OpenGL and Zlib, present on most systems, headers may need to be installed
|
293
|
-
* To use with python requires python
|
294
|
-
* For video output, requires: libavcodec, libavformat, libavutil, libswscale (from FFmpeg / libav)
|
297
|
+
* To use with python requires python 3.6+ and NumPy
|
298
|
+
* For video output, requires: PyAV or for built in encoding, libavcodec, libavformat, libavutil, libswscale (from FFmpeg / libav)
|
295
299
|
* To build the python interface from source requires swig (http://www.swig.org/)
|
296
300
|
|
297
301
|
### Who do I talk to? ###
|
298
302
|
|
299
303
|
* Report bugs/issues here on github: https://github.com/lavavu/LavaVu/issues
|
300
|
-
* Contact developer: Owen Kaluza (at)
|
304
|
+
* Contact developer: Owen Kaluza (at) anu.edu.au
|
301
305
|
|
302
306
|
For further documentation / examples, see the online documentation
|
303
307
|
* https://lavavu.github.io/Documentation
|
@@ -1,18 +1,18 @@
|
|
1
|
-
lavavu/lavavu.py,sha256=
|
1
|
+
lavavu/lavavu.py,sha256=I64ioPwTN1eyZcZEaF9RfdxncfLuihl-7VqqqJDFLCw,218528
|
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
|
5
5
|
lavavu/points.py,sha256=jRRtA6CrcA46Y2jUJmkxnIiVoMC5a14xEd_ojhmjhz4,5871
|
6
6
|
lavavu/LavaVuPython.py,sha256=ixhceiAr0gGGfCe3d2cY0IIgS4hbgoYJGa_RfgAmmrU,33207
|
7
|
-
lavavu/tracers.py,sha256
|
7
|
+
lavavu/tracers.py,sha256=-NwdBAj5vYWmLt4NE0gWl36SQShQhICR7vBE4rzNOFI,8488
|
8
8
|
lavavu/convert.py,sha256=tbYRjLE2l1hI4d6tsW41Lia1JXmrWSc0-JAYCiMrjys,35516
|
9
|
-
lavavu/control.py,sha256=
|
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
12
|
lavavu/aserver.py,sha256=SfFvLeDTcx1XtS8fY_HIrDmh3q9HicCBRSAriY5yyOE,12003
|
13
13
|
lavavu/font.bin,sha256=fvi5zkvmq6gh9v3jXedBVuxNJWKmHtbjECzv6eT9wb4,225360
|
14
14
|
lavavu/__main__.py,sha256=EbDetijCjyoiNxmExqnDGoRVs996tSVave5DML9zuMY,235
|
15
|
-
lavavu/_LavaVuPython.cpython-311-darwin.so,sha256=
|
15
|
+
lavavu/_LavaVuPython.cpython-311-darwin.so,sha256=4f_OIq_Z1CDwE96EOJLY_E-4pHxMRE1Quk5JEHHtqSM,3927376
|
16
16
|
lavavu/html/control.css,sha256=PVLwmle00ciEckUV5ZIRmI3Whxhl7-mlVexnyyxoU70,3259
|
17
17
|
lavavu/html/control.js,sha256=oV24eJZ0vfuCxF3fO60eeJSkNFJ9hUkSCThHGJS1Wvc,11652
|
18
18
|
lavavu/html/gui.css,sha256=PRDLsYwM6cgLC9zZsEAG0dnnSd-HYH6oSEfsdEBkuxk,582
|
@@ -27,11 +27,11 @@ 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=
|
30
|
+
lavavu/html/webview.html,sha256=8eilGjX8y_I5OjCvTm-ZAQDNOSCaT1yvogKFqK4lCS0,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
|
34
|
-
lavavu/html/menu.js,sha256=
|
34
|
+
lavavu/html/menu.js,sha256=42h-BCnrmEpW4IdZRKC_FIXUVczJP0sm4ciZ2ccfs-k,21630
|
35
35
|
lavavu/html/baseviewer.js,sha256=u3UhC1At6rMBKmcQ7d2DXTRxQ20wsQkc4lqA-7sL7i4,9567
|
36
36
|
lavavu/osmesa/LavaVuPython.py,sha256=ixhceiAr0gGGfCe3d2cY0IIgS4hbgoYJGa_RfgAmmrU,33207
|
37
37
|
lavavu/osmesa/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -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.
|
51
|
-
lavavu-1.9.
|
52
|
-
lavavu-1.9.
|
53
|
-
lavavu-1.9.
|
54
|
-
lavavu-1.9.
|
55
|
-
lavavu-1.9.
|
50
|
+
lavavu-1.9.6.dist-info/RECORD,,
|
51
|
+
lavavu-1.9.6.dist-info/WHEEL,sha256=EfZGgIDXTDki1cNGEkgBr7YEgShBrw-nMmb-y67Rxxs,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
|
File without changes
|
File without changes
|
File without changes
|