1

I am an aspiring programmer and I wanted to take out the brightest colors from the matplotlib CSS4 dictionary which can be reached with "print(matplotlib.colors.CSS4_COLORS". Can you please fix it?

def hex_to_rgb(hex):
    hex = hex.lstrip('#')
    lv = len(hex)
    return tuple(int(hex[i:i+lv//3], 16) for i in range(0, lv, lv//3))


for key, value in CSS4_COLORS.items():
    rgb = hex_to_rgb(value)
    rgb_average = (rgb[0] + rgb[1] + rgb[2]) / 3
    if rgb_average > 210:
        del CSS4_COLORS[key]

print(CSS4_COLORS)

It gives out the error:

RuntimeError: dictionary changed size during iteration

Sorry if this was answered before, I must have not understood then.

rdas
  • 20,604
  • 6
  • 33
  • 46
Gaul
  • 11
  • 1

1 Answers1

0

The error messages states what the problem is: it is not permitted to delete elements of a dictionary you are currently iterating over. You can find more on the reasoning behind this at this post, but the essence is that deleting an entry changes the 'iteration order', so you cannot simply continue iteration where you left off.

A simple way to solve this would be to duplicate the dictionary, iterating over the first and deleting entries from the second. Better yet is to use a dictionary comprehension to construct a new dictionary with only the elements of the old dictionary that have a low enough average.

def hex_to_rgb(hex):
    hex = hex.lstrip('#')
    lv = len(hex)
    return tuple(int(hex[i:i+lv//3], 16) for i in range(0, lv, lv//3))

def average(value):
    rgb = hex_to_rgb(value)
    return (rgb[0] + rgb[1] + rgb[2]) / 3

without_brightest = {key:value for key, value in CSS$_COLORS.items() if average(value) <= 210}
# The condition becomes the opposite, <= 210 instead of > 210, because we are deciding what to include instead of what to delete.

print(without_brightest)

This will yield the new dictionary excluding the bright values, and it will leave the original matplotlib dictionary intact.

If, for some reason, you need to modify the original dictionary instead of creating a new one, you can use the method mentioned previously of making a second dictionary to iterate over. You can make a shallow copy with dict.copy, which would change your second for loop to

for key, value in CSS4_COLORS.copy().items():
    rgb = hex_to_rgb(value)
    rgb_average = (rgb[0] + rgb[1] + rgb[2]) / 3
    if rgb_average > 210:
        del CSS4_COLORS[key]

This would create a new dictionary to iterate over, and modify the original. You should probably only use this method if you need the original modified and cannot simply assign another dictionary to it. You have to make a new dictionary object either way, so the first variant is preferable.

Hephaistos-plus
  • 156
  • 2
  • 9