Skip to content

Conversation

@sfc-gh-lwilby
Copy link
Collaborator

Describe your changes

Fixes a v1.50.0 regression where plots and images rendered at 16px width in fragments, expanders, and containers instead of proper dimensions.

Changes Made:

Root Cause:

Commit 4954237 (Sept 11, 2025) changed imgs container from width: 100% to width: auto to fix horizontal alignment (#12435). This inadvertently broke initial width calculation:

  • Parent container with width: auto depends on content
  • On initial render, content not loaded yet, so auto = 0px
  • Child elements calculate as 100% of 0px = 16px minimum
  • Fullscreen toggle forced recalculation and restored proper width

Expected Behavior (now fixed):

  • Plots and images render at proper width on initial load
  • No tiny 16px plots in fragments
  • No tiny images in expanders or containers
  • Horizontal alignment still works with explicit widths

GitHub Issue Link (if applicable)

Fixes #12678
Fixes #12763

Testing Plan

  • E2E Tests - Added 6 comprehensive regression tests that verify width > 200px in all contexts
  • Manual testing - Created test app in st-issues repo for verification

Test Results:
✅ All 6 new regression tests PASS (were failing at 16px, now pass with proper width)
✅ Existing st_image and st_pyplot tests PASS
✅ Container alignment tests PASS (preserves #12435 fix)

Manual Testing:

Additional Notes:

This fix carefully balances two requirements:

  1. Width calculation needs explicit container width (100%) - fixes Plots are shown tiny, fixed after maximizing and unmaximizing plot again - v1.50.0 #12678
  2. Horizontal alignment needs auto width with explicit sizes - preserves st.image in st.container with horizontal_alignment is always left-aligned #12435

The conditional logic ensures both features work correctly without interfering with each other.


Contribution License Agreement

By submitting this pull request you agree that all contributions to this project are made under the Apache 2.0 license.

@sfc-gh-lwilby sfc-gh-lwilby added security-assessment-completed Security assessment has been completed for PR change:bugfix PR contains bug fix implementation impact:users PR changes affect end users labels Oct 18, 2025
@snyk-io
Copy link
Contributor

snyk-io bot commented Oct 18, 2025

Snyk checks have passed. No issues have been found so far.

Status Scanner Critical High Medium Low Total (0)
Licenses 0 0 0 0 0 issues
Open Source Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@github-actions
Copy link
Contributor

github-actions bot commented Oct 18, 2025

✅ PR preview is ready!

Name Link
📦 Wheel file https://core-previews.s3-us-west-2.amazonaws.com/pr-12807/streamlit-1.50.0-py3-none-any.whl
📦 @streamlit/component-v2-lib Download from artifacts
🕹️ Preview app pr-12807.streamlit.app (☁️ Deploy here if not accessible)

@sfc-gh-lwilby sfc-gh-lwilby changed the title Fix pyplot/image width regression in fragments, expanders, containers [fix] pyplot/image width regression in fragments, expanders, containers Oct 18, 2025
sfc-gh-lwilby added a commit that referenced this pull request Oct 19, 2025
Addresses PR #12807 review feedback:

1. BLOCKING: Restructured E2E tests to focus on width modes
   - Changed from context-based tests (fragment/expander/container)
     to parameterized tests covering all combinations of:
     * Width modes: default (stretch/legacy) and content
     * Contexts: fragment, expander, container
   - Tests now clearly communicate what's being tested
   - Eliminated redundant test functions (6 tests → 1 parameterized + 1 count check)

2. Improved terminology in frontend code comment
   - Changed 'isUsingStretchOrDefault' to 'isUsingStretchOrLegacy'
   - Added clarifying comment about legacy behavior
   - Addresses question about what 'default' means

3. Updated test documentation
   - Removed references to 'workaround' terminology
   - Added clear explanation of width modes and bug symptoms
   - Improved comments explaining 200px threshold reasoning

Changes maintain the same test coverage but with clearer structure
and more maintainable parameterized approach.
sfc-gh-lwilby added a commit that referenced this pull request Oct 19, 2025
Addresses all blocking feedback from PR #12807 review:

1. BLOCKING: Move tests into existing st_pyplot files
   - Moved regression tests from standalone files into st_pyplot.py
   - Moved test functions into st_pyplot_test.py
   - Deleted standalone st_pyplot_image_width_regression* files
   - Better for test suite performance and organization

2. BLOCKING: Add pixel width test cases
   - Added 400px width tests for all contexts (fragment, expander, container)
   - Now tests all width modes: 'stretch', 'content', and pixel values
   - Ensures conditional logic in StyledElementContainerLayoutWrapper handles all cases

3. BLOCKING: Use 'stretch' instead of 'default'
   - Changed test app to use 'stretch' directly
   - Eliminated conditional logic (can pass width value directly to st.pyplot)
   - Clearer and more aligned with Width type system

Test structure:
- 9 regression tests (3 width modes × 3 contexts)
- Parameterized test function for all combinations
- Updated element counts in existing tests (11 → 20)

All three blocking issues resolved.
sfc-gh-lwilby added a commit that referenced this pull request Oct 19, 2025
…ions

Addresses three suggestions from PR #12807 review:

1. Simplify test cases (suggestion #2)
   - Reduced from 9 parameterized tests to 3 focused tests
   - Removed fragment and expander contexts (regression only in containers)
   - Eliminated parameterization that made test app hard to read
   - Simple, clear structure with named containers

2. Add deterministic width assertions (suggestion #3)
   - stretch: Container width=600, expect ~580-600px (allows padding)
   - content: Figure 6.4in @ 100 DPI = 640px, expect ~620-640px
   - pixel: Explicit width=500, expect ~480-500px
   - More stable than arbitrary >200px threshold

3. Clean up unnecessary comments (suggestion #4)
   - Removed comments that just describe next line
   - Kept meaningful comments explaining test logic and expectations
   - Improved readability

Test structure:
- 3 regression tests in containers only
- Specific figure size (6.4in x 4.8in at 100 DPI)
- Known container width for stretch test
- Deterministic assertions with reasonable margins

Note: Suggestion #1 (use_container_width check) addressed with explanation
in PR comment - current logic is correct for the new widthConfig system.
Fixes width calculation bug where plots and images rendered at 16px
in fragments, expanders, and containers (v1.50.0 regression).

Root cause: Commit 4954237 changed imgs container from width 100%
to auto for horizontal alignment (#12435), breaking initial width
calculation when no explicit width is set.

Changes:
- Conditional width override in StyledElementContainerLayoutWrapper
- Use width 100% for stretch/default (fixes width calculation)
- Use width auto for content/pixel (preserves alignment fix)
- Add comprehensive E2E regression tests (6 tests)

Tests verify:
- Plots render at proper width (>200px, not 16px) in all contexts
- width='content' workaround still works
- Horizontal alignment preserved from #12435

Fixes #12678
Fixes #12763
Addresses PR #12807 review feedback:

1. BLOCKING: Restructured E2E tests to focus on width modes
   - Changed from context-based tests (fragment/expander/container)
     to parameterized tests covering all combinations of:
     * Width modes: default (stretch/legacy) and content
     * Contexts: fragment, expander, container
   - Tests now clearly communicate what's being tested
   - Eliminated redundant test functions (6 tests → 1 parameterized + 1 count check)

2. Improved terminology in frontend code comment
   - Changed 'isUsingStretchOrDefault' to 'isUsingStretchOrLegacy'
   - Added clarifying comment about legacy behavior
   - Addresses question about what 'default' means

3. Updated test documentation
   - Removed references to 'workaround' terminology
   - Added clear explanation of width modes and bug symptoms
   - Improved comments explaining 200px threshold reasoning

Changes maintain the same test coverage but with clearer structure
and more maintainable parameterized approach.
Addresses all blocking feedback from PR #12807 review:

1. BLOCKING: Move tests into existing st_pyplot files
   - Moved regression tests from standalone files into st_pyplot.py
   - Moved test functions into st_pyplot_test.py
   - Deleted standalone st_pyplot_image_width_regression* files
   - Better for test suite performance and organization

2. BLOCKING: Add pixel width test cases
   - Added 400px width tests for all contexts (fragment, expander, container)
   - Now tests all width modes: 'stretch', 'content', and pixel values
   - Ensures conditional logic in StyledElementContainerLayoutWrapper handles all cases

3. BLOCKING: Use 'stretch' instead of 'default'
   - Changed test app to use 'stretch' directly
   - Eliminated conditional logic (can pass width value directly to st.pyplot)
   - Clearer and more aligned with Width type system

Test structure:
- 9 regression tests (3 width modes × 3 contexts)
- Parameterized test function for all combinations
- Updated element counts in existing tests (11 → 20)

All three blocking issues resolved.
…ions

Addresses three suggestions from PR #12807 review:

1. Simplify test cases (suggestion #2)
   - Reduced from 9 parameterized tests to 3 focused tests
   - Removed fragment and expander contexts (regression only in containers)
   - Eliminated parameterization that made test app hard to read
   - Simple, clear structure with named containers

2. Add deterministic width assertions (suggestion #3)
   - stretch: Container width=600, expect ~580-600px (allows padding)
   - content: Figure 6.4in @ 100 DPI = 640px, expect ~620-640px
   - pixel: Explicit width=500, expect ~480-500px
   - More stable than arbitrary >200px threshold

3. Clean up unnecessary comments (suggestion #4)
   - Removed comments that just describe next line
   - Kept meaningful comments explaining test logic and expectations
   - Improved readability

Test structure:
- 3 regression tests in containers only
- Specific figure size (6.4in x 4.8in at 100 DPI)
- Known container width for stretch test
- Deterministic assertions with reasonable margins

Note: Suggestion #1 (use_container_width check) addressed with explanation
in PR comment - current logic is correct for the new widthConfig system.
Changed from dimensional assertions to snapshot tests for better robustness:

Before:
- Asserted exact pixel dimensions (560-600px, 620-680px, 480-500px)
- Brittle due to matplotlib rendering variations across browsers
- Failed in CI with unexpected 672px for content width

After:
- Use snapshot testing like other tests in the file
- More consistent with existing test patterns
- Still catches regression (16px width would look very different)
- More maintainable and less brittle

Benefits:
- Follows existing pattern in st_pyplot_test.py
- Visual verification instead of pixel-perfect assertions
- Snapshots will clearly show if regression returns
- Works across all browsers without adjustment
Addressed suggestion #1 feedback:

The suggestion to check use_container_width field revealed a TypeScript
error - ImageList proto doesn't have useContainerWidth field (unlike
chart elements). ImageList only has deprecated 'width' field (WidthBehavior enum).

Current logic is correct:
- When widthConfig is not set → default to stretch behavior (width: 100%)
- When widthConfig.useStretch → use stretch behavior (width: 100%)
- When widthConfig has other values → use auto width

The legacy 'width' field (WidthBehavior enum) is handled by ImageList
component itself, not by the container wrapper. The container just provides
the outer width context.

Updated comment to clarify this and explain the default legacy behavior.
Addresses blocking feedback: Use key-based access and snapshot containers.

Changes:
- Added keys to test containers (regression_stretch, regression_content, regression_pixel)
- Changed from index-based access (nth(11), nth(12), nth(13))
  to key-based access (get_element_by_key)
- Snapshot whole container instead of just the image element

Benefits:
- More stable (key-based locators over indices)
- Follows E2E best practices
- Snapshots capture full context (container + border + image)
- Clearer test intent with named keys
- Eliminates need to count element indices

This is the recommended pattern from e2e_playwright best practices
for elements that support key parameter.
@sfc-gh-lwilby sfc-gh-lwilby force-pushed the fix/pyplot-image-width-regression-fragments branch from 94ca590 to b29f8bc Compare October 22, 2025 16:36
@sfc-gh-lwilby sfc-gh-lwilby changed the title [fix] pyplot/image width regression in fragments, expanders, containers [fix] pyplot/image width regression in fragments, containers Oct 22, 2025
@sfc-gh-lwilby sfc-gh-lwilby marked this pull request as ready for review October 22, 2025 20:23
Copy link
Contributor

@sfc-gh-nbellante sfc-gh-nbellante left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@sfc-gh-lwilby sfc-gh-lwilby merged commit 595d61c into develop Oct 24, 2025
45 of 46 checks passed
@sfc-gh-lwilby sfc-gh-lwilby deleted the fix/pyplot-image-width-regression-fragments branch October 24, 2025 22:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

change:bugfix PR contains bug fix implementation impact:users PR changes affect end users security-assessment-completed Security assessment has been completed for PR

Projects

None yet

3 participants