Skip to content

⚡️ Speed up function axis_spanning_shape_annotation by 6% #111

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

codeflash-ai[bot]
Copy link

@codeflash-ai codeflash-ai bot commented May 24, 2025

📄 6% (0.06x) speedup for axis_spanning_shape_annotation in plotly/shapeannotation.py

⏱️ Runtime : 3.05 milliseconds 2.86 milliseconds (best of 277 runs)

📝 Explanation and details

Here is an optimized version of your program for runtime and memory efficiency, while preserving function names, signatures, and return values, and keeping comments where logical code blocks are changed. Optimizations focused on.

  • Minimize temporary list allocations (especially min([x0, x1]), replace with min(x0, x1) etc).
  • Optimize set constructions for position comparison (avoid repeated creation of temporary sets and repeated split operations).
  • Micro-optimize by inlining very cheap computations or removing duplicates.
  • Precompute reused results when necessary.
  • Use for-loops instead of repeated if-elif chains when the possible positions are known and stable.

Summary of changes:

  • Avoid redundant temporary lists/sets: using min(x0, x1) over [x0, x1], tuple for coordinates for less allocation, frozenset to enable O(1) mapping lookups.
  • Speed up if-elif blocks: use a mapping keyed by frozenset(position_set) that's much quicker than a sequential if-elif chain.
  • Reduce dictionary calls and lookups.
  • Reduce function call overhead and unnecessary lambdas/filter.

All code functionality and return values remain unchanged.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 943 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 100.0%
🌀 Generated Regression Tests Details
import pytest
from plotly.shapeannotation import axis_spanning_shape_annotation

# ----------------- UNIT TESTS -----------------

# 1. Basic Test Cases

def test_none_annotation_and_no_kwargs_returns_none():
    # If both annotation and annotation_kwargs are None/empty, should return None
    codeflash_output = axis_spanning_shape_annotation(None, "vline", {"x0": 1, "x1": 1, "y0": 0, "y1": 10}, {})

def test_basic_vline_top_right():
    # Basic vline, default position (should be 'top right')
    codeflash_output = axis_spanning_shape_annotation(
        None,
        "vline",
        {"x0": 2, "x1": 2, "y0": 0, "y1": 10},
        {}
    ); result = codeflash_output

def test_basic_hline_top_right():
    # Basic hline, default position (should be 'top right')
    codeflash_output = axis_spanning_shape_annotation(
        None,
        "hline",
        {"x0": 0, "x1": 10, "y0": 3, "y1": 3},
        {}
    ); result = codeflash_output

def test_basic_vrect_inside_top_left():
    # vrect, explicit position
    codeflash_output = axis_spanning_shape_annotation(
        None,
        "vrect",
        {"x0": 1, "x1": 5, "y0": 2, "y1": 8},
        {"annotation_position": "top left"}
    ); result = codeflash_output

def test_basic_hrect_inside_bottom_right():
    # hrect, explicit position
    codeflash_output = axis_spanning_shape_annotation(
        None,
        "hrect",
        {"x0": 1, "x1": 5, "y0": 2, "y1": 8},
        {"annotation_position": "bottom right"}
    ); result = codeflash_output

def test_annotation_dict_overrides_shape():
    # If annotation dict already has x, y, xanchor, yanchor, these should not be overwritten
    ann = {"x": 999, "y": 888, "xanchor": "foo", "yanchor": "bar"}
    codeflash_output = axis_spanning_shape_annotation(
        ann.copy(),
        "vline",
        {"x0": 1, "x1": 1, "y0": 0, "y1": 10},
        {}
    ); result = codeflash_output

def test_annotation_kwargs_override_dict():
    # annotation_ prefixed kwargs should override annotation dict fields (except position)
    ann = {"text": "hello"}
    codeflash_output = axis_spanning_shape_annotation(
        ann,
        "vline",
        {"x0": 1, "x1": 1, "y0": 0, "y1": 10},
        {"annotation_text": "world", "annotation_font_size": 12}
    ); result = codeflash_output

