@@ -393,17 +393,15 @@ def get_uid_str(uid):
393393
394394 if (!data.success) {
395395 resolve(undefined);
396+ return;
396397 }
397398
398- if (key.includes("spatialdata_attrs") && key.endsWith("0") && !ArrayBuffer.isView(bufferData.buffer)) {
399- // For some reason, the Zarrita.js UnicodeStringArray does not seem to work with
400- // ArrayBuffers (throws a TypeError), so here we convert to Uint8Array if needed.
401- // This error is occurring specifically for the arr.getChunk call within the AnnDataSource._loadString function.
402- // TODO: figure out a more long-term solution.
403- resolve(new Uint8Array(bufferData.buffer));
399+ if (ArrayBuffer.isView(bufferData)) {
400+ resolve(new Uint8Array(bufferData.buffer, bufferData.byteOffset, bufferData.byteLength));
401+ return;
404402 }
405-
406- resolve(bufferData.buffer) ;
403+ resolve(new Uint8Array(bufferData.buffer));
404+ return ;
407405 });
408406 }
409407
@@ -435,15 +433,26 @@ def get_uid_str(uid):
435433 });
436434 if (!data.success) return undefined;
437435
438- if (key.includes("spatialdata_attrs") && key.endsWith("0") && !ArrayBuffer.isView(buffers[0].buffer)) {
439- // For some reason, the Zarrita.js UnicodeStringArray does not seem to work with
440- // ArrayBuffers (throws a TypeError), so here we convert to Uint8Array if needed.
441- // This error is occurring specifically for the arr.getChunk call within the AnnDataSource._loadString function.
442- // TODO: figure out a more long-term solution.
443- return new Uint8Array(buffers[0].buffer);
436+ if (ArrayBuffer.isView(buffers[0])) {
437+ return new Uint8Array(buffers[0].buffer, buffers[0].byteOffset, buffers[0].byteLength);
444438 }
439+ return new Uint8Array(buffers[0].buffer);
440+ }
441+ },
442+ async getRange(key, rangeQuery) {
443+ if (invokeBatched) {
444+ return enqueue([storeUrl, key, rangeQuery]);
445+ } else {
446+ // Do not submit zarr gets in batches. Instead, submit individually.
447+ const [data, buffers] = await view.experimental.invoke("_zarr_get_range", [storeUrl, key, rangeQuery], {
448+ signal: AbortSignal.timeout(invokeTimeout),
449+ });
450+ if (!data.success) return undefined;
445451
446- return buffers[0].buffer;
452+ if (ArrayBuffer.isView(buffers[0])) {
453+ return new Uint8Array(buffers[0].buffer, buffers[0].byteOffset, buffers[0].byteLength);
454+ }
455+ return new Uint8Array(buffers[0].buffer);
447456 }
448457 },
449458 }
@@ -729,7 +738,7 @@ class VitessceWidget(anywidget.AnyWidget):
729738
730739 next_port = DEFAULT_PORT
731740
732- js_package_version = Unicode ('3.9.2 ' ).tag (sync = True )
741+ js_package_version = Unicode ('3.9.4 ' ).tag (sync = True )
733742 js_dev_mode = Bool (False ).tag (sync = True )
734743 custom_js_url = Unicode ('' ).tag (sync = True )
735744 plugin_esm = List (trait = Unicode ('' ), default_value = []).tag (sync = True )
@@ -742,7 +751,7 @@ class VitessceWidget(anywidget.AnyWidget):
742751
743752 store_urls = List (trait = Unicode ('' ), default_value = []).tag (sync = True )
744753
745- def __init__ (self , config , height = 600 , theme = 'auto' , uid = None , port = None , proxy = False , js_package_version = '3.9.2 ' , js_dev_mode = False , custom_js_url = '' , plugins = None , remount_on_uid_change = True , prefer_local = True , invoke_timeout = 300000 , invoke_batched = True , page_mode = False , page_esm = None , prevent_scroll = True , server_host = None ):
754+ def __init__ (self , config , height = 600 , theme = 'auto' , uid = None , port = None , proxy = False , js_package_version = '3.9.4 ' , js_dev_mode = False , custom_js_url = '' , plugins = None , remount_on_uid_change = True , prefer_local = True , invoke_timeout = 300000 , invoke_batched = True , page_mode = False , page_esm = None , prevent_scroll = True , server_host = None ):
746755 """
747756 Construct a new Vitessce widget. Not intended to be instantiated directly; instead, use ``VitessceConfig.widget``.
748757
@@ -850,21 +859,42 @@ def _zarr_get(self, params, buffers):
850859 except KeyError :
851860 buffers = []
852861 return {"success" : len (buffers ) == 1 }, buffers
862+
863+ @anywidget .experimental .command
864+ def _zarr_get_range (self , params , buffers ):
865+ [store_url , key , range_query ] = params
866+ store = self ._stores [store_url ]
867+ try :
868+ full_value = store [key .lstrip ("/" )]
869+ # Reference: https://github.com/manzt/zarrita.js/blob/f63a2521e2b46b22aa26af4146822e4d827dff83/packages/%40zarrita-storage/src/types.ts#L3
870+ if "suffixLength" in range_query :
871+ suffix_length = range_query ["suffixLength" ]
872+ buffers = [full_value [- suffix_length :]]
873+ elif "offset" in range_query and "length" in range_query :
874+ offset = range_query ["offset" ]
875+ length = range_query ["length" ]
876+ buffers = [full_value [offset :offset + length ]]
877+ except KeyError :
878+ buffers = []
879+ return {"success" : len (buffers ) == 1 }, buffers
853880
854881 @anywidget .experimental .command
855882 def _zarr_get_multi (self , params_arr , buffers ):
856- # This variant of _zarr_get supports batching.
883+ # This variant of _zarr_get and _zarr_get_range supports batching.
857884 result_dicts = []
858885 result_buffers = []
859886 for params in params_arr :
860- [store_url , key ] = params
861- store = self ._stores [store_url ]
862- try :
863- result_buffers .append (store [key .lstrip ("/" )])
864- result_dicts .append ({"success" : True })
865- except KeyError :
866- result_buffers .append (b'' )
887+ if len (params ) == 2 :
888+ result_dict , result_buffer_arr = self ._zarr_get (params , buffers )
889+ elif len (params ) == 3 :
890+ result_dict , result_buffer_arr = self ._zarr_get_range (params , buffers )
891+
892+ if result_dict ["success" ] and len (result_buffer_arr ) == 1 :
893+ result_dicts .append (result_dict )
894+ result_buffers .append (result_buffer_arr [0 ])
895+ else :
867896 result_dicts .append ({"success" : False })
897+ result_buffers .append (b'' )
868898 return result_dicts , result_buffers
869899
870900 @anywidget .experimental .command
@@ -876,7 +906,7 @@ def _plugin_command(self, params, buffers):
876906# Launch Vitessce using plain HTML representation (no ipywidgets)
877907
878908
879- def ipython_display (config , height = 600 , theme = 'auto' , base_url = None , host_name = None , uid = None , port = None , proxy = False , js_package_version = '3.9.2 ' , js_dev_mode = False , custom_js_url = '' , plugins = None , remount_on_uid_change = True , page_mode = False , page_esm = None , server_host = None ):
909+ def ipython_display (config , height = 600 , theme = 'auto' , base_url = None , host_name = None , uid = None , port = None , proxy = False , js_package_version = '3.9.4 ' , js_dev_mode = False , custom_js_url = '' , plugins = None , remount_on_uid_change = True , page_mode = False , page_esm = None , server_host = None ):
880910 from IPython .display import display , HTML
881911 uid_str = "vitessce" + get_uid_str (uid )
882912
0 commit comments