tests.test_events API documentation

# tests.test_events

View Source

      1import os
      2import time
      3
      4import pytest
      5
      6import cv2
      7import numpy as np
      8import pandas as pd
      9
     10from csi_images.csi_scans import Scan
     11from csi_images.csi_tiles import Tile
     12from csi_images.csi_events import Event, EventArray
     13from csi_images import csi_images
     14
     15if os.environ.get("DEBIAN_FRONTEND") == "noninteractive":
     16    SHOW_PLOTS = False
     17else:
     18    # Change this to your preference for local testing, but commit as True
     19    SHOW_PLOTS = True
     20
     21
     22@pytest.fixture
     23def bzscan():
     24    return Scan.load_txt("tests/data")
     25
     26
     27@pytest.fixture
     28def axscan():
     29    return Scan.load_yaml("tests/data")
     30
     31
     32def test_get_crops(bzscan):
     33    tile = Tile(bzscan, 1000)
     34    event = Event(tile, 400, 350)
     35
     36    # Test a regular event
     37    images = event.get_crops()
     38    assert len(images) == 5
     39    images = event.get_crops(crop_size=50)
     40    assert images[0].shape == (50, 50)
     41    images = event.get_crops(crop_size=100)
     42    assert images[0].shape == (100, 100)
     43
     44    if SHOW_PLOTS:
     45        for image in images:
     46            cv2.imshow("Bright DAPI event in the center", image)
     47            cv2.waitKey(0)
     48        cv2.destroyAllWindows()
     49
     50    # Test a corner event
     51    event = Event(tile, 1350, 2)
     52    images = event.get_crops()
     53    assert len(images) == 5
     54    images = event.get_crops(crop_size=200)
     55    assert images[0].shape == (200, 200)
     56    images = event.get_crops(crop_size=100)
     57    assert images[0].shape == (100, 100)
     58
     59    if SHOW_PLOTS:
     60        for image in images:
     61            cv2.imshow("Events in the top-right corner of a tile", image)
     62            cv2.waitKey(0)
     63        cv2.destroyAllWindows()
     64
     65    # Test many events
     66    tile2 = Tile(bzscan, 500)
     67    events = [
     68        Event(tile, 515, 411),
     69        Event(tile2, 2, 1000),
     70        Event(tile, 1000, 1000),
     71        Event(tile, 87, 126),
     72        Event(tile, 1000, 2),
     73        Event(tile2, 800, 800),
     74        Event(tile, 1000, 662),
     75    ]
     76
     77    # Test time to extract images sequentially
     78    start_time = time.time()
     79    images_1 = []
     80    for event in events:
     81        images_1.append(event.get_crops())
     82    sequential_time = time.time() - start_time
     83
     84    # Test time to extract images in parallel
     85    start_time = time.time()
     86    images_2 = Event.get_many_crops(events, crop_size=100)
     87    parallel_time = time.time() - start_time
     88    assert parallel_time < sequential_time
     89    for list_a, list_b in zip(images_1, images_2):
     90        assert len(list_a) == len(list_b)
     91        for image_a, image_b in zip(list_a, list_b):
     92            assert np.array_equal(image_a, image_b)
     93
     94    # Test that it works after converting to EventArray and back
     95    event_array = EventArray.from_events(events)
     96    remade_events = event_array.to_events(
     97        [bzscan], ignore_metadata=True, ignore_features=True
     98    )
     99    images_3 = Event.get_many_crops(remade_events, crop_size=100)
    100    for list_a, list_b in zip(images_1, images_3):
    101        assert len(list_a) == len(list_b)
    102        for image_a, image_b in zip(list_a, list_b):
    103            assert np.array_equal(image_a, image_b)
    104
    105
    106def test_event_coordinates_for_bzscanner(bzscan):
    107    # Origin
    108    tile = Tile(bzscan, 0)
    109    event = Event(tile, 0, 0)
    110    scan_origin = event.get_scan_position()
    111    assert 2500 <= scan_origin[0] <= 3500
    112    assert 2500 <= scan_origin[1] <= 3500
    113    scan_origin_on_slide = event.get_slide_position()
    114    assert 71500 <= scan_origin_on_slide[0] <= 72500
    115    assert 21500 <= scan_origin_on_slide[1] <= 22500
    116    # Within the same tile, "top-right corner"
    117    event = Event(tile, 1000, 0)
    118    scan_position = event.get_scan_position()
    119    assert scan_origin[0] < scan_position[0]
    120    assert scan_origin[1] == scan_position[1]
    121    slide_position = event.get_slide_position()
    122    assert scan_origin_on_slide[0] == slide_position[0]
    123    assert scan_origin_on_slide[1] > slide_position[1]
    124    # Within the same tile, "bottom-left corner"
    125    event = Event(tile, 0, 1000)
    126    scan_position = event.get_scan_position()
    127    assert scan_origin[0] == scan_position[0]
    128    assert scan_origin[1] < scan_position[1]
    129    slide_position = event.get_slide_position()
    130    assert scan_origin_on_slide[0] > slide_position[0]
    131    assert scan_origin_on_slide[1] == slide_position[1]
    132
    133    # Next row, opposite side
    134    tile = Tile(bzscan, (bzscan.roi[0].tile_cols - 1, 1))
    135    event = Event(tile, 1000, 1000)
    136    scan_position = event.get_scan_position()
    137    assert scan_origin[0] <= scan_position[0]
    138    assert scan_origin[1] <= scan_position[1]
    139    slide_position = event.get_slide_position()
    140    assert slide_position[0] <= scan_origin_on_slide[0]
    141    assert slide_position[1] <= scan_origin_on_slide[1]
    142
    143    # Opposite corner
    144    tile = Tile(bzscan, (bzscan.roi[0].tile_cols - 1, bzscan.roi[0].tile_rows - 1))
    145    event = Event(tile, 1361, 1003)
    146    scan_position = event.get_scan_position()
    147    assert 21500 <= scan_position[0] <= 22500
    148    assert 58500 <= scan_position[1] <= 60500
    149    slide_position = event.get_slide_position()
    150    assert 14500 <= slide_position[0] <= 15500
    151    assert 2500 <= slide_position[1] <= 3500
    152
    153
    154def test_event_coordinates_for_axioscan(axscan):
    155    # Origin
    156    tile = Tile(axscan, 0)
    157    event = Event(tile, 0, 0)
    158    scan_position = event.get_scan_position()
    159    assert -59000 <= scan_position[0] < -55000
    160    assert 0 <= scan_position[1] < 4000
    161    slide_position = event.get_slide_position()
    162    assert 16000 <= slide_position[0] < 20000
    163    assert scan_position[1] == slide_position[1]
    164
    165    # Opposite corner
    166    tile = Tile(axscan, (axscan.roi[0].tile_cols - 1, axscan.roi[0].tile_rows - 1))
    167    event = Event(tile, 2000, 2000)
    168    scan_position = event.get_scan_position()
    169    assert -4000 <= scan_position[0] <= 0
    170    assert 21000 <= scan_position[1] <= 25000
    171    slide_position = event.get_slide_position()
    172    assert 71000 <= slide_position[0] <= 75000
    173    assert scan_position[1] == slide_position[1]
    174
    175
    176def test_eventarray_conversions(axscan):
    177    # Origin
    178    tile = Tile(axscan, 0)
    179    event0 = Event(tile, 0, 0)
    180    event1 = Event(tile, 1000, 1000)
    181    event2 = Event(tile, 2000, 2000)
    182
    183    event_array = EventArray.from_events([event0, event1, event2])
    184
    185    assert len(event_array) == 3
    186    assert event_array.metadata is None
    187    assert event_array.features is None
    188
    189    event0.metadata = pd.Series({"event0": 0})
    190
    191    try:
    192        event_array = EventArray.from_events([event0, event1, event2])
    193        # Should throw error
    194        assert False
    195    except ValueError:
    196        pass
    197
    198    event1.metadata = pd.Series({"event0": 1})
    199    event2.metadata = pd.Series({"event0": 2})
    200
    201    event_array = EventArray.from_events([event0, event1, event2])
    202
    203    assert len(event_array) == 3
    204
    205    events_df = event_array.to_dataframe()
    206
    207    assert len(events_df) == 3
    208
    209    assert event_array == EventArray.from_dataframe(events_df)
    210
    211    # Test adding different dtypes and converting back and forth
    212    event_array.features = pd.DataFrame(
    213        {"feature1": [1, 2, 3], "feature2": [4.0, 5.0, 6.0]}
    214    )
    215    remade_event_list = event_array.to_events([axscan])
    216    assert len(remade_event_list) == 3
    217    remade_event_array = EventArray.from_events(remade_event_list)
    218    assert event_array == remade_event_array
    219    # Test saving and loading
    220    assert event_array.save_csv("tests/data/events.csv")
    221    assert event_array == EventArray.load_csv("tests/data/events.csv")
    222    os.remove("tests/data/events.csv")
    223
    224    assert event_array.save_hdf5("tests/data/events.h5")
    225    assert event_array == EventArray.load_hdf5("tests/data/events.h5")
    226    os.remove("tests/data/events.h5")
    227
    228
    229# @pytest.mark.skip(reason="No longer required.")
    230def test_ocular_conversions():
    231    input_path = "/mnt/HDSCA_Development/DZ/0B68818/ocular"
    232    result = EventArray.load_ocular(input_path)
    233    # For the purposes of this test, we will manually relabel "clust" == nan to 0
    234    # These come from ocular_interesting.rds, which does not have clusters
    235    result.metadata["clust"] = result.metadata["clust"].fillna(0)
    236    result.metadata["hcpc"] = result.metadata["hcpc"].fillna(0)
    237    result.save_ocular("tests/data")
    238    new_result = EventArray.load_ocular("tests/data")
    239    # # Sort them so that they are in the same order
    240    result = result.sort(["tile", "x", "y"])
    241    new_result = new_result.sort(["tile", "x", "y"])
    242    # Note: hcpc method within ocularr and here are different
    243    result.metadata["hcpc"] = new_result.metadata["hcpc"].copy()
    244    assert result == new_result
    245    # Clean up
    246    os.remove("tests/data/rc-final.csv")
    247    os.remove("tests/data/rc-final.rds")
    248    os.remove("tests/data/rc-final1.rds")
    249    os.remove("tests/data/rc-final2.rds")
    250    os.remove("tests/data/rc-final3.rds")
    251    os.remove("tests/data/rc-final4.rds")
    252
    253    # Try it with "others" files
    254    result = EventArray.load_ocular(input_path, event_type="others")
    255    result.save_ocular("tests/data", event_type="others")
    256    new_result = EventArray.load_ocular("tests/data", event_type="others")
    257    result = result.sort(["tile", "x", "y"])
    258    new_result = new_result.sort(["tile", "x", "y"])
    259    # Note: hcpc method within ocularr and here are different
    260    result.metadata["hcpc"] = new_result.metadata["hcpc"].copy()
    261    assert result == new_result
    262    # Clean up
    263    os.remove("tests/data/others-final.csv")
    264    os.remove("tests/data/others-final.rds")
    265    os.remove("tests/data/others-final1.rds")
    266    os.remove("tests/data/others-final2.rds")
    267    os.remove("tests/data/others-final3.rds")
    268    os.remove("tests/data/others-final4.rds")
    269
    270
    271def test_copy_sort_rows_get(axscan):
    272    # Origin
    273    tile = Tile(axscan, 0)
    274    events = [
    275        Event(tile, 0, 100),
    276        Event(tile, 0, 0),
    277        Event(tile, 1000, 1000),
    278        Event(tile, 1000, 1),
    279        Event(tile, 2000, 2000),
    280    ]
    281
    282    events = EventArray.from_events(events)
    283
    284    # Copy
    285    events_copy = events.copy()
    286    events_copy.info["x"] = np.uint16(1)
    287    # Check that changes to the copy did not change the original
    288    assert events_copy.info["x"].equals(pd.Series([1, 1, 1, 1, 1], dtype=np.uint16))
    289    assert events.info["x"].equals(pd.Series([0, 0, 1000, 1000, 2000], dtype=np.uint16))
    290
    291    # Sort
    292    events = events.sort(["x", "y"], ascending=[False, True])
    293    assert events.info["x"].equals(pd.Series([2000, 1000, 1000, 0, 0], dtype=np.uint16))
    294    assert events.info["y"].equals(pd.Series([2000, 1, 1000, 0, 100], dtype=np.uint16))
    295
    296    # Get
    297    events_get = events.get(["x", "y"])
    298    assert events_get["x"].equals(pd.Series([2000, 1000, 1000, 0, 0], dtype=np.uint16))
    299    assert events_get["y"].equals(pd.Series([2000, 1, 1000, 0, 100], dtype=np.uint16))
    300    assert events_get.columns.equals(pd.Index(["x", "y"]))
    301
    302    # Rows
    303    events_get = events.rows([0, 1, 3])
    304    assert len(events_get) == 3
    305    assert events_get.info["x"].equals(pd.Series([2000, 1000, 0], dtype=np.uint16))
    306    assert events_get.info["y"].equals(pd.Series([2000, 1, 0], dtype=np.uint16))
    307    events_get = events.rows([True, False, False, True, True])
    308    assert len(events_get) == 3
    309    assert events_get.info["x"].equals(pd.Series([2000, 0, 0], dtype=np.uint16))
    310    assert events_get.info["y"].equals(pd.Series([2000, 0, 100], dtype=np.uint16))
    311
    312
    313def test_event_montages(bzscan):
    314    tile = Tile(bzscan, 1000)
    315    event = Event(tile, 515, 411)
    316    images = event.get_crops(crop_size=100)
    317
    318    montage = csi_images.make_montage(
    319        images,
    320        [0, 1, 4, 2],
    321        {0: (0, 0, 1), 1: (1, 0, 0), 2: (0, 1, 0), 4: (1, 1, 1)},
    322        labels=["RGB", "DAPI", "AF555", "AF488", "AF647"],
    323    )
    324    if SHOW_PLOTS:
    325        cv2.imshow(
    326            "Full, classic montage with labels",
    327            cv2.cvtColor(montage, cv2.COLOR_RGB2BGR),
    328        )
    329        cv2.waitKey(0)
    330        cv2.destroyAllWindows()
    331
    332
    333def test_saving_crops_and_montages(bzscan):
    334    tile = Tile(bzscan, 1000)
    335    tile2 = Tile(bzscan, 0)
    336    events = [
    337        Event(tile, 515, 411),
    338        Event(tile2, 2, 1000),
    339        Event(tile, 1000, 1000),
    340        Event(tile2, 800, 800),
    341        Event(tile, 1000, 662),
    342    ]
    343
    344    # Get all crops and montages
    345    serial_crops = []
    346    serial_montages = []
    347    for event in events:
    348        serial_crops.append(event.get_crops())
    349        serial_montages.append(event.get_montage())
    350
    351    # Save crops and montages
    352    Event.get_and_save_many_crops(events, "temp", bzscan.get_channel_names())
    353    Event.get_and_save_many_montages(events, "temp")
    354
    355    saved_crops = []
    356    saved_montages = []
    357    for event in events:
    358        crops = event.load_crops("temp")
    359        saved_crops.append([crops[c] for c in bzscan.get_channel_names()])
    360        saved_montages.append(event.load_montage("temp"))
    361
    362    # Make sure crops are identical
    363    for a, b in zip(serial_crops, saved_crops):
    364        for a_img, b_img in zip(a, b):
    365            assert np.array_equal(a_img, b_img)
    366
    367    # Montages got JPEG compressed, so
    368    # Size comparison:
    369    for a, b in zip(serial_montages, saved_montages):
    370        assert a.shape == b.shape
    371
    372    # Visual inspection
    373    if SHOW_PLOTS:
    374        cv2.imshow("Original", cv2.cvtColor(serial_montages[0], cv2.COLOR_RGB2BGR))
    375        cv2.imshow("Saved", cv2.cvtColor(saved_montages[0], cv2.COLOR_RGB2BGR))
    376        cv2.waitKey(0)
    377        cv2.destroyAllWindows()
    378
    379    # Clean up
    380    for file in os.listdir("temp"):
    381        os.remove(os.path.join("temp", file))
    382    os.rmdir("temp")