def test_annotation_position_in_kwargs_not_set_in_result():
    # annotation_position in kwargs should NOT be set in result
    codeflash_output = axis_spanning_shape_annotation(
        None,
        "vline",
        {"x0": 1, "x1": 1, "y0": 0, "y1": 10},
        {"annotation_position": "top left"}
    ); result = codeflash_output

# 2. Edge Test Cases


def test_invalid_position_raises():
    # Invalid position should raise
    with pytest.raises(ValueError):
        axis_spanning_shape_annotation(
            None,
            "vline",
            {"x0": 1, "x1": 1, "y0": 0, "y1": 10},
            {"annotation_position": "banana"}
        )

def test_vrect_outside_top_right():
    # vrect, outside top right
    codeflash_output = axis_spanning_shape_annotation(
        None,
        "vrect",
        {"x0": 1, "x1": 5, "y0": 2, "y1": 8},
        {"annotation_position": "outside top right"}
    ); result = codeflash_output

def test_hrect_outside_bottom_left():
    # hrect, outside bottom left
    codeflash_output = axis_spanning_shape_annotation(
        None,
        "hrect",
        {"x0": 1, "x1": 5, "y0": 2, "y1": 8},
        {"annotation_position": "outside bottom left"}
    ); result = codeflash_output

def test_vline_bottom():
    # vline, bottom
    codeflash_output = axis_spanning_shape_annotation(
        None,
        "vline",
        {"x0": 1, "x1": 1, "y0": 0, "y1": 10},
        {"annotation_position": "bottom"}
    ); result = codeflash_output

def test_hline_left():
    # hline, left
    codeflash_output = axis_spanning_shape_annotation(
        None,
        "hline",
        {"x0": 0, "x1": 10, "y0": 3, "y1": 3},
        {"annotation_position": "left"}
    ); result = codeflash_output

def test_rect_with_x0_greater_than_x1_and_y0_greater_than_y1():
    # Should handle x0 > x1 and y0 > y1 correctly
    codeflash_output = axis_spanning_shape_annotation(
        None,
        "vrect",
        {"x0": 10, "x1": 2, "y0": 8, "y1": 1},
        {"annotation_position": "top left"}
    ); result = codeflash_output

def test_annotation_is_empty_dict():
    # annotation is empty dict, should fill in all keys
    codeflash_output = axis_spanning_shape_annotation(
        {},
        "hline",
        {"x0": 0, "x1": 10, "y0": 3, "y1": 3},
        {}
    ); result = codeflash_output

def test_annotation_with_some_fields_none():
    # If annotation dict has some fields as None, these should be filled in
    codeflash_output = axis_spanning_shape_annotation(
        {"x": None, "y": None, "xanchor": None, "yanchor": None, "text": "foo"},
        "vline",
        {"x0": 1, "x1": 1, "y0": 0, "y1": 10},
        {}
    ); result = codeflash_output

def test_kwargs_with_non_annotation_keys_ignored():
    # Only annotation_ keys should be processed
    codeflash_output = axis_spanning_shape_annotation(
        None,
        "vline",
        {"x0": 1, "x1": 1, "y0": 0, "y1": 10},
        {"foo": "bar", "baz": 123}
    ); result = codeflash_output

# 3. Large Scale Test Cases

def test_many_annotations_large_scale():
    # Simulate a batch of many axis_spanning_shape_annotation calls
    # (not a performance test, but checks no cross-talk or state issues)
    for i in range(100):
        x = i
        y = 2 * i
        # alternate vline/hline/vrect/hrect
        shape_types = ["vline", "hline", "vrect", "hrect"]
        shape_type = shape_types[i % 4]
        shape_args = {"x0": x, "x1": x + 1, "y0": y, "y1": y + 1}
        kwargs = {"annotation_text": f"anno_{i}", "annotation_font_size": i}
        codeflash_output = axis_spanning_shape_annotation(
            None, shape_type, shape_args, kwargs
        ); result = codeflash_output

def test_large_rect_coordinates():
    # Test with large coordinate values
    shape_args = {"x0": 1e6, "x1": 1e6 + 500, "y0": -1e6, "y1": -1e6 + 300}
    codeflash_output = axis_spanning_shape_annotation(
        None,
        "vrect",
        shape_args,
        {"annotation_position": "top right"}
    ); result = codeflash_output

