@@ -1500,6 +1500,55 @@ def displayed_image_sizes(frame: CytoDataFrame) -> list:
15001500 assert all (size == (expected_width , expected_height ) for size in sizes )
15011501
15021502
1503+ def test_repr_html_transposed_render_whole_image_without_bounding_box_or_center (
1504+ cytotable_NF1_data_parquet_shrunken : str ,
1505+ ):
1506+ """
1507+ Tests that ``.T`` on a whole-FOV CytoDataFrame (no bounding box or
1508+ compartment center columns) still renders a transposed table with the
1509+ embedded image intact, rather than falling back to an untransposed table
1510+ of raw filenames.
1511+
1512+ See https://github.com/cytomining/CytoDataFrame/issues/226.
1513+ """
1514+
1515+ image_dir = (
1516+ f"{ pathlib .Path (cytotable_NF1_data_parquet_shrunken ).parent } /Plate_2_images"
1517+ )
1518+ image_filename = next (pathlib .Path (image_dir ).glob ("*.tif" )).name
1519+
1520+ # a minimal whole-FOV frame with no bounding box or compartment
1521+ # center columns at all (mirrors the issue's reproduction).
1522+ df = pd .DataFrame (
1523+ {
1524+ "FileName_OrigDNA" : [image_filename , image_filename ],
1525+ "PathName_OrigDNA" : [image_dir , image_dir ],
1526+ "SomeMetric" : [- 2.5 , - 2.7 ],
1527+ }
1528+ )
1529+
1530+ whole_frame = CytoDataFrame (df , display_options = {"render_whole_image" : True })
1531+ assert whole_frame ._custom_attrs ["data_bounding_box" ] is None
1532+ assert whole_frame ._custom_attrs ["compartment_center_xy" ] is None
1533+
1534+ non_transposed_html = whole_frame .head (2 )._repr_html_ (debug = True )
1535+ transposed_html = whole_frame .head (2 ).T ._repr_html_ (debug = True )
1536+
1537+ non_transposed_images = re .findall (
1538+ r"data:image/png;base64,([^\"]+)" , non_transposed_html
1539+ )
1540+ transposed_images = re .findall (r"data:image/png;base64,([^\"]+)" , transposed_html )
1541+
1542+ # the transposed rendering must still embed the same images as the
1543+ # non-transposed rendering (previously it silently rendered none).
1544+ assert len (transposed_images ) == len (non_transposed_images ) > 0
1545+
1546+ # the transposed rendering must actually be transposed: the
1547+ # FileName_OrigDNA column becomes a row label instead of appearing
1548+ # in the header row.
1549+ assert ">FileName_OrigDNA<" in transposed_html
1550+
1551+
15031552def test_repr_html_offset_bounding_box_warns_when_centers_missing_with_bbox (
15041553 cytotable_NF1_data_parquet_shrunken : str ,
15051554 caplog : pytest .LogCaptureFixture ,
@@ -3155,6 +3204,73 @@ def test_generate_jupyter_dataframe_html_with_joined_components(
31553204 assert "<div>OME</div>" in html
31563205
31573206
3207+ def test_generate_jupyter_dataframe_html_preserves_center_join_with_existing_paths (
3208+ monkeypatch : pytest .MonkeyPatch ,
3209+ tmp_path : pathlib .Path ,
3210+ ):
3211+ """
3212+ Regression test: an externally joined compartment center must survive
3213+ rendering even when image-path columns are already present on the
3214+ frame (so the image-path re-add block takes its "already present"
3215+ branch instead of re-joining). Before the fix, that branch discarded
3216+ the joined compartment center columns, and the later ``.drop(...)``
3217+ of those columns raised a ``KeyError``.
3218+ """
3219+ base = pd .DataFrame (
3220+ {
3221+ "Image_FileName_DNA" : ["dna.tiff" ],
3222+ "Image_PathName_DNA" : [str (tmp_path )],
3223+ },
3224+ index = [0 ],
3225+ )
3226+ cdf = CytoDataFrame (
3227+ base ,
3228+ data_context_dir = str (tmp_path ),
3229+ display_options = {"render_whole_image" : True },
3230+ )
3231+ assert cdf ._custom_attrs ["data_bounding_box" ] is None
3232+ cdf ._custom_attrs ["compartment_center_xy" ] = pd .DataFrame (
3233+ {"Cells_Location_Center_X" : [5 ], "Cells_Location_Center_Y" : [6 ]},
3234+ index = [0 ],
3235+ )
3236+ cdf ._custom_attrs ["data_image_paths" ] = pd .DataFrame (
3237+ {"Image_PathName_DNA" : [str (tmp_path )]},
3238+ index = [0 ],
3239+ )
3240+
3241+ options = {
3242+ "display.notebook_repr_html" : True ,
3243+ "display.max_rows" : 10 ,
3244+ "display.min_rows" : 10 ,
3245+ "display.max_columns" : 10 ,
3246+ "display.show_dimensions" : False ,
3247+ }
3248+
3249+ monkeypatch .setattr ("cytodataframe.frame.get_option" , lambda name : options [name ])
3250+ monkeypatch .setattr (
3251+ "cytodataframe.frame.CytoDataFrame.find_image_columns" ,
3252+ lambda self : ["Image_FileName_DNA" ],
3253+ )
3254+ monkeypatch .setattr (
3255+ "cytodataframe.frame.CytoDataFrame.find_image_path_columns" ,
3256+ lambda self , image_cols , all_cols : {"Image_FileName_DNA" : "Image_PathName_DNA" },
3257+ )
3258+ monkeypatch .setattr (
3259+ "cytodataframe.frame.CytoDataFrame.get_displayed_rows" ,
3260+ lambda self : [0 ],
3261+ )
3262+ monkeypatch .setattr (
3263+ cdf ,
3264+ "process_image_data_as_html_display" ,
3265+ lambda ** _kwargs : "<img src='x'/>" ,
3266+ )
3267+
3268+ # previously raised KeyError from dropping compartment center columns
3269+ # that had been silently discarded earlier in the method.
3270+ html = cdf ._generate_jupyter_dataframe_html ()
3271+ assert "<img src='x'/>" in html
3272+
3273+
31583274def test_render_output_displays_js_and_print_html (monkeypatch : pytest .MonkeyPatch ):
31593275 cdf = CytoDataFrame (pd .DataFrame ({"A" : [1 ]}))
31603276 cdf ._custom_attrs ["_output" ] = nullcontext ()
0 commit comments