tests.test_events API documentation

# tests.test_events

View Source

      1import os
      2import time
      3
      4import cv2
      5import numpy as np
      6import pandas as pd
      7
      8from csi_images import csi_events, csi_tiles, csi_scans
      9
     10
     11if os.environ.get("DEBIAN_FRONTEND") == "noninteractive":
     12    SHOW_PLOTS = False
     13else:
     14    # Change this to your preference for local testing, but commit as True
     15    SHOW_PLOTS = True
     16
     17
     18def test_getting_event():
     19    scan = csi_scans.Scan.load_txt("tests/data")
     20    tile = csi_tiles.Tile(scan, 1000)
     21    event = csi_events.Event(
     22        scan,
     23        tile,
     24        515,
     25        411,
     26    )
     27    images = event.extract_images()
     28    assert len(images) == 4
     29    images = event.extract_images(crop_size=100, in_pixels=True)
     30    assert images[0].shape == (100, 100)
     31    images = event.extract_images(crop_size=50, in_pixels=True)
     32    assert images[0].shape == (50, 50)
     33
     34    if SHOW_PLOTS:
     35        for image in images:
     36            cv2.imshow("Bright DAPI event in the center", image)
     37            cv2.waitKey(0)
     38        cv2.destroyAllWindows()
     39
     40    # Test a corner event
     41    event = csi_events.Event(
     42        scan,
     43        tile,
     44        2,
     45        1000,
     46    )
     47    images = event.extract_images()
     48    assert len(images) == 4
     49    images = event.extract_images(crop_size=100, in_pixels=True)
     50    assert images[0].shape == (100, 100)
     51    images = event.extract_images(crop_size=200, in_pixels=True)
     52    assert images[0].shape == (200, 200)
     53
     54    if SHOW_PLOTS:
     55        for image in images:
     56            cv2.imshow("Events in the corner of a tile", image)
     57            cv2.waitKey(0)
     58        cv2.destroyAllWindows()
     59
     60
     61def test_getting_many_events():
     62    scan = csi_scans.Scan.load_txt("tests/data")
     63    tile = csi_tiles.Tile(scan, 1000)
     64    tile2 = csi_tiles.Tile(scan, 0)
     65    events = [
     66        csi_events.Event(scan, tile, 515, 411),
     67        csi_events.Event(scan, tile2, 2, 1000),
     68        csi_events.Event(scan, tile, 1000, 1000),
     69        csi_events.Event(scan, tile, 87, 126),
     70        csi_events.Event(scan, tile, 1000, 2),
     71        csi_events.Event(scan, tile2, 800, 800),
     72        csi_events.Event(scan, tile, 1000, 662),
     73    ]
     74    # Test time to extract images sequentially
     75    start_time = time.time()
     76    images_1 = []
     77    for event in events:
     78        images_1.append(event.extract_images())
     79    sequential_time = time.time() - start_time
     80
     81    # Test time to extract images in parallel
     82    start_time = time.time()
     83    images_2 = csi_events.Event.extract_images_for_list(events, crop_size=100)
     84    parallel_time = time.time() - start_time
     85    assert parallel_time < sequential_time
     86    for list_a, list_b in zip(images_1, images_2):
     87        assert len(list_a) == len(list_b)
     88        for image_a, image_b in zip(list_a, list_b):
     89            assert np.array_equal(image_a, image_b)
     90
     91    # Test that it works after converting to EventArray and back
     92    event_array = csi_events.EventArray.from_events(events)
     93    remade_events = event_array.to_events(
     94        [scan], ignore_metadata=True, ignore_features=True
     95    )
     96    images_3 = csi_events.Event.extract_images_for_list(remade_events, crop_size=100)
     97    for list_a, list_b in zip(images_1, images_3):
     98        assert len(list_a) == len(list_b)
     99        for image_a, image_b in zip(list_a, list_b):
    100            assert np.array_equal(image_a, image_b)
    101
    102
    103def test_event_coordinates_for_bzscanner():
    104    scan = csi_scans.Scan.load_txt("tests/data")
    105    # Origin
    106    tile = csi_tiles.Tile(scan, 0)
    107    event = csi_events.Event(scan, tile, 0, 0)
    108    scan_origin = event.get_scan_position()
    109    assert 2500 <= scan_origin[0] <= 3500
    110    assert 2500 <= scan_origin[1] <= 3500
    111    scan_origin_on_slide = event.get_slide_position()
    112    assert 71500 <= scan_origin_on_slide[0] <= 72500
    113    assert 21500 <= scan_origin_on_slide[1] <= 22500
    114    # Within the same tile, "bottom-right corner"
    115    event = csi_events.Event(scan, tile, 1000, 1000)
    116    scan_position = event.get_scan_position()
    117    assert scan_origin[0] <= scan_position[0]
    118    assert scan_origin[1] <= scan_position[1]
    119    slide_position = event.get_slide_position()
    120    assert slide_position[0] <= scan_origin_on_slide[0]
    121    assert slide_position[1] <= scan_origin_on_slide[1]
    122
    123    # Next row, opposite side
    124    tile = csi_tiles.Tile(scan, (scan.roi[0].tile_cols - 1, 1))
    125    event = csi_events.Event(scan, tile, 1000, 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 slide_position[0] <= scan_origin_on_slide[0]
    131    assert slide_position[1] <= scan_origin_on_slide[1]
    132
    133    # Opposite corner
    134    tile = csi_tiles.Tile(scan, (scan.roi[0].tile_cols - 1, scan.roi[0].tile_rows - 1))
    135    event = csi_events.Event(scan, tile, 1361, 1003)
    136    scan_position = event.get_scan_position()
    137    assert 21500 <= scan_position[0] <= 22500
    138    assert 58500 <= scan_position[1] <= 60500
    139    slide_position = event.get_slide_position()
    140    assert 14500 <= slide_position[0] <= 15500
    141    assert 2500 <= slide_position[1] <= 3500
    142
    143
    144def test_event_coordinates_for_axioscan():
    145    scan = csi_scans.Scan.load_yaml("tests/data")
    146    # Origin
    147    tile = csi_tiles.Tile(scan, 0)
    148    event = csi_events.Event(scan, tile, 0, 0)
    149    scan_position = event.get_scan_position()
    150    assert -59000 <= scan_position[0] < -55000
    151    assert 0 <= scan_position[1] < 4000
    152    slide_position = event.get_slide_position()
    153    assert 16000 <= slide_position[0] < 20000
    154    assert scan_position[1] == slide_position[1]
    155
    156    # Opposite corner
    157    tile = csi_tiles.Tile(scan, (scan.roi[0].tile_cols - 1, scan.roi[0].tile_rows - 1))
    158    event = csi_events.Event(scan, tile, 2000, 2000)
    159    scan_position = event.get_scan_position()
    160    assert -4000 <= scan_position[0] <= 0
    161    assert 21000 <= scan_position[1] <= 25000
    162    slide_position = event.get_slide_position()
    163    assert 71000 <= slide_position[0] <= 75000
    164    assert scan_position[1] == slide_position[1]
    165
    166
    167def test_eventarray_conversions():
    168    scan = csi_scans.Scan.load_yaml("tests/data")
    169    # Origin
    170    tile = csi_tiles.Tile(scan, 0)
    171    event0 = csi_events.Event(scan, tile, 0, 0)
    172    event1 = csi_events.Event(scan, tile, 1000, 1000)
    173    event2 = csi_events.Event(scan, tile, 2000, 2000)
    174
    175    event_array = csi_events.EventArray.from_events([event0, event1, event2])
    176
    177    assert len(event_array) == 3
    178    assert event_array.metadata is None
    179    assert event_array.features is None
    180
    181    event0.metadata = pd.Series({"event0": 0})
    182
    183    try:
    184        event_array = csi_events.EventArray.from_events([event0, event1, event2])
    185        # Should throw error
    186        assert False
    187    except ValueError:
    188        pass
    189
    190    event1.metadata = pd.Series({"event0": 1})
    191    event2.metadata = pd.Series({"event0": 2})
    192
    193    event_array = csi_events.EventArray.from_events([event0, event1, event2])
    194
    195    assert len(event_array) == 3
    196
    197    events_df = event_array.to_dataframe()
    198
    199    assert len(events_df) == 3
    200
    201    assert event_array == csi_events.EventArray.from_dataframe(events_df)
    202
    203    # Test saving and loading
    204    assert event_array.save_csv("tests/data/events.csv")
    205    assert event_array == csi_events.EventArray.load_csv("tests/data/events.csv")
    206    os.remove("tests/data/events.csv")
    207
    208    assert event_array.save_hdf5("tests/data/events.h5")
    209    assert event_array == csi_events.EventArray.load_hdf5("tests/data/events.h5")
    210    os.remove("tests/data/events.h5")
    211
    212
    213def test_ocular_conversions():
    214    scan = csi_scans.Scan.load_txt("tests/data")
    215    input_path = "/mnt/HDSCA_Development/DZ/0B58703/ocular"
    216    result = csi_events.EventArray.load_ocular(input_path)
    217    # For the purposes of this test, we will manually relabel "clust" == nan to 0
    218    # These come from ocular_interesting.rds, which does not have clusters
    219    result.metadata["clust"] = result.metadata["clust"].fillna(0)
    220    result.metadata["hcpc"] = result.metadata["hcpc"].fillna(0)
    221    result.save_ocular("tests/data")
    222    new_result = csi_events.EventArray.load_ocular("tests/data")
    223    # # Sort them so that they are in the same order
    224    result = result.sort(["tile", "x", "y"])
    225    new_result = new_result.sort(["tile", "x", "y"])
    226    # Note: hcpc method within ocularr and here are different
    227    result.metadata["hcpc"] = new_result.metadata["hcpc"].copy(deep=True)
    228    assert result == new_result
    229    # Clean up
    230    os.remove("tests/data/rc-final.csv")
    231    os.remove("tests/data/rc-final.rds")
    232    os.remove("tests/data/rc-final1.rds")
    233    os.remove("tests/data/rc-final2.rds")
    234    os.remove("tests/data/rc-final3.rds")
    235    os.remove("tests/data/rc-final4.rds")
    236
    237    # Try it with "others" files
    238    result = csi_events.EventArray.load_ocular(input_path, event_type="others")
    239    result.save_ocular("tests/data", event_type="others")
    240    new_result = csi_events.EventArray.load_ocular("tests/data", event_type="others")
    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(deep=True)
    245    assert result == new_result
    246    # Clean up
    247    os.remove("tests/data/others-final.csv")
    248    os.remove("tests/data/others-final.rds")
    249    os.remove("tests/data/others-final1.rds")
    250    os.remove("tests/data/others-final2.rds")
    251    os.remove("tests/data/others-final3.rds")
    252    os.remove("tests/data/others-final4.rds")
    253
    254
    255def test_copy_sort_rows_get():
    256    scan = csi_scans.Scan.load_yaml("tests/data")
    257    # Origin
    258    tile = csi_tiles.Tile(scan, 0)
    259    events = [
    260        csi_events.Event(scan, tile, 0, 100),
    261        csi_events.Event(scan, tile, 0, 0),
    262        csi_events.Event(scan, tile, 1000, 1000),
    263        csi_events.Event(scan, tile, 1000, 1),
    264        csi_events.Event(scan, tile, 2000, 2000),
    265    ]
    266
    267    events = csi_events.EventArray.from_events(events)
    268
    269    # Copy
    270    events_copy = events.copy()
    271    events_copy.info["x"] = 1
    272    # Check that changes to the copy did not change the original
    273    assert events_copy.info["x"].equals(pd.Series([1, 1, 1, 1, 1]))
    274    assert events.info["x"].equals(pd.Series([0, 0, 1000, 1000, 2000]))
    275
    276    # Sort
    277    events = events.sort(["x", "y"], ascending=[False, True])
    278    assert events.info["x"].equals(pd.Series([2000, 1000, 1000, 0, 0]))
    279    assert events.info["y"].equals(pd.Series([2000, 1, 1000, 0, 100]))
    280
    281    # Get
    282    events_get = events.get(["x", "y"])
    283    assert events_get["x"].equals(pd.Series([2000, 1000, 1000, 0, 0]))
    284    assert events_get["y"].equals(pd.Series([2000, 1, 1000, 0, 100]))
    285    assert events_get.columns.equals(pd.Index(["x", "y"]))
    286
    287    # Rows
    288    events_get = events.rows([0, 1, 3])
    289    assert len(events_get) == 3
    290    assert events_get.info["x"].equals(pd.Series([2000, 1000, 0]))
    291    assert events_get.info["y"].equals(pd.Series([2000, 1, 0]))
    292    events_get = events.rows([True, False, False, True, True])
    293    assert len(events_get) == 3
    294    assert events_get.info["x"].equals(pd.Series([2000, 0, 0]))
    295    assert events_get.info["y"].equals(pd.Series([2000, 0, 100]))

def test_getting_event(): View Source

    19def test_getting_event():
    20    scan = csi_scans.Scan.load_txt("tests/data")
    21    tile = csi_tiles.Tile(scan, 1000)
    22    event = csi_events.Event(
    23        scan,
    24        tile,
    25        515,
    26        411,
    27    )
    28    images = event.extract_images()
    29    assert len(images) == 4
    30    images = event.extract_images(crop_size=100, in_pixels=True)
    31    assert images[0].shape == (100, 100)
    32    images = event.extract_images(crop_size=50, in_pixels=True)
    33    assert images[0].shape == (50, 50)
    34
    35    if SHOW_PLOTS:
    36        for image in images:
    37            cv2.imshow("Bright DAPI event in the center", image)
    38            cv2.waitKey(0)
    39        cv2.destroyAllWindows()
    40
    41    # Test a corner event
    42    event = csi_events.Event(
    43        scan,
    44        tile,
    45        2,
    46        1000,
    47    )
    48    images = event.extract_images()
    49    assert len(images) == 4
    50    images = event.extract_images(crop_size=100, in_pixels=True)
    51    assert images[0].shape == (100, 100)
    52    images = event.extract_images(crop_size=200, in_pixels=True)
    53    assert images[0].shape == (200, 200)
    54
    55    if SHOW_PLOTS:
    56        for image in images:
    57            cv2.imshow("Events in the corner of a tile", image)
    58            cv2.waitKey(0)
    59        cv2.destroyAllWindows()

def test_getting_many_events(): View Source

     62def test_getting_many_events():
     63    scan = csi_scans.Scan.load_txt("tests/data")
     64    tile = csi_tiles.Tile(scan, 1000)
     65    tile2 = csi_tiles.Tile(scan, 0)
     66    events = [
     67        csi_events.Event(scan, tile, 515, 411),
     68        csi_events.Event(scan, tile2, 2, 1000),
     69        csi_events.Event(scan, tile, 1000, 1000),
     70        csi_events.Event(scan, tile, 87, 126),
     71        csi_events.Event(scan, tile, 1000, 2),
     72        csi_events.Event(scan, tile2, 800, 800),
     73        csi_events.Event(scan, tile, 1000, 662),
     74    ]
     75    # Test time to extract images sequentially
     76    start_time = time.time()
     77    images_1 = []
     78    for event in events:
     79        images_1.append(event.extract_images())
     80    sequential_time = time.time() - start_time
     81
     82    # Test time to extract images in parallel
     83    start_time = time.time()
     84    images_2 = csi_events.Event.extract_images_for_list(events, crop_size=100)
     85    parallel_time = time.time() - start_time
     86    assert parallel_time < sequential_time
     87    for list_a, list_b in zip(images_1, images_2):
     88        assert len(list_a) == len(list_b)
     89        for image_a, image_b in zip(list_a, list_b):
     90            assert np.array_equal(image_a, image_b)
     91
     92    # Test that it works after converting to EventArray and back
     93    event_array = csi_events.EventArray.from_events(events)
     94    remade_events = event_array.to_events(
     95        [scan], ignore_metadata=True, ignore_features=True
     96    )
     97    images_3 = csi_events.Event.extract_images_for_list(remade_events, crop_size=100)
     98    for list_a, list_b in zip(images_1, images_3):
     99        assert len(list_a) == len(list_b)
    100        for image_a, image_b in zip(list_a, list_b):
    101            assert np.array_equal(image_a, image_b)

def test_event_coordinates_for_bzscanner(): View Source

    104def test_event_coordinates_for_bzscanner():
    105    scan = csi_scans.Scan.load_txt("tests/data")
    106    # Origin
    107    tile = csi_tiles.Tile(scan, 0)
    108    event = csi_events.Event(scan, tile, 0, 0)
    109    scan_origin = event.get_scan_position()
    110    assert 2500 <= scan_origin[0] <= 3500
    111    assert 2500 <= scan_origin[1] <= 3500
    112    scan_origin_on_slide = event.get_slide_position()
    113    assert 71500 <= scan_origin_on_slide[0] <= 72500
    114    assert 21500 <= scan_origin_on_slide[1] <= 22500
    115    # Within the same tile, "bottom-right corner"
    116    event = csi_events.Event(scan, tile, 1000, 1000)
    117    scan_position = event.get_scan_position()
    118    assert scan_origin[0] <= scan_position[0]
    119    assert scan_origin[1] <= scan_position[1]
    120    slide_position = event.get_slide_position()
    121    assert slide_position[0] <= scan_origin_on_slide[0]
    122    assert slide_position[1] <= scan_origin_on_slide[1]
    123
    124    # Next row, opposite side
    125    tile = csi_tiles.Tile(scan, (scan.roi[0].tile_cols - 1, 1))
    126    event = csi_events.Event(scan, tile, 1000, 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 slide_position[0] <= scan_origin_on_slide[0]
    132    assert slide_position[1] <= scan_origin_on_slide[1]
    133
    134    # Opposite corner
    135    tile = csi_tiles.Tile(scan, (scan.roi[0].tile_cols - 1, scan.roi[0].tile_rows - 1))
    136    event = csi_events.Event(scan, tile, 1361, 1003)
    137    scan_position = event.get_scan_position()
    138    assert 21500 <= scan_position[0] <= 22500
    139    assert 58500 <= scan_position[1] <= 60500
    140    slide_position = event.get_slide_position()
    141    assert 14500 <= slide_position[0] <= 15500
    142    assert 2500 <= slide_position[1] <= 3500

def test_event_coordinates_for_axioscan(): View Source

    145def test_event_coordinates_for_axioscan():
    146    scan = csi_scans.Scan.load_yaml("tests/data")
    147    # Origin
    148    tile = csi_tiles.Tile(scan, 0)
    149    event = csi_events.Event(scan, tile, 0, 0)
    150    scan_position = event.get_scan_position()
    151    assert -59000 <= scan_position[0] < -55000
    152    assert 0 <= scan_position[1] < 4000
    153    slide_position = event.get_slide_position()
    154    assert 16000 <= slide_position[0] < 20000
    155    assert scan_position[1] == slide_position[1]
    156
    157    # Opposite corner
    158    tile = csi_tiles.Tile(scan, (scan.roi[0].tile_cols - 1, scan.roi[0].tile_rows - 1))
    159    event = csi_events.Event(scan, tile, 2000, 2000)
    160    scan_position = event.get_scan_position()
    161    assert -4000 <= scan_position[0] <= 0
    162    assert 21000 <= scan_position[1] <= 25000
    163    slide_position = event.get_slide_position()
    164    assert 71000 <= slide_position[0] <= 75000
    165    assert scan_position[1] == slide_position[1]

def test_eventarray_conversions(): View Source

    168def test_eventarray_conversions():
    169    scan = csi_scans.Scan.load_yaml("tests/data")
    170    # Origin
    171    tile = csi_tiles.Tile(scan, 0)
    172    event0 = csi_events.Event(scan, tile, 0, 0)
    173    event1 = csi_events.Event(scan, tile, 1000, 1000)
    174    event2 = csi_events.Event(scan, tile, 2000, 2000)
    175
    176    event_array = csi_events.EventArray.from_events([event0, event1, event2])
    177
    178    assert len(event_array) == 3
    179    assert event_array.metadata is None
    180    assert event_array.features is None
    181
    182    event0.metadata = pd.Series({"event0": 0})
    183
    184    try:
    185        event_array = csi_events.EventArray.from_events([event0, event1, event2])
    186        # Should throw error
    187        assert False
    188    except ValueError:
    189        pass
    190
    191    event1.metadata = pd.Series({"event0": 1})
    192    event2.metadata = pd.Series({"event0": 2})
    193
    194    event_array = csi_events.EventArray.from_events([event0, event1, event2])
    195
    196    assert len(event_array) == 3
    197
    198    events_df = event_array.to_dataframe()
    199
    200    assert len(events_df) == 3
    201
    202    assert event_array == csi_events.EventArray.from_dataframe(events_df)
    203
    204    # Test saving and loading
    205    assert event_array.save_csv("tests/data/events.csv")
    206    assert event_array == csi_events.EventArray.load_csv("tests/data/events.csv")
    207    os.remove("tests/data/events.csv")
    208
    209    assert event_array.save_hdf5("tests/data/events.h5")
    210    assert event_array == csi_events.EventArray.load_hdf5("tests/data/events.h5")
    211    os.remove("tests/data/events.h5")

def test_ocular_conversions(): View Source

    214def test_ocular_conversions():
    215    scan = csi_scans.Scan.load_txt("tests/data")
    216    input_path = "/mnt/HDSCA_Development/DZ/0B58703/ocular"
    217    result = csi_events.EventArray.load_ocular(input_path)
    218    # For the purposes of this test, we will manually relabel "clust" == nan to 0
    219    # These come from ocular_interesting.rds, which does not have clusters
    220    result.metadata["clust"] = result.metadata["clust"].fillna(0)
    221    result.metadata["hcpc"] = result.metadata["hcpc"].fillna(0)
    222    result.save_ocular("tests/data")
    223    new_result = csi_events.EventArray.load_ocular("tests/data")
    224    # # Sort them so that they are in the same order
    225    result = result.sort(["tile", "x", "y"])
    226    new_result = new_result.sort(["tile", "x", "y"])
    227    # Note: hcpc method within ocularr and here are different
    228    result.metadata["hcpc"] = new_result.metadata["hcpc"].copy(deep=True)
    229    assert result == new_result
    230    # Clean up
    231    os.remove("tests/data/rc-final.csv")
    232    os.remove("tests/data/rc-final.rds")
    233    os.remove("tests/data/rc-final1.rds")
    234    os.remove("tests/data/rc-final2.rds")
    235    os.remove("tests/data/rc-final3.rds")
    236    os.remove("tests/data/rc-final4.rds")
    237
    238    # Try it with "others" files
    239    result = csi_events.EventArray.load_ocular(input_path, event_type="others")
    240    result.save_ocular("tests/data", event_type="others")
    241    new_result = csi_events.EventArray.load_ocular("tests/data", event_type="others")
    242    result = result.sort(["tile", "x", "y"])
    243    new_result = new_result.sort(["tile", "x", "y"])
    244    # Note: hcpc method within ocularr and here are different
    245    result.metadata["hcpc"] = new_result.metadata["hcpc"].copy(deep=True)
    246    assert result == new_result
    247    # Clean up
    248    os.remove("tests/data/others-final.csv")
    249    os.remove("tests/data/others-final.rds")
    250    os.remove("tests/data/others-final1.rds")
    251    os.remove("tests/data/others-final2.rds")
    252    os.remove("tests/data/others-final3.rds")
    253    os.remove("tests/data/others-final4.rds")

def test_copy_sort_rows_get(): View Source

    256def test_copy_sort_rows_get():
    257    scan = csi_scans.Scan.load_yaml("tests/data")
    258    # Origin
    259    tile = csi_tiles.Tile(scan, 0)
    260    events = [
    261        csi_events.Event(scan, tile, 0, 100),
    262        csi_events.Event(scan, tile, 0, 0),
    263        csi_events.Event(scan, tile, 1000, 1000),
    264        csi_events.Event(scan, tile, 1000, 1),
    265        csi_events.Event(scan, tile, 2000, 2000),
    266    ]
    267
    268    events = csi_events.EventArray.from_events(events)
    269
    270    # Copy
    271    events_copy = events.copy()
    272    events_copy.info["x"] = 1
    273    # Check that changes to the copy did not change the original
    274    assert events_copy.info["x"].equals(pd.Series([1, 1, 1, 1, 1]))
    275    assert events.info["x"].equals(pd.Series([0, 0, 1000, 1000, 2000]))
    276
    277    # Sort
    278    events = events.sort(["x", "y"], ascending=[False, True])
    279    assert events.info["x"].equals(pd.Series([2000, 1000, 1000, 0, 0]))
    280    assert events.info["y"].equals(pd.Series([2000, 1, 1000, 0, 100]))
    281
    282    # Get
    283    events_get = events.get(["x", "y"])
    284    assert events_get["x"].equals(pd.Series([2000, 1000, 1000, 0, 0]))
    285    assert events_get["y"].equals(pd.Series([2000, 1, 1000, 0, 100]))
    286    assert events_get.columns.equals(pd.Index(["x", "y"]))
    287
    288    # Rows
    289    events_get = events.rows([0, 1, 3])
    290    assert len(events_get) == 3
    291    assert events_get.info["x"].equals(pd.Series([2000, 1000, 0]))
    292    assert events_get.info["y"].equals(pd.Series([2000, 1, 0]))
    293    events_get = events.rows([True, False, False, True, True])
    294    assert len(events_get) == 3
    295    assert events_get.info["x"].equals(pd.Series([2000, 0, 0]))
    296    assert events_get.info["y"].equals(pd.Series([2000, 0, 100]))