def test_large_number_of_kwargs():
    # Test with many annotation_ kwargs
    kwargs = {f"annotation_custom_{i}": i for i in range(100)}
    # Add a required annotation_position so annotation is created
    kwargs["annotation_position"] = "top right"
    codeflash_output = axis_spanning_shape_annotation(
        None,
        "vline",
        {"x0": 5, "x1": 5, "y0": 0, "y1": 10},
        kwargs
    ); result = codeflash_output
    for i in range(100):
        pass

def test_large_scale_rects_positions():
    # Test all valid positions for vrect and hrect in a loop, to ensure no position fails
    positions = [
        "top left", "top right", "top", "bottom left", "bottom right", "bottom",
        "left", "right", "inside", "outside top left", "outside top right",
        "outside top", "outside bottom left", "outside bottom right", "outside bottom",
        "outside left", "outside right"
    ]
    shape_args = {"x0": 0, "x1": 10, "y0": 0, "y1": 10}
    for pos in positions:
        for shape_type in ["vrect", "hrect"]:
            # Should not raise
            codeflash_output = axis_spanning_shape_annotation(
                None, shape_type, shape_args, {"annotation_position": pos}
            ); result = codeflash_output

def test_large_scale_lines_positions():
    # Test all valid positions for vline and hline in a loop, to ensure no position fails
    positions = [
        "top left", "top right", "top", "bottom left", "bottom right", "bottom",
        "left", "right"
    ]
    shape_args = {"x0": 0, "x1": 0, "y0": 0, "y1": 10}
    for pos in positions:
        for shape_type in ["vline", "hline"]:
            # Should not raise
            codeflash_output = axis_spanning_shape_annotation(
                None, shape_type, shape_args, {"annotation_position": pos}
            ); result = codeflash_output
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.

import pytest  # used for our unit tests
from plotly.shapeannotation import axis_spanning_shape_annotation

# unit tests

# ----------------------- BASIC TEST CASES -----------------------

def test_none_annotation_and_no_kwargs_returns_none():
    # No annotation and no annotation_ keys: should return None
    codeflash_output = axis_spanning_shape_annotation(None, "vline", {"x0": 1, "x1": 1, "y0": 0, "y1": 10}, {})

def test_minimal_vline_defaults():
    # Should compute annotation at default position (top right)
    codeflash_output = axis_spanning_shape_annotation(
        None,
        "vline",
        {"x0": 1, "x1": 1, "y0": 0, "y1": 10},
        {}
    ); result = codeflash_output

def test_minimal_hline_defaults():
    # Should compute annotation at default position (top right)
    codeflash_output = axis_spanning_shape_annotation(
        None,
        "hline",
        {"x0": 0, "x1": 10, "y0": 5, "y1": 5},
        {}
    ); result = codeflash_output

def test_minimal_vrect_defaults():
    # Should compute annotation at default position (top right, prepended with inside)
    codeflash_output = axis_spanning_shape_annotation(
        None,
        "vrect",
        {"x0": 1, "x1": 3, "y0": 2, "y1": 4},
        {}
    ); result = codeflash_output

def test_minimal_hrect_defaults():
    # Should compute annotation at default position (top right, prepended with inside)
    codeflash_output = axis_spanning_shape_annotation(
        None,
        "hrect",
        {"x0": 1, "x1": 3, "y0": 2, "y1": 4},
        {}
    ); result = codeflash_output

def test_annotation_position_override():
    # Should use annotation_position from kwargs
    codeflash_output = axis_spanning_shape_annotation(
        None,
        "vline",
        {"x0": 1, "x1": 1, "y0": 0, "y1": 10},
        {"annotation_position": "bottom left"}
    ); result = codeflash_output

def test_annotation_dict_is_mutated():
    # If annotation dict is supplied, it is mutated and returned
    anno = {"text": "foo"}
    codeflash_output = axis_spanning_shape_annotation(
        anno,
        "hline",
        {"x0": 0, "x1": 10, "y0": 5, "y1": 5},
        {}
    ); out = codeflash_output