@pytest.fixture
def bzscan(): View Source

    23@pytest.fixture
    24def bzscan():
    25    return Scan.load_txt("tests/data")

@pytest.fixture
def axscan(): View Source

    28@pytest.fixture
    29def axscan():
    30    return Scan.load_yaml("tests/data")

def test_get_crops(bzscan): View Source

     33def test_get_crops(bzscan):
     34    tile = Tile(bzscan, 1000)
     35    event = Event(tile, 400, 350)
     36
     37    # Test a regular event
     38    images = event.get_crops()
     39    assert len(images) == 5
     40    images = event.get_crops(crop_size=50)
     41    assert images[0].shape == (50, 50)
     42    images = event.get_crops(crop_size=100)
     43    assert images[0].shape == (100, 100)
     44
     45    if SHOW_PLOTS:
     46        for image in images:
     47            cv2.imshow("Bright DAPI event in the center", image)
     48            cv2.waitKey(0)
     49        cv2.destroyAllWindows()
     50
     51    # Test a corner event
     52    event = Event(tile, 1350, 2)
     53    images = event.get_crops()
     54    assert len(images) == 5
     55    images = event.get_crops(crop_size=200)
     56    assert images[0].shape == (200, 200)
     57    images = event.get_crops(crop_size=100)
     58    assert images[0].shape == (100, 100)
     59
     60    if SHOW_PLOTS:
     61        for image in images:
     62            cv2.imshow("Events in the top-right corner of a tile", image)
     63            cv2.waitKey(0)
     64        cv2.destroyAllWindows()
     65
     66    # Test many events
     67    tile2 = Tile(bzscan, 500)
     68    events = [
     69        Event(tile, 515, 411),
     70        Event(tile2, 2, 1000),
     71        Event(tile, 1000, 1000),
     72        Event(tile, 87, 126),
     73        Event(tile, 1000, 2),
     74        Event(tile2, 800, 800),
     75        Event(tile, 1000, 662),
     76    ]
     77
     78    # Test time to extract images sequentially
     79    start_time = time.time()
     80    images_1 = []
     81    for event in events:
     82        images_1.append(event.get_crops())
     83    sequential_time = time.time() - start_time
     84
     85    # Test time to extract images in parallel
     86    start_time = time.time()
     87    images_2 = Event.get_many_crops(events, crop_size=100)
     88    parallel_time = time.time() - start_time
     89    assert parallel_time < sequential_time
     90    for list_a, list_b in zip(images_1, images_2):
     91        assert len(list_a) == len(list_b)
     92        for image_a, image_b in zip(list_a, list_b):
     93            assert np.array_equal(image_a, image_b)
     94
     95    # Test that it works after converting to EventArray and back
     96    event_array = EventArray.from_events(events)
     97    remade_events = event_array.to_events(
     98        [bzscan], ignore_metadata=True, ignore_features=True
     99    )
    100    images_3 = Event.get_many_crops(remade_events, crop_size=100)
    101    for list_a, list_b in zip(images_1, images_3):
    102        assert len(list_a) == len(list_b)
    103        for image_a, image_b in zip(list_a, list_b):
    104            assert np.array_equal(image_a, image_b)

