Skip to content

.T/transpose corrupts rendering for whole-FOV CytoDataFrames using render_whole_image (no bounding box / compartment center) #226

Closed

Description

@jenna-tomkinson

Environment

  • cytodataframe: 0.3.3
  • Python: 3.11
  • Installed via: pip install cytodataframe (PyPI)

Summary

Calling .T (or .transpose()) on a CytoDataFrame built from image-level (whole-FOV) data (i.e., no bounding box columns and no compartment-center columns, using display_options={"render_whole_image": True}), produces a broken render: the output is neither transposed nor does it show the embedded image. It falls back to a plain untransposed table of raw filenames.

Without .T, the same object renders correctly with real embedded images and a correct table.

Minimal reproduction

import pandas as pd
from cytodataframe import CytoDataFrame

df = pd.DataFrame({
    "FileName_OrigDNA": ["imgA.tiff", "imgB.tiff"],
    "PathName_OrigDNA": ["/path/to/images", "/path/to/images"],
    "SomeMetric": [-2.5, -2.7],
})

cdf = CytoDataFrame(df, display_options={"render_whole_image": True})

cdf.head(2)      # renders correctly: real embedded images
cdf.head(2).T    # broken: no images, and NOT actually transposed in the rendered HTML

Expected behavior

cdf.head(2).T should render a transposed table with the image still embedded in the FileName_OrigDNA row.

Actual behavior

The rendered HTML is untransposed (same orientation as before .T) and shows raw filename text instead of the image.

Image

Root cause

In _generate_jupyter_dataframe_html (src/cytodataframe/frame.py), around the "Re-add image path columns" block:

data = (
    data.join(other=self._custom_attrs["data_image_paths"])
    if compartment_center_externally_joined or bounding_box_externally_joined
    else self.join(other=self._custom_attrs["data_image_paths"])
)

Earlier in the method, when is_transposed is True, a correctly un-transposed working copy is built:

if self._custom_attrs["is_transposed"]:
    data = pd.DataFrame(self).transpose()

But the image-path re-join's else branch joins against self (still in its transposed shape — columns are row-ids, index is the original column labels) instead of the already-corrected data. Since neither bounding_box_externally_joined nor compartment_center_externally_joined is True for whole-FOV data (there's no bounding box or compartment center at all), this else branch is exactly the one taken. So the un-transpose fix from earlier is discarded, and the join is performed on completely mismatched indices, silently producing no usable PathName_* values. Because this corrupted data is used going forward, the later if self._custom_attrs["is_transposed"]: data = data.transpose() retranspose-for-display step also ends up applied to the wrong object, which is why the final table isn't transposed either.

Suggested fix

In that branch, join against data (the transpose-corrected copy) rather than self whenever is_transposed is True, e.g.:

data = (
    data.join(other=self._custom_attrs["data_image_paths"])
    if compartment_center_externally_joined
    or bounding_box_externally_joined
    or self._custom_attrs["is_transposed"]
    else self.join(other=self._custom_attrs["data_image_paths"])
)

Activity

  1. added theissue type on Aug 27, 2026
  2. d33bs commented on Aug 28, 2026

    @d33bs
    Member

    Thanks @jenna-tomkinson, a fix is ready for review in #227

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions