tests.test_events

  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():
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():
 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():
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():
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():
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():
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():
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]))