def translate_line(steno3d_resource, view, _lookup_dict=None): """Translate Steno3D line into LineSet Element and Arrays""" vertices = files.Array(steno3d_resource.mesh.vertices) segments = files.Array(steno3d_resource.mesh.segments) data = [ translate_binder(dat, view, _lookup_dict=_lookup_dict) for dat in steno3d_resource.data ] element = spatial.ElementLineSet( name=steno3d_resource.title or '', description=steno3d_resource.description or '', vertices=vertices, segments=segments, data=data, ) if steno3d_resource.mesh.opts.view_type == 'tube': opts = spatial.OptionsTubes(radius={'value': 10}) else: opts = spatial.OptionsLines() opts.visible = True opts.color.value = 'random' opts.opacity.value = 1. if steno3d_resource.opts.color is not None: opts.color.value = steno3d_resource.opts.color if steno3d_resource.opts.opacity is not None: opts.opacity.value = steno3d_resource.opts.opacity element.defaults = opts view.contents += [vertices, segments, element] view.elements += [element] if _lookup_dict is not None and hasattr(steno3d_resource, '_upload_data'): _lookup_dict.update({steno3d_resource._upload_data['uid']: element}) return element
def translate_data_array(steno3d_data, location, view, _lookup_dict=None): """Translate Steno3D array data into Data, Mapping, and Arrays""" arr = files.Array(steno3d_data.array) data = spatial.DataBasic( name=steno3d_data.title or '', description=steno3d_data.description or '', array=arr, location=location, ) if steno3d_data.colormap is not None: gradient = files.Array(steno3d_data.colormap) mapping = spatial.MappingContinuous( gradient=gradient, data_controls=[ np.nanmin(steno3d_data.array), np.nanmax(steno3d_data.array), ], gradient_controls=[0., 1.], visibility=[True, True, True], ) data.mappings = [mapping] view.contents += [mapping, gradient] view.contents += [arr, data] if _lookup_dict is not None and hasattr(steno3d_data, '_upload_data'): _lookup_dict.update({steno3d_data._upload_data['uid']: data}) return data
def translate_data_category(steno3d_data, location, view, _lookup_dict=None): """Translate Steno3D category data into Data, Mappings, and Array""" arr = files.Array(steno3d_data.array) data = spatial.DataCategory( name=steno3d_data.title or '', description=steno3d_data.description or '', array=arr, location=location, ) if steno3d_data.categories is not None: mapping = spatial.MappingCategory( values=steno3d_data.categories, indices=list(range(len(steno3d_data.categories))), visibility=[True] * len(steno3d_data.categories), ) data.categories = mapping view.contents.append(mapping) if steno3d_data.colormap is not None: mapping = spatial.MappingCategory( values=steno3d_data.colormap, indices=list(range(len(steno3d_data.colormap))), visibility=[True] * len(steno3d_data.colormap), ) if not data.categories: data.categories = mapping else: data.mappings = [mapping] view.contents.append(mapping) view.contents += [arr, data] if _lookup_dict is not None and hasattr(steno3d_data, '_upload_data'): _lookup_dict.update({steno3d_data._upload_data['uid']: data}) return data
def translate_point(steno3d_resource, view, _lookup_dict=None): """Translate Steno3D point into PointSet Element and Array""" vertices = files.Array(steno3d_resource.mesh.vertices) data = [ translate_binder(dat, view, _lookup_dict=_lookup_dict) for dat in steno3d_resource.data ] + [ translations[tex.__class__](tex, view, _lookup_dict=_lookup_dict) for tex in steno3d_resource.textures ] element = spatial.ElementPointSet( name=steno3d_resource.title or '', description=steno3d_resource.description or '', vertices=vertices, data=data, ) if steno3d_resource.opts.color is not None: element.defaults.color.value = steno3d_resource.opts.color if steno3d_resource.opts.opacity is not None: element.defaults.opacity.value = steno3d_resource.opts.opacity view.contents += [vertices, element] view.elements += [element] if _lookup_dict is not None and hasattr(steno3d_resource, '_upload_data'): _lookup_dict.update({steno3d_resource._upload_data['uid']: element}) return element
def translate_data_discrete(steno3d_data, location, view, _lookup_dict=None): """Translate Steno3D discrete data into Data, Mapping, and Array""" arr = files.Array(steno3d_data.array) if steno3d_data.range_visibility is not None: visibility = [bool(rv) for rv in steno3d_data.range_visibility] else: visibility = [True] * (len(steno3d_data.end_values) + 1) if steno3d_data.end_inclusive is not None: end_inclusive = [bool(ei) for ei in steno3d_data.end_inclusive] else: end_inclusive = [True] * len(steno3d_data.end_values) mapping = spatial.MappingDiscrete( end_points=steno3d_data.end_values, visibility=visibility, end_inclusive=end_inclusive, values=steno3d_data.colormap or [''] * (len(steno3d_data.end_values) + 1), ) data = spatial.DataBasic(name=steno3d_data.title or '', description=steno3d_data.description or '', array=arr, location=location, mappings=[mapping]) view.contents += [arr, mapping, data] if _lookup_dict is not None and hasattr(steno3d_data, '_upload_data'): _lookup_dict.update({steno3d_data._upload_data['uid']: data}) return data
def translate_surface(steno3d_resource, view, _lookup_dict=None): """Translate Steno3D surface into Surface Element and Arrays""" data = [ translate_binder(dat, view, _lookup_dict=_lookup_dict) for dat in steno3d_resource.data ] + [ translations[tex.__class__](tex, view, _lookup_dict=_lookup_dict) for tex in steno3d_resource.textures ] if isinstance(steno3d_resource.mesh, steno3d.Mesh2D): vertices = files.Array(steno3d_resource.mesh.vertices) triangles = files.Array(steno3d_resource.mesh.triangles) element = spatial.ElementSurface( name=steno3d_resource.title or '', description=steno3d_resource.description or '', vertices=vertices, triangles=triangles, data=data, ) view.contents += [vertices, triangles] else: element = spatial.ElementSurfaceGrid( name=steno3d_resource.title or '', description=steno3d_resource.description or '', tensor_u=list(steno3d_resource.mesh.h1), tensor_v=list(steno3d_resource.mesh.h2), axis_u=steno3d_resource.mesh.U, axis_v=steno3d_resource.mesh.V, origin=steno3d_resource.mesh.O, data=data, ) if (steno3d_resource.mesh.Z is not None and len(steno3d_resource.mesh.Z)): offset_w = files.Array(steno3d_resource.mesh.Z) element.offset_w = offset_w view.contents.append(offset_w) if steno3d_resource.opts.color is not None: element.defaults.color.value = steno3d_resource.opts.color if steno3d_resource.opts.opacity is not None: element.defaults.opacity.value = steno3d_resource.opts.opacity if steno3d_resource.mesh.opts.wireframe is not None: element.defaults.wireframe.active = steno3d_resource.mesh.opts.wireframe view.contents.append(element) view.elements += [element] if _lookup_dict is not None and hasattr(steno3d_resource, '_upload_data'): _lookup_dict.update({steno3d_resource._upload_data['uid']: element}) return element
def test_array_init(input_arr): arr = files.Array(input_arr) assert arr.validate() assert isinstance(arr.array, np.ndarray) assert np.array_equal(arr.array, np.array([1, 2, 3])) assert arr.dtype.startswith('Int') assert arr.shape == [3] assert arr.content_type == 'application/octet-stream' assert arr.content_length == np.dtype(arr.array.dtype).itemsize * 3 assert arr.is_1d()
def test_array_serialize(): arr = files.Array([[1]]) arr.validate() serial_arr = arr.serialize() assert serial_arr == { '__class__': 'Array', 'content_length': np.dtype(arr.array.dtype).itemsize, 'content_type': 'application/octet-stream', 'dtype': 'Int32Array', 'shape': [1, 1], }
def test_upload(mock_regex, mock_upload_image, mock_upload_array, mock_put, mock_patch, mock_post, verbose, workers, parallel, session): mock_resp = mock.MagicMock() mock_resp.json.return_value = { 'links': { 'self': 'https://example.com/api/self', 'location': 'https://example.com/api/location', 'thumbnail': 'https://example.com/api/self/thumbnail' }, } mock_resp.ok = True mock_post.return_value = mock_resp mock_patch.return_value = mock_resp mock_put.return_value = mock_resp mock_file_resp = mock.MagicMock() mock_file_resp.json.return_value = {} mock_file_resp.ok = True mock_upload_array.return_value = mock_file_resp mock_upload_image.return_value = mock_file_resp mock_regex.return_value = re.compile(r'^https://example\.com/api/') mapping_uploaded = spatial.MappingDiscrete( values=[(255, 0, 0), (0, 255, 0), (0, 0, 255)], end_points=[10., 20.], end_inclusive=[True, True], visibility=[True, True, True], ) mapping_uploaded._links = { 'self': 'https://example.com/api/mapping_uploaded' } array_data = files.Array([0., 10, 20]) img = io.BytesIO() s = [[0, 1, 0, 1], [1, 0, 1, 0], [0, 1, 0, 1], [1, 0, 1, 0]] w = png.Writer(4, 4, greyscale=True, bitdepth=16) w.write(img, s) view = manifests.View( name='Test View', elements=[ spatial.ElementPointSet( vertices=files.Array([[0., 0, 0], [1, 1, 1], [2, 2, 2]]), data=[ spatial.DataBasic( name='Dataset 1', location='n', array=array_data, uid='local_id', ), spatial.DataBasic( name='Dataset 2', description='Same array as dataset 1', location='n', array=array_data, mappings=[ spatial.MappingContinuous( gradient='https://example.com/api/my_colormap', data_controls=[0., 10., 20., 30.], ), mapping_uploaded, ]), spatial.TextureProjection( origin=[0., 0, 0], axis_u=[1., 0, 0], axis_v=[0., 1, 0], image=img, ), ], defaults={ 'color': { 'value': '#FF0000' }, 'opacity': { 'value': 1 }, 'size': { 'value': 10 }, 'shape': 'square' }, ), 'https://example.com/api/my_element', ]) try: dirname, _ = os.path.split(os.path.abspath(__file__)) png_file = os.path.sep.join(dirname.split(os.path.sep) + ['temp.png']) s = ['110010010011', '101011010100', '110010110101', '100010010011'] s = [[int(v) for v in val] for val in s] f = open(png_file, 'wb') w = png.Writer(len(s[0]), len(s), greyscale=True, bitdepth=16) w.write(f, s) f.close() session.upload( view, verbose=verbose, thumbnail=png_file, parallel=parallel, workers=workers, ) finally: os.remove(png_file) assert mock_post.call_count == 9 assert mock_patch.call_count == 1 assert mock_put.call_count == 1 assert mock_upload_array.call_count == 2 assert mock_upload_image.call_count == 2 mock_post.assert_has_calls( [ mock.call( 'https://example.com/api/v1/project/myorg/myproj/files/array', json={ 'shape': [3, 3], 'dtype': 'Float64Array', 'content_type': 'application/octet-stream', 'content_length': 31, 'content_encoding': 'gzip' }, ), mock.call( 'https://example.com/api/v1/project/myorg/myproj/files/array', json={ 'shape': [3], 'dtype': 'Float64Array', 'content_type': 'application/octet-stream', 'content_length': 24, # this file is 29 bytes when compressed }, ), mock.call( 'https://example.com/api/v1/project/myorg/myproj/files/image', json={ 'content_type': 'image/png', 'content_length': img.seek(0, 2), }, ), mock.call( 'https://example.com/api/v1/project/myorg/myproj/mappings/continuous', json={ 'gradient': 'https://example.com/api/my_colormap', 'data_controls': [0., 10., 20., 30.], 'gradient_controls': [0., 0., 1., 1.], 'visibility': [False, True, True, True, False], 'interpolate': False, }, ), mock.call( 'https://example.com/api/v1/project/myorg/myproj/data/basic', json={ 'name': 'Dataset 1', 'location': 'nodes', 'array': 'https://example.com/api/self', 'mappings': [], }, ), mock.call( 'https://example.com/api/v1/project/myorg/myproj/data/basic', json={ 'name': 'Dataset 2', 'description': 'Same array as dataset 1', 'location': 'nodes', 'array': 'https://example.com/api/self', 'mappings': [ 'https://example.com/api/self', 'https://example.com/api/mapping_uploaded', ], }, ), mock.call( 'https://example.com/api/v1/project/myorg/myproj/textures/projection', json={ 'origin': [0., 0, 0], 'axis_u': [1., 0, 0], 'axis_v': [0., 1, 0], 'image': 'https://example.com/api/self', }, ), mock.call( 'https://example.com/api/v1/project/myorg/myproj/elements/pointset', json={ 'vertices': 'https://example.com/api/self', 'data': [ 'https://example.com/api/self', 'https://example.com/api/self', 'https://example.com/api/self', ], 'defaults': { 'visible': True, 'color': { 'value': '#FF0000' }, 'opacity': { 'value': 1 }, 'size': { 'value': 10 }, 'shape': 'square' }, }, ), mock.call( 'https://example.com/api/v1/project/myorg/myproj/views', json={ 'name': 'Test View', 'elements': [ 'https://example.com/api/self', 'https://example.com/api/my_element', ], 'contents': [ 'https://example.com/api/self', 'https://example.com/api/self', 'https://example.com/api/my_colormap', 'https://example.com/api/self', 'https://example.com/api/mapping_uploaded', 'https://example.com/api/self', 'https://example.com/api/self', 'https://example.com/api/self', 'https://example.com/api/self', 'https://example.com/api/self', 'https://example.com/api/my_element', ], }, ), ], any_order=True) mock_patch.assert_called_with( 'https://example.com/api/mapping_uploaded', json={ 'values': ['#FF0000', '#00FF00', '#0000FF'], 'end_points': [10., 20.], 'end_inclusive': [True, True], 'visibility': [True, True, True], }, ) mock_put.assert_called_with( 'https://example.com/api/self/thumbnail', json={ 'content_type': 'image/png', 'content_length': 88, }, )
def test_array_assignment(input_arr): arr = files.Array() with pytest.raises(ValueError): arr.array = input_arr
def test_object_without_array(): arr = files.Array() arr.content_length = 64 arr.dtype = 'Int8Array' arr.shape = [64] assert arr.validate()
def test_is_1d(input, is_1d): assert files.Array(input).is_1d() == is_1d
def test_bad_input(): with pytest.raises(properties.ValidationError): files.Array(dtype='bad') arr = files.Array(dtype='Int32Array', shape=[1]) with pytest.raises(properties.ValidationError): arr.content_length = 100
def test_empty_init(): arr = files.Array() with pytest.raises(properties.ValidationError): arr.validate()
import properties from lfview.resources import files, spatial def test_types(): assert spatial.DataBasic.BASE_TYPE == 'data' assert spatial.DataBasic.SUB_TYPE == 'basic' assert spatial.DataCategory.BASE_TYPE == 'data' assert spatial.DataCategory.SUB_TYPE == 'category' @pytest.mark.parametrize('array', [ 'https://example.com/api/files/array/abc123', [10., 20, 15.], files.Array(shape=[3], dtype='Float32Array', content_length=12), ]) @pytest.mark.parametrize('location', ['nodes', 'cells', 'N', 'CC']) @pytest.mark.parametrize( 'mappings', [[ 'https://example.com/api/mappings/continuous/abc123', 'https://example.com/api/mappings/discrete/def456' ], [{ 'gradient': 'https://example.com/api/files/array/ghi789', 'data_controls': [1., 2., 3., 4.] }, { 'values': ['a', 'b'], 'end_points': [1.], 'end_inclusive': [True], 'visibility': [True, True]
def test_unsupported_array(): with pytest.raises(ValueError): files.Array('bad array') int64array = np.array([100000000000]) with pytest.raises(ValueError): files.Array(int64array)
def test_types(): assert spatial.MappingContinuous.BASE_TYPE == 'mappings' assert spatial.MappingDiscrete.BASE_TYPE == 'mappings' assert spatial.MappingCategory.BASE_TYPE == 'mappings' assert spatial.MappingContinuous.SUB_TYPE == 'continuous' assert spatial.MappingDiscrete.SUB_TYPE == 'discrete' assert spatial.MappingCategory.SUB_TYPE == 'category' @pytest.mark.parametrize( 'gradient', [ 'https://example.com/api/files/array/abc123', [[0, 0, 0], [255, 255, 255]], files.Array(shape=[5, 3], dtype='Int16Array', content_length=30) ] ) @pytest.mark.parametrize('data_controls', [[-1., 2., 3.], [1., 1., 1.]]) @pytest.mark.parametrize('gradient_controls', [[0., 0.5, 1], [0., 0., 0.]]) @pytest.mark.parametrize( 'visibility', [[True, True, True, True], [0, 0, 1, 0]] ) @pytest.mark.parametrize('interpolate', [0, 1]) def test_good_continuous( gradient, data_controls, gradient_controls, visibility, interpolate ): mc = spatial.MappingContinuous( gradient=gradient, data_controls=data_controls, gradient_controls=gradient_controls,
session.upload_feedback(feedback, slide=slide_url, verbose=verbose) if isinstance(feedback, scene.Feedback): mock_upload.assert_called_once_with( resource=feedback, verbose=verbose, chunk_size=None, json_dict=expected_json_dict, post_url=expected_post_url, executor=mock_executor, ) else: mock_upload.assert_called_once() @pytest.mark.parametrize(('feedback', 'slide_url'), [ (files.Array([1., 2.]), 'https://example.com/api/v1/view/org1/proj1/view1/slides/slide1'), (None, None), (None, 'https://example.com/api/v1/view/org1/proj1/view1/slides/slide1/feedback' ), ]) @pytest.mark.parametrize('verbose', [True, False]) def test_bad_upload_feedback(feedback, slide_url, verbose, session): if not feedback: feedback = scene.Feedback(comment='bad') with pytest.raises(ValueError): session.upload_feedback(feedback, slide=slide_url, verbose=verbose) @pytest.fixture