Skip to content

⚡️ Speed up function convert_rgba_array by 65% #5244

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 2 commits into
base: main
Choose a base branch
from

Conversation

misrasaurabh1
Copy link

📄 65% (0.65x) speedup for convert_rgba_array in plotly/matplotlylib/mpltools.py

⏱️ Runtime : 5.66 milliseconds 3.44 milliseconds (best of 166 runs)

📝 Explanation and details

Here is a faster, more memory-efficient rewrite. This version avoids unnecessary list creation, uses list comprehensions for performance, and eliminates intermediate variables. The output is unchanged.

Changes:

  • Eliminated clean_color_list.
  • Used a single efficient list comprehension without intermediate dicts.
  • Switched .format to f-strings (faster in modern Python).
  • Preserved function signature and return value.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 46 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 100.0%
🌀 Generated Regression Tests Details
import pytest  # used for our unit tests
from plotly.matplotlylib.mpltools import convert_rgba_array

# unit tests

# 1. BASIC TEST CASES

def test_single_color_middle_values():
    # Test with a single color with mid-range values
    input_colors = [(0.5, 0.5, 0.5, 0.5)]
    expected = "rgba(127,127,127,0.5)"
    codeflash_output = convert_rgba_array(input_colors)

def test_single_color_all_zeros():
    # Test with a single color, all zeros (black, fully transparent)
    input_colors = [(0.0, 0.0, 0.0, 0.0)]
    expected = "rgba(0,0,0,0.0)"
    codeflash_output = convert_rgba_array(input_colors)

def test_single_color_all_ones():
    # Test with a single color, all ones (white, fully opaque)
    input_colors = [(1.0, 1.0, 1.0, 1.0)]
    expected = "rgba(255,255,255,1.0)"
    codeflash_output = convert_rgba_array(input_colors)

def test_multiple_colors_basic():
    # Test with two distinct colors
    input_colors = [(1.0, 0.0, 0.0, 1.0), (0.0, 1.0, 0.0, 0.5)]
    expected = ["rgba(255,0,0,1.0)", "rgba(0,255,0,0.5)"]
    codeflash_output = convert_rgba_array(input_colors)

def test_multiple_colors_varied():
    # Test with three colors, varying alpha and RGB
    input_colors = [
        (0.2, 0.4, 0.6, 0.8),
        (0.9, 0.1, 0.3, 0.2),
        (0.0, 0.0, 1.0, 1.0)
    ]
    expected = [
        "rgba(51,102,153,0.8)",
        "rgba(229,25,76,0.2)",
        "rgba(0,0,255,1.0)"
    ]
    codeflash_output = convert_rgba_array(input_colors)

# 2. EDGE TEST CASES

def test_empty_list():
    # Test with an empty list (should return an empty list)
    input_colors = []
    expected = []
    codeflash_output = convert_rgba_array(input_colors)

def test_minimal_alpha():
    # Test with alpha = 0.0 (fully transparent)
    input_colors = [(0.1, 0.2, 0.3, 0.0)]
    expected = "rgba(25,51,76,0.0)"
    codeflash_output = convert_rgba_array(input_colors)

def test_maximal_alpha():
    # Test with alpha = 1.0 (fully opaque)
    input_colors = [(0.1, 0.2, 0.3, 1.0)]
    expected = "rgba(25,51,76,1.0)"
    codeflash_output = convert_rgba_array(input_colors)

def test_floats_near_zero():
    # Test with values very close to zero
    input_colors = [(0.0001, 0.0002, 0.0003, 0.0004)]
    expected = "rgba(0,0,0,0.0004)"
    codeflash_output = convert_rgba_array(input_colors)

def test_floats_near_one():
    # Test with values very close to one
    input_colors = [(0.9999, 0.9998, 0.9997, 0.9996)]
    expected = "rgba(254,254,254,0.9996)"
    codeflash_output = convert_rgba_array(input_colors)

def test_rounding_down():
    # Test that values just below .5 round down
    input_colors = [(0.499, 0.499, 0.499, 0.5)]
    expected = "rgba(127,127,127,0.5)"
    codeflash_output = convert_rgba_array(input_colors)

def test_rounding_up():
    # Test that values just above .5 round up
    input_colors = [(0.501, 0.501, 0.501, 0.5)]
    expected = "rgba(127,127,127,0.5)"
    codeflash_output = convert_rgba_array(input_colors)

def test_alpha_precision():
    # Test that alpha is preserved as a float, not rounded
    input_colors = [(0.1, 0.2, 0.3, 0.123456)]
    expected = "rgba(25,51,76,0.123456)"
    codeflash_output = convert_rgba_array(input_colors)

def test_input_tuple_length():
    # Test with invalid input: tuple of wrong length
    input_colors = [(0.1, 0.2, 0.3)]  # missing alpha
    with pytest.raises(IndexError):
        convert_rgba_array(input_colors)