def test_annotation_kwargs_override():
    # annotation_foo in kwargs overrides annotation dict
    anno = {"text": "foo", "x": None}
    codeflash_output = axis_spanning_shape_annotation(
        anno,
        "hline",
        {"x0": 0, "x1": 10, "y0": 5, "y1": 5},
        {"annotation_text": "bar", "annotation_x": 123}
    ); out = codeflash_output

def test_annotation_position_and_kwargs():
    # annotation_position in kwargs, plus other annotation_foo
    codeflash_output = axis_spanning_shape_annotation(
        None,
        "vrect",
        {"x0": 1, "x1": 3, "y0": 2, "y1": 4},
        {"annotation_position": "outside bottom left", "annotation_text": "bar"}
    ); out = codeflash_output

def test_annotation_x_and_y_preserved():
    # If annotation dict already has x/y, they are not overwritten
    anno = {"x": 99, "y": 88}
    codeflash_output = axis_spanning_shape_annotation(
        anno,
        "vline",
        {"x0": 1, "x1": 1, "y0": 0, "y1": 10},
        {}
    ); out = codeflash_output

# ----------------------- EDGE TEST CASES -----------------------


def test_invalid_position_raises():
    # Should raise ValueError for invalid annotation_position
    with pytest.raises(ValueError):
        axis_spanning_shape_annotation(
            None,
            "vline",
            {"x0": 1, "x1": 1, "y0": 0, "y1": 10},
            {"annotation_position": "notarealposition"}
        )


def test_swapped_coords():
    # x0 > x1, y0 > y1 should still work (min/max logic)
    codeflash_output = axis_spanning_shape_annotation(
        None,
        "vrect",
        {"x0": 5, "x1": 2, "y0": 10, "y1": 3},
        {"annotation_position": "inside bottom left"}
    ); out = codeflash_output

def test_none_annotation_with_annotation_kwargs():
    # If annotation is None but annotation_foo kwargs are present, should return dict
    codeflash_output = axis_spanning_shape_annotation(
        None,
        "hrect",
        {"x0": 1, "x1": 2, "y0": 3, "y1": 4},
        {"annotation_text": "abc"}
    ); out = codeflash_output

def test_annotation_with_none_fields_filled():
    # If annotation dict has None for xanchor/yanchor, should fill them in
    anno = {"xanchor": None, "yanchor": None}
    codeflash_output = axis_spanning_shape_annotation(
        anno,
        "hline",
        {"x0": 0, "x1": 10, "y0": 5, "y1": 5},
        {}
    ); out = codeflash_output

def test_rect_inside_only():
    # "inside" position only
    codeflash_output = axis_spanning_shape_annotation(
        None,
        "hrect",
        {"x0": 1, "x1": 2, "y0": 3, "y1": 4},
        {"annotation_position": "inside"}
    ); out = codeflash_output

def test_rect_outside_right():
    codeflash_output = axis_spanning_shape_annotation(
        None,
        "vrect",
        {"x0": 1, "x1": 2, "y0": 3, "y1": 4},
        {"annotation_position": "outside right"}
    ); out = codeflash_output

def test_line_left_right_positions():
    # vline left/right positions
    codeflash_output = axis_spanning_shape_annotation(
        None,
        "vline",
        {"x0": 1, "x1": 1, "y0": 0, "y1": 10},
        {"annotation_position": "left"}
    ); out_left = codeflash_output
    codeflash_output = axis_spanning_shape_annotation(
        None,
        "vline",
        {"x0": 1, "x1": 1, "y0": 0, "y1": 10},
        {"annotation_position": "right"}
    ); out_right = codeflash_output

def test_line_top_bottom_positions():
    # hline top/bottom positions
    codeflash_output = axis_spanning_shape_annotation(
        None,
        "hline",
        {"x0": 0, "x1": 10, "y0": 5, "y1": 5},
        {"annotation_position": "top"}
    ); out_top = codeflash_output
    codeflash_output = axis_spanning_shape_annotation(
        None,
        "hline",
        {"x0": 0, "x1": 10, "y0": 5, "y1": 5},
        {"annotation_position": "bottom"}
    ); out_bottom = codeflash_output