def test_event_coordinates_for_bzscanner(bzscan): View Source

    107def test_event_coordinates_for_bzscanner(bzscan):
    108    # Origin
    109    tile = Tile(bzscan, 0)
    110    event = Event(tile, 0, 0)
    111    scan_origin = event.get_scan_position()
    112    assert 2500 <= scan_origin[0] <= 3500
    113    assert 2500 <= scan_origin[1] <= 3500
    114    scan_origin_on_slide = event.get_slide_position()
    115    assert 71500 <= scan_origin_on_slide[0] <= 72500
    116    assert 21500 <= scan_origin_on_slide[1] <= 22500
    117    # Within the same tile, "top-right corner"
    118    event = Event(tile, 1000, 0)
    119    scan_position = event.get_scan_position()
    120    assert scan_origin[0] < scan_position[0]
    121    assert scan_origin[1] == scan_position[1]
    122    slide_position = event.get_slide_position()
    123    assert scan_origin_on_slide[0] == slide_position[0]
    124    assert scan_origin_on_slide[1] > slide_position[1]
    125    # Within the same tile, "bottom-left corner"
    126    event = Event(tile, 0, 1000)
    127    scan_position = event.get_scan_position()
    128    assert scan_origin[0] == scan_position[0]
    129    assert scan_origin[1] < scan_position[1]
    130    slide_position = event.get_slide_position()
    131    assert scan_origin_on_slide[0] > slide_position[0]
    132    assert scan_origin_on_slide[1] == slide_position[1]
    133
    134    # Next row, opposite side
    135    tile = Tile(bzscan, (bzscan.roi[0].tile_cols - 1, 1))
    136    event = Event(tile, 1000, 1000)
    137    scan_position = event.get_scan_position()
    138    assert scan_origin[0] <= scan_position[0]
    139    assert scan_origin[1] <= scan_position[1]
    140    slide_position = event.get_slide_position()
    141    assert slide_position[0] <= scan_origin_on_slide[0]
    142    assert slide_position[1] <= scan_origin_on_slide[1]
    143
    144    # Opposite corner
    145    tile = Tile(bzscan, (bzscan.roi[0].tile_cols - 1, bzscan.roi[0].tile_rows - 1))
    146    event = Event(tile, 1361, 1003)
    147    scan_position = event.get_scan_position()
    148    assert 21500 <= scan_position[0] <= 22500
    149    assert 58500 <= scan_position[1] <= 60500
    150    slide_position = event.get_slide_position()
    151    assert 14500 <= slide_position[0] <= 15500
    152    assert 2500 <= slide_position[1] <= 3500

def test_event_coordinates_for_axioscan(axscan): View Source

    155def test_event_coordinates_for_axioscan(axscan):
    156    # Origin
    157    tile = Tile(axscan, 0)
    158    event = Event(tile, 0, 0)
    159    scan_position = event.get_scan_position()
    160    assert -59000 <= scan_position[0] < -55000
    161    assert 0 <= scan_position[1] < 4000
    162    slide_position = event.get_slide_position()
    163    assert 16000 <= slide_position[0] < 20000
    164    assert scan_position[1] == slide_position[1]
    165
    166    # Opposite corner
    167    tile = Tile(axscan, (axscan.roi[0].tile_cols - 1, axscan.roi[0].tile_rows - 1))
    168    event = Event(tile, 2000, 2000)
    169    scan_position = event.get_scan_position()
    170    assert -4000 <= scan_position[0] <= 0
    171    assert 21000 <= scan_position[1] <= 25000
    172    slide_position = event.get_slide_position()
    173    assert 71000 <= slide_position[0] <= 75000
    174    assert scan_position[1] == slide_position[1]

def test_eventarray_conversions(axscan): View Source

    177def test_eventarray_conversions(axscan):
    178    # Origin
    179    tile = Tile(axscan, 0)
    180    event0 = Event(tile, 0, 0)
    181    event1 = Event(tile, 1000, 1000)
    182    event2 = Event(tile, 2000, 2000)
    183
    184    event_array = EventArray.from_events([event0, event1, event2])
    185
    186    assert len(event_array) == 3
    187    assert event_array.metadata is None
    188    assert event_array.features is None
    189
    190    event0.metadata = pd.Series({"event0": 0})
    191
    192    try:
    193        event_array = EventArray.from_events([event0, event1, event2])
    194        # Should throw error
    195        assert False
    196    except ValueError:
    197        pass
    198
    199    event1.metadata = pd.Series({"event0": 1})
    200    event2.metadata = pd.Series({"event0": 2})
    201
    202    event_array = EventArray.from_events([event0, event1, event2])
    203
    204    assert len(event_array) == 3
    205
    206    events_df = event_array.to_dataframe()
    207
    208    assert len(events_df) == 3
    209
    210    assert event_array == EventArray.from_dataframe(events_df)
    211
    212    # Test adding different dtypes and converting back and forth
    213    event_array.features = pd.DataFrame(
    214        {"feature1": [1, 2, 3], "feature2": [4.0, 5.0, 6.0]}
    215    )
    216    remade_event_list = event_array.to_events([axscan])
    217    assert len(remade_event_list) == 3
    218    remade_event_array = EventArray.from_events(remade_event_list)
    219    assert event_array == remade_event_array
    220    # Test saving and loading
    221    assert event_array.save_csv("tests/data/events.csv")
    222    assert event_array == EventArray.load_csv("tests/data/events.csv")
    223    os.remove("tests/data/events.csv")
    224
    225    assert event_array.save_hdf5("tests/data/events.h5")
    226    assert event_array == EventArray.load_hdf5("tests/data/events.h5")
    227    os.remove("tests/data/events.h5")

def test_ocular_conversions(): View Source

    231def test_ocular_conversions():
    232    input_path = "/mnt/HDSCA_Development/DZ/0B68818/ocular"
    233    result = EventArray.load_ocular(input_path)
    234    # For the purposes of this test, we will manually relabel "clust" == nan to 0
    235    # These come from ocular_interesting.rds, which does not have clusters
    236    result.metadata["clust"] = result.metadata["clust"].fillna(0)
    237    result.metadata["hcpc"] = result.metadata["hcpc"].fillna(0)
    238    result.save_ocular("tests/data")
    239    new_result = EventArray.load_ocular("tests/data")
    240    # # Sort them so that they are in the same order
    241    result = result.sort(["tile", "x", "y"])
    242    new_result = new_result.sort(["tile", "x", "y"])
    243    # Note: hcpc method within ocularr and here are different
    244    result.metadata["hcpc"] = new_result.metadata["hcpc"].copy()
    245    assert result == new_result
    246    # Clean up
    247    os.remove("tests/data/rc-final.csv")
    248    os.remove("tests/data/rc-final.rds")
    249    os.remove("tests/data/rc-final1.rds")
    250    os.remove("tests/data/rc-final2.rds")
    251    os.remove("tests/data/rc-final3.rds")
    252    os.remove("tests/data/rc-final4.rds")
    253
    254    # Try it with "others" files
    255    result = EventArray.load_ocular(input_path, event_type="others")
    256    result.save_ocular("tests/data", event_type="others")
    257    new_result = EventArray.load_ocular("tests/data", event_type="others")
    258    result = result.sort(["tile", "x", "y"])
    259    new_result = new_result.sort(["tile", "x", "y"])
    260    # Note: hcpc method within ocularr and here are different
    261    result.metadata["hcpc"] = new_result.metadata["hcpc"].copy()
    262    assert result == new_result
    263    # Clean up
    264    os.remove("tests/data/others-final.csv")
    265    os.remove("tests/data/others-final.rds")
    266    os.remove("tests/data/others-final1.rds")
    267    os.remove("tests/data/others-final2.rds")
    268    os.remove("tests/data/others-final3.rds")
    269    os.remove("tests/data/others-final4.rds")

def test_copy_sort_rows_get(axscan): View Source

    272def test_copy_sort_rows_get(axscan):
    273    # Origin
    274    tile = Tile(axscan, 0)
    275    events = [
    276        Event(tile, 0, 100),
    277        Event(tile, 0, 0),
    278        Event(tile, 1000, 1000),
    279        Event(tile, 1000, 1),
    280        Event(tile, 2000, 2000),
    281    ]
    282
    283    events = EventArray.from_events(events)
    284
    285    # Copy
    286    events_copy = events.copy()
    287    events_copy.info["x"] = np.uint16(1)
    288    # Check that changes to the copy did not change the original
    289    assert events_copy.info["x"].equals(pd.Series([1, 1, 1, 1, 1], dtype=np.uint16))
    290    assert events.info["x"].equals(pd.Series([0, 0, 1000, 1000, 2000], dtype=np.uint16))
    291
    292    # Sort
    293    events = events.sort(["x", "y"], ascending=[False, True])
    294    assert events.info["x"].equals(pd.Series([2000, 1000, 1000, 0, 0], dtype=np.uint16))
    295    assert events.info["y"].equals(pd.Series([2000, 1, 1000, 0, 100], dtype=np.uint16))
    296
    297    # Get
    298    events_get = events.get(["x", "y"])
    299    assert events_get["x"].equals(pd.Series([2000, 1000, 1000, 0, 0], dtype=np.uint16))
    300    assert events_get["y"].equals(pd.Series([2000, 1, 1000, 0, 100], dtype=np.uint16))
    301    assert events_get.columns.equals(pd.Index(["x", "y"]))
    302
    303    # Rows
    304    events_get = events.rows([0, 1, 3])
    305    assert len(events_get) == 3
    306    assert events_get.info["x"].equals(pd.Series([2000, 1000, 0], dtype=np.uint16))
    307    assert events_get.info["y"].equals(pd.Series([2000, 1, 0], dtype=np.uint16))
    308    events_get = events.rows([True, False, False, True, True])
    309    assert len(events_get) == 3
    310    assert events_get.info["x"].equals(pd.Series([2000, 0, 0], dtype=np.uint16))
    311    assert events_get.info["y"].equals(pd.Series([2000, 0, 100], dtype=np.uint16))

def test_event_montages(bzscan): View Source

    314def test_event_montages(bzscan):
    315    tile = Tile(bzscan, 1000)
    316    event = Event(tile, 515, 411)
    317    images = event.get_crops(crop_size=100)
    318
    319    montage = csi_images.make_montage(
    320        images,
    321        [0, 1, 4, 2],
    322        {0: (0, 0, 1), 1: (1, 0, 0), 2: (0, 1, 0), 4: (1, 1, 1)},
    323        labels=["RGB", "DAPI", "AF555", "AF488", "AF647"],
    324    )
    325    if SHOW_PLOTS:
    326        cv2.imshow(
    327            "Full, classic montage with labels",
    328            cv2.cvtColor(montage, cv2.COLOR_RGB2BGR),
    329        )
    330        cv2.waitKey(0)
    331        cv2.destroyAllWindows()

def test_saving_crops_and_montages(bzscan): View Source

    334def test_saving_crops_and_montages(bzscan):
    335    tile = Tile(bzscan, 1000)
    336    tile2 = Tile(bzscan, 0)
    337    events = [
    338        Event(tile, 515, 411),
    339        Event(tile2, 2, 1000),
    340        Event(tile, 1000, 1000),
    341        Event(tile2, 800, 800),
    342        Event(tile, 1000, 662),
    343    ]
    344
    345    # Get all crops and montages
    346    serial_crops = []
    347    serial_montages = []
    348    for event in events:
    349        serial_crops.append(event.get_crops())
    350        serial_montages.append(event.get_montage())
    351
    352    # Save crops and montages
    353    Event.get_and_save_many_crops(events, "temp", bzscan.get_channel_names())
    354    Event.get_and_save_many_montages(events, "temp")
    355
    356    saved_crops = []
    357    saved_montages = []
    358    for event in events:
    359        crops = event.load_crops("temp")
    360        saved_crops.append([crops[c] for c in bzscan.get_channel_names()])
    361        saved_montages.append(event.load_montage("temp"))
    362
    363    # Make sure crops are identical
    364    for a, b in zip(serial_crops, saved_crops):
    365        for a_img, b_img in zip(a, b):
    366            assert np.array_equal(a_img, b_img)
    367
    368    # Montages got JPEG compressed, so
    369    # Size comparison:
    370    for a, b in zip(serial_montages, saved_montages):
    371        assert a.shape == b.shape
    372
    373    # Visual inspection
    374    if SHOW_PLOTS:
    375        cv2.imshow("Original", cv2.cvtColor(serial_montages[0], cv2.COLOR_RGB2BGR))
    376        cv2.imshow("Saved", cv2.cvtColor(saved_montages[0], cv2.COLOR_RGB2BGR))
    377        cv2.waitKey(0)
    378        cv2.destroyAllWindows()
    379
    380    # Clean up
    381    for file in os.listdir("temp"):
    382        os.remove(os.path.join("temp", file))
    383    os.rmdir("temp")