def create_intensity_table_with_coords(area: Area, n_spots: int = 10) -> IntensityTable: """ Creates a 50X50 intensity table with physical coordinates within the given Area. Parameters ---------- area: Area The area of physical space the IntensityTable should be defined over n_spots: Number of spots to add to the IntensityTable """ codebook = codebook_array_factory() it = IntensityTable.synthetic_intensities(codebook, num_z=1, height=50, width=50, n_spots=n_spots) # intensity table 1 has 10 spots, xmin = 0, ymin = 0, xmax = 2, ymax = 1 it[Coordinates.X.value] = xr.DataArray(np.linspace(area.min_x, area.max_x, n_spots), dims=Features.AXIS) it[Coordinates.Y.value] = xr.DataArray(np.linspace(area.min_y, area.max_y, n_spots), dims=Features.AXIS) return it
def test_tranfering_physical_coords_to_intensity_table(): stack_shape = OrderedDict([(Axes.ROUND, 3), (Axes.CH, 2), (Axes.ZPLANE, 1), (Axes.Y, 50), (Axes.X, 40)]) physical_coords = OrderedDict([(PhysicalCoordinateTypes.X_MIN, 1), (PhysicalCoordinateTypes.X_MAX, 2), (PhysicalCoordinateTypes.Y_MIN, 4), (PhysicalCoordinateTypes.Y_MAX, 6), (PhysicalCoordinateTypes.Z_MIN, 1), (PhysicalCoordinateTypes.Z_MAX, 3)]) stack = imagestack_with_coords_factory(stack_shape, physical_coords) codebook = codebook_array_factory() intensities = IntensityTable.synthetic_intensities( codebook, num_z=stack_shape[Axes.ZPLANE], height=stack_shape[Axes.Y], width=stack_shape[Axes.X], n_spots=NUMBER_SPOTS) intensities = transfer_physical_coords_to_intensity_table( intensity_table=intensities, image_stack=stack) # Assert that new cords were added xc = intensities.coords[Coordinates.X] yc = intensities.coords[Coordinates.Y] zc = intensities.coords[Coordinates.Z] assert xc.size == NUMBER_SPOTS assert yc.size == NUMBER_SPOTS assert zc.size == NUMBER_SPOTS # Assert that the physical coords align with their corresponding pixel coords for spot in xc.features: pixel_x = spot[Axes.X.value].data pixel_x_floor, pixel_x_ceiling = math.floor(pixel_x), math.ceil( pixel_x) physical_x_floor = stack.xarray[Coordinates.X.value][pixel_x_floor] physical_x_ceiling = stack.xarray[Coordinates.X.value][pixel_x_ceiling] assert physical_x_floor <= spot[ Coordinates.X.value] <= physical_x_ceiling for spot in yc.features: pixel_y = spot[Axes.Y.value].data pixel_y_floor, pixel_y_ceiling = math.floor(pixel_y), math.ceil( pixel_y) physical_y_floor = stack.xarray[Coordinates.Y.value][pixel_y_floor] physical_y_ceiling = stack.xarray[Coordinates.Y.value][pixel_y_ceiling] assert physical_y_floor <= spot[ Coordinates.Y.value] <= physical_y_ceiling # Assert that zc value is middle of z range for spot in zc.features: z_plane = spot[Axes.ZPLANE.value].data physical_z = stack.xarray[Coordinates.Z.value][z_plane] assert np.isclose(spot[Coordinates.Z.value], physical_z)
def test_save_expression_matrix(): codebook = codebook_array_factory() decoded_intensities = factories.synthetic_decoded_intensity_table( codebook, num_z=3, height=100, width=100, n_spots=10) # mock out come cell_ids cell_ids = random.sample(range(1, 20), NUMBER_SPOTS) decoded_intensities[Features.CELL_ID] = (Features.AXIS, cell_ids) expression_matrix = decoded_intensities.to_expression_matrix() # test all saving methods expression_matrix.save("expression")
def test_tranfering_physical_coords_to_expression_matrix(): stack_shape = OrderedDict([(Axes.ROUND, 3), (Axes.CH, 2), (Axes.ZPLANE, 1), (Axes.Y, 50), (Axes.X, 40)]) physical_coords = OrderedDict([(PhysicalCoordinateTypes.X_MIN, 1), (PhysicalCoordinateTypes.X_MAX, 2), (PhysicalCoordinateTypes.Y_MIN, 4), (PhysicalCoordinateTypes.Y_MAX, 6), (PhysicalCoordinateTypes.Z_MIN, 1), (PhysicalCoordinateTypes.Z_MAX, 3)]) stack = imagestack_with_coords_factory(stack_shape, physical_coords) codebook = codebook_array_factory() decoded_intensities = synthetic_decoded_intensity_table( codebook, num_z=stack_shape[Axes.ZPLANE], height=stack_shape[Axes.Y], width=stack_shape[Axes.X], n_spots=NUMBER_SPOTS) intensities = transfer_physical_coords_to_intensity_table( image_stack=stack, intensity_table=decoded_intensities) # Check that error is thrown before target assignment try: decoded_intensities.to_expression_matrix() except KeyError as e: # Assert value error is thrown with right message assert e.args[0] == "IntensityTable must have 'cell_id' assignments for each cell before " \ "this function can be called. See starfish.spots.AssignTargets.Label." # mock out come cell_ids cell_ids = random.sample(range(1, 20), NUMBER_SPOTS) decoded_intensities[Features.CELL_ID] = (Features.AXIS, cell_ids) expression_matrix = intensities.to_expression_matrix() # Assert that coords were transferred xc = expression_matrix.coords[Coordinates.X] yc = expression_matrix.coords[Coordinates.Y] zc = expression_matrix.coords[Coordinates.Z] assert xc.size == len(set(cell_ids)) assert yc.size == len(set(cell_ids)) assert zc.size == len(set(cell_ids))
def dummy_intensities() -> IntensityTable: codebook = codebook_array_factory() intensities = factories.synthetic_decoded_intensity_table( codebook, num_z=10, height=10, width=10, n_spots=5, ) intensities[Coordinates.Z.value] = (Features.AXIS, [0, 1, 0, 1, 0]) intensities[Coordinates.Y.value] = (Features.AXIS, [10, 30, 50, 40, 20]) intensities[Coordinates.X.value] = (Features.AXIS, [50.2, 30.2, 60.2, 40.2, 70.2]) # remove target from dummy to test error messages del intensities[Features.TARGET] return intensities
def test_synthetic_intensity_generation(): """ Create a 2-spot IntensityTable of pixel size (z=3, y=4, x=5) from a codebook with 3 channels and 2 rounds. Verify that the constructed Synthetic IntensityTable conforms to those dimensions, and given a known random seed, that the output spots decode to match a target in the input Codebook """ # set seed to check that codebook is matched. This seed generates 2 instances of GENE_B np.random.seed(2) codebook = codebook_array_factory() num_z, height, width = 3, 4, 5 intensities = IntensityTable.synthetic_intensities( codebook, num_z=num_z, height=height, width=width, n_spots=2, ) # sizes should match codebook assert intensities.sizes[Axes.ROUND] == 2 assert intensities.sizes[Axes.CH] == 3 assert intensities.sizes[Features.AXIS] == 2 # attributes should be bounded by the specified size assert np.all(intensities[Axes.ZPLANE.value] <= num_z) assert np.all(intensities[Axes.Y.value] <= height) assert np.all(intensities[Axes.X.value] <= width) # both codes should match GENE_B assert np.array_equal( np.where(intensities.values), [ [0, 0, 1, 1], # two each in feature 0 & 1 [1, 2, 1, 2], # one each in channel 1 & 2 [1, 0, 1, 0] ], # channel 1 matches round 1, channel 2 matches round zero )
def test_synthetic_intensity_generation(): """ Create a 2-spot IntensityTable of pixel size (z=3, y=4, x=5) from a codebook with 3 channels and 2 rounds. Verify that the constructed Synthetic IntensityTable conforms to those dimensions, and given a known random seed, that the output spots decode to match a target in the input Codebook """ # set seed to check that codebook is matched. This seed generates 2 instances of GENE_B np.random.seed(2) codebook = codebook_array_factory() num_z, height, width = 3, 4, 5 intensities = IntensityTable.synthetic_intensities( codebook, num_z=num_z, height=height, width=width, n_spots=2, ) # sizes should match codebook assert intensities.sizes[Axes.ROUND] == 2 assert intensities.sizes[Axes.CH] == 3 assert intensities.sizes[Features.AXIS] == 2 # attributes should be bounded by the specified size assert np.all(intensities[Axes.ZPLANE.value] <= num_z) assert np.all(intensities[Axes.Y.value] <= height) assert np.all(intensities[Axes.X.value] <= width) # both codes should match GENE_B gene_b_intensities = codebook.sel(target="GENE_B") for feature_id in range(intensities.sizes[Features.AXIS]): feature_intensities = intensities[{Features.AXIS: feature_id}] assert np.array_equal(gene_b_intensities.values, feature_intensities.values)