def test_input_value_out_of_range():
    # Test with values outside [0, 1] -- should not clamp, just multiply
    input_colors = [(-0.1, 1.2, 0.5, 1.5)]
    expected = "rgba(-25,306,127,1.5)"
    codeflash_output = convert_rgba_array(input_colors)

def test_input_non_float_values():
    # Test with integer input values (should work, as int * 255 is valid)
    input_colors = [(1, 0, 0, 1)]
    expected = "rgba(255,0,0,1)"
    codeflash_output = convert_rgba_array(input_colors)

def test_input_as_list_instead_of_tuple():
    # Test with color as a list instead of a tuple
    input_colors = [[0.1, 0.2, 0.3, 0.4]]
    expected = "rgba(25,51,76,0.4)"
    codeflash_output = convert_rgba_array(input_colors)



def test_large_number_of_colors():
    # Test with 1000 colors, all unique
    input_colors = [(i/1000, (1000-i)/1000, (i%256)/255, (i%100)/100) for i in range(1000)]
    codeflash_output = convert_rgba_array(input_colors); result = codeflash_output

def test_large_all_same_color():
    # Test with 1000 identical colors
    input_colors = [(0.1, 0.2, 0.3, 0.4)] * 1000
    codeflash_output = convert_rgba_array(input_colors); result = codeflash_output

def test_large_all_different_alpha():
    # Test with 1000 colors, all different alpha
    input_colors = [(0.5, 0.5, 0.5, i/1000) for i in range(1000)]
    codeflash_output = convert_rgba_array(input_colors); result = codeflash_output

def test_large_extreme_values():
    # Test with 1000 colors, alternating extreme values
    input_colors = []
    for i in range(1000):
        if i % 2 == 0:
            input_colors.append((0.0, 0.0, 0.0, 0.0))
        else:
            input_colors.append((1.0, 1.0, 1.0, 1.0))
    codeflash_output = convert_rgba_array(input_colors); 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.matplotlylib.mpltools import convert_rgba_array

# unit tests

# ----------- Basic Test Cases -----------

def test_single_color_basic():
    # Test with a single RGBA color
    input_color = [(1.0, 0.0, 0.0, 0.5)]  # Red, half transparent
    expected = "rgba(255,0,0,0.5)"
    codeflash_output = convert_rgba_array(input_color)

def test_multiple_colors_basic():
    # Test with multiple RGBA colors
    input_colors = [
        (1.0, 0.0, 0.0, 1.0),  # Red, opaque
        (0.0, 1.0, 0.0, 0.5),  # Green, half transparent
        (0.0, 0.0, 1.0, 0.0)   # Blue, fully transparent
    ]
    expected = [
        "rgba(255,0,0,1.0)",
        "rgba(0,255,0,0.5)",
        "rgba(0,0,255,0.0)"
    ]
    codeflash_output = convert_rgba_array(input_colors)

def test_single_color_full_black():
    # Test with a single black color, fully opaque
    input_color = [(0.0, 0.0, 0.0, 1.0)]
    expected = "rgba(0,0,0,1.0)"
    codeflash_output = convert_rgba_array(input_color)

def test_single_color_full_white():
    # Test with a single white color, fully opaque
    input_color = [(1.0, 1.0, 1.0, 1.0)]
    expected = "rgba(255,255,255,1.0)"
    codeflash_output = convert_rgba_array(input_color)

def test_single_color_no_alpha():
    # Test with a single color, fully transparent
    input_color = [(0.5, 0.5, 0.5, 0.0)]
    expected = "rgba(127,127,127,0.0)"
    codeflash_output = convert_rgba_array(input_color)

def test_alpha_precision():
    # Test with an alpha value with more decimal places
    input_color = [(0.2, 0.4, 0.6, 0.333333)]
    expected = "rgba(51,102,153,0.333333)"
    codeflash_output = convert_rgba_array(input_color)

def test_multiple_colors_varied_alpha():
    # Test with multiple colors and varied alpha values
    input_colors = [
        (0.1, 0.2, 0.3, 0.0),
        (0.4, 0.5, 0.6, 0.5),
        (0.7, 0.8, 0.9, 1.0)
    ]
    expected = [
        "rgba(25,51,76,0.0)",
        "rgba(102,127,153,0.5)",
        "rgba(178,204,229,1.0)"
    ]
    codeflash_output = convert_rgba_array(input_colors)

# ----------- Edge Test Cases -----------

def test_empty_list():
    # Test with an empty list
    input_colors = []
    expected = []
    codeflash_output = convert_rgba_array(input_colors)

def test_minimal_channel_values():
    # Test with channels at their minimum (0.0)
    input_color = [(0.0, 0.0, 0.0, 0.0)]
    expected = "rgba(0,0,0,0.0)"
    codeflash_output = convert_rgba_array(input_color)

def test_maximal_channel_values():
    # Test with channels at their maximum (1.0)
    input_color = [(1.0, 1.0, 1.0, 1.0)]
    expected = "rgba(255,255,255,1.0)"
    codeflash_output = convert_rgba_array(input_color)