def test_line_position_case_insensitive():
    # Should be case sensitive, so "Top Right" is invalid
    with pytest.raises(ValueError):
        axis_spanning_shape_annotation(
            None,
            "vline",
            {"x0": 1, "x1": 1, "y0": 0, "y1": 10},
            {"annotation_position": "Top Right"}
        )

# ----------------------- LARGE SCALE TEST CASES -----------------------

def test_large_number_of_kwargs():
    # Should handle a large number of unrelated kwargs
    kwargs = {f"foo{i}": i for i in range(500)}
    kwargs.update({"annotation_text": "big", "annotation_position": "top"})
    codeflash_output = axis_spanning_shape_annotation(
        None,
        "vline",
        {"x0": 1, "x1": 1, "y0": 0, "y1": 10},
        kwargs
    ); out = codeflash_output

def test_large_shape_args_range():
    # Should work for large coordinate values
    codeflash_output = axis_spanning_shape_annotation(
        None,
        "hrect",
        {"x0": 0, "x1": 999, "y0": 0, "y1": 999},
        {"annotation_position": "inside"}
    ); out = codeflash_output

def test_many_annotations_in_loop():
    # Should not leak state between calls, and should be fast for many calls
    # (but keep below 1000 for performance)
    for i in range(250):
        codeflash_output = axis_spanning_shape_annotation(
            None,
            "vrect" if i % 2 == 0 else "hrect",
            {"x0": i, "x1": i+2, "y0": i*2, "y1": i*2+4},
            {"annotation_position": "inside top right", "annotation_text": f"anno{i}"}
        ); out = codeflash_output

def test_large_annotation_dict():
    # Should handle a large annotation dict with many fields
    anno = {f"field{i}": i for i in range(500)}
    codeflash_output = axis_spanning_shape_annotation(
        anno,
        "hline",
        {"x0": 0, "x1": 10, "y0": 5, "y1": 5},
        {"annotation_position": "top"}
    ); out = codeflash_output
    # All other fields preserved
    for i in range(500):
        pass

def test_performance_many_calls():
    # Should not be too slow for many calls (not a strict timing test)
    for i in range(500):
        codeflash_output = axis_spanning_shape_annotation(
            None,
            "hline",
            {"x0": i, "x1": i+1, "y0": i*2, "y1": i*2},
            {"annotation_position": "top right"}
        ); out = codeflash_output
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.

To edit these changes git checkout codeflash/optimize-axis_spanning_shape_annotation-mb2cxlx3 and push.

Codeflash

Here is an optimized version of your program for runtime and memory efficiency, while preserving function names, signatures, and return values, and keeping comments where logical code blocks are changed. Optimizations focused on.

- **Minimize temporary list allocations** (especially `min([x0, x1])`, replace with `min(x0, x1)` etc).
- **Optimize set constructions** for position comparison (avoid repeated creation of temporary sets and repeated split operations).
- **Micro-optimize by inlining very cheap computations** or removing duplicates.
- **Precompute reused results** when necessary.
- **Use for-loops instead of repeated if-elif** chains when the possible positions are known and stable.




**Summary of changes:**
- **Avoid redundant temporary lists/sets**: using `min(x0, x1)` over `[x0, x1]`, tuple for coordinates for less allocation, `frozenset` to enable O(1) mapping lookups.
- **Speed up if-elif blocks**: use a mapping keyed by `frozenset(position_set)` that's much quicker than a sequential if-elif chain.
- **Reduce dictionary calls and lookups**.
- **Reduce function call overhead and unnecessary lambdas/filter**.

All code functionality and return values remain unchanged.
@codeflash-ai codeflash-ai bot added the ⚡️ codeflash Optimization PR opened by Codeflash AI label May 24, 2025
@codeflash-ai codeflash-ai bot requested a review from misrasaurabh1 May 24, 2025 15:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
⚡️ codeflash Optimization PR opened by Codeflash AI
Projects
None yet
Development

Successfully merging this pull request may close these issues.

0 participants