def test_channel_rounding_down():
    # Test rounding down for float to int conversion
    input_color = [(0.499, 0.499, 0.499, 1.0)]
    expected = "rgba(127,127,127,1.0)"  # int(0.499*255) == 127
    codeflash_output = convert_rgba_array(input_color)

def test_channel_rounding_up():
    # Test rounding up for float to int conversion
    input_color = [(0.501, 0.501, 0.501, 1.0)]
    expected = "rgba(127,127,127,1.0)"  # int(0.501*255) == 127
    codeflash_output = convert_rgba_array(input_color)

def test_alpha_as_int():
    # Test with alpha as an integer (should still work)
    input_color = [(0.1, 0.2, 0.3, 1)]
    expected = "rgba(25,51,76,1)"
    codeflash_output = convert_rgba_array(input_color)

def test_alpha_as_string():
    # Test with alpha as a string (should be preserved as string)
    input_color = [(0.1, 0.2, 0.3, "0.7")]
    expected = "rgba(25,51,76,0.7)"
    codeflash_output = convert_rgba_array(input_color)

def test_negative_channel_values():
    # Test with negative channel values (should convert to negative ints)
    input_color = [(-0.1, -0.2, -0.3, 0.5)]
    expected = "rgba(-25,-51,-76,0.5)"
    codeflash_output = convert_rgba_array(input_color)

def test_channel_values_above_one():
    # Test with channel values above 1.0 (should convert to >255)
    input_color = [(1.1, 1.2, 1.3, 0.5)]
    expected = "rgba(280,306,331,0.5)"
    codeflash_output = convert_rgba_array(input_color)

def test_alpha_out_of_range():
    # Test with alpha < 0 or > 1 (should be preserved as is)
    input_colors = [
        (0.5, 0.5, 0.5, -0.1),
        (0.5, 0.5, 0.5, 1.1)
    ]
    expected = [
        "rgba(127,127,127,-0.1)",
        "rgba(127,127,127,1.1)"
    ]
    codeflash_output = convert_rgba_array(input_colors)

def test_non_tuple_input():
    # Test with a list instead of tuple for color
    input_color = [[0.1, 0.2, 0.3, 0.5]]
    expected = "rgba(25,51,76,0.5)"
    codeflash_output = convert_rgba_array(input_color)


def test_input_with_less_than_four_elements():
    # Test with a color tuple with less than 4 elements (should raise error)
    input_color = [(0.1, 0.2, 0.3)]
    with pytest.raises(IndexError):
        convert_rgba_array(input_color)


def test_input_with_nested_lists():
    # Test with nested list of colors
    input_colors = [[(0.1, 0.2, 0.3, 0.5), (0.4, 0.5, 0.6, 0.7)]]
    # Should raise error because the function expects a flat list
    with pytest.raises(TypeError):
        convert_rgba_array(input_colors)

def test_input_with_none():
    # Test with None as input
    with pytest.raises(TypeError):
        convert_rgba_array(None)

# ----------- Large Scale Test Cases -----------

def test_large_list_of_colors():
    # Test with a large list of colors (1000 elements)
    input_colors = [(i/999, (999-i)/999, 0.5, 0.5) for i in range(1000)]
    # Each color should be mapped to an rgba string
    expected = [
        "rgba({},{},{},{})".format(
            int(i/999*255),
            int((999-i)/999*255),
            int(0.5*255),
            0.5
        ) for i in range(1000)
    ]
    codeflash_output = convert_rgba_array(input_colors); result = codeflash_output

def test_large_list_all_same_color():
    # Test with a large list of the same color
    input_colors = [(0.1, 0.2, 0.3, 0.4)] * 1000
    expected = ["rgba(25,51,76,0.4)"] * 1000
    codeflash_output = convert_rgba_array(input_colors); result = codeflash_output

def test_large_list_varied_alpha():
    # Test with a large list with varying alpha values
    input_colors = [(0.5, 0.5, 0.5, i/999) for i in range(1000)]
    expected = [
        "rgba(127,127,127,{})".format(i/999) for i in range(1000)
    ]
    codeflash_output = convert_rgba_array(input_colors); result = codeflash_output

def test_large_list_edge_channel_values():
    # Test with a large list with edge channel values
    input_colors = [(1.0, 0.0, 0.0, 1.0)] * 500 + [(0.0, 1.0, 0.0, 0.0)] * 500
    expected = ["rgba(255,0,0,1.0)"] * 500 + ["rgba(0,255,0,0.0)"] * 500
    codeflash_output = convert_rgba_array(input_colors); 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.

Codeflash

codeflash-ai bot and others added 2 commits May 21, 2025 07:56
Here is a faster, more memory-efficient rewrite. This version avoids unnecessary list creation, uses list comprehensions for performance, and eliminates intermediate variables. The output is unchanged.


**Changes:**
- Eliminated `clean_color_list`.
- Used a single efficient list comprehension without intermediate dicts.
- Switched `.format` to f-strings (faster in modern Python).
- Preserved function signature and return value.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant