Home > Enterprise >  Fill radial bars of barplot with gradient
Fill radial bars of barplot with gradient

Time:12-21

I am trying to generate a radial (circular) barplot displaying various color ranges in order to compare them. Using a radial barplot allows to better apprehend the circular nature of the hue value and to represent out-of-range ranges such as [340°, 10°]

To illustrate with this image, the idea is to replace the black color of the bars of the barplot on the left by the parts of the chromatic circle (displayed on the right) corresponding. Radial barplot and color wheel

This is the code that I use to generate the radial barplot :

import matplotlib.pyplot as plt
from numpy import pi

start_values = [0, 3*pi/4, pi/6]
range_values = [pi/3, 3*pi/10, pi/2]

ax = plt.subplot(projection='polar')

for i in range(len(start_values)):
    ax.barh(i, range_values[i], left=start_values[i], color=(0, 0, 0))

I wanted to apply Matplotlib's hsv color map but the color parameter of barh() does not accept it.

On the internet I have only found techniques to apply gradients or cmaps to regular barplots, with rectangular bars (like this one: output

CodePudding user response:

Thanks Pierre, I used your technique to build a graph that also represents saturation and value as a gradient in the direction of the radius. Here is what it returns for the example given (with saturation and value ranges added)

Code:

figure, axes = plt.subplots(2, 2, figsize=(10, 20))

def radius_barplot(lower_color, upper_color, ax, index=None, angle_precision=1, hue_only=0.1):
    if index is None: index = range(len(lower_color[0]))
    ax = plt.subplot(projection='polar')
    pi2 = 2*pi
    full_color = 1 - hue_only

    for i, frame in enumerate(index):

        #print("Frame n°", i 1, sep='')
        min_hue, max_hue = lower_color[0][frame] / 179 * 2 * pi, upper_color[0][frame] / 179 * 2 * pi
        min_sat, min_val = lower_color[1][frame] / 255, lower_color[2][frame] / 255
        range_hue, range_sat, range_val = max_hue - min_hue, round(upper_color[1][frame] - lower_color[1][frame]), round(upper_color[2][frame] - lower_color[2][frame])
        n_height = min(max(range_sat, range_val), 20)
        pas_height = 1*full_color/n_height
        large_pas_angle, large_pas_height = angle_precision*1.5/180*pi, pas_height*1.25
        pas_sat, pas_val = range_sat / 255 / n_height, range_val / 255 / n_height

        #print("Angle range: [", round(min_hue/pi*180), "; ", round((max_hue)/pi*180), "]", sep='')
        
        # For each degree of the angle
        for angle in np.arange(min_hue, max_hue, angle_precision/180*pi):
            
            # To avoid an overflow on the end of the interval
            if angle   large_pas_angle > max_hue: large_pas_angle = max_hue - angle
                        
            # For each line inside the current bar
            for height in range(n_height):
                """
                print("Height: [", round(i   height*pas_height, 2), ", ", round(i   height*pas_height   pas_height, 2),
                      "], angle: ", round(angle/pi*180, 3),
                      "°: color [", round(angle*360), ", ", round((min_sat   height*pas_sat)*100), ", ", round((min_val   height*pas_val)*100), "]", sep='')
                """
                ax.barh(y=i   height*pas_height,
                        width=large_pas_angle, left=angle, height=large_pas_height, align='edge',
                        color=colorsys.hsv_to_rgb(angle/pi2,
                                                  min_sat   height*pas_sat,
                                                  min_val   height*pas_val)
                        )
            
            # To display the reference hue (with full saturation and value)
            ax.barh(y=i   full_color,
                    width=large_pas_angle, left=angle, height=hue_only, align='edge',
                    color=colorsys.hsv_to_rgb(angle/pi2, 1, 1)
                    )
            # """
        ax.set_rgrids(range(len(index)), labels=index)

# Execute the function with the example data
radius_barplot(
    ((0, (3*pi/4)/(2*pi)*179, (pi/6)/(2*pi)*179), (0, 200, 50), (0, 50, 200)),  # Minimal values of colors ranges
    (((pi/3)/(2*pi)*179, (21*pi/20)/(2*pi)*179, (2*pi/3)/(2*pi)*179), (255, 250, 100), (255, 100, 250)),  # Maximal values of colors ranges
               axes[0])

Graph:

Radius barplot for color range

The main problem of this technique is its complexity: returning this graph took 1 minute and 45 seconds on my computer and getting the graph I am interested in takes almost 5 minutes.

So if someone has a better, more optimal method to obtain a similar result I would still be interested.

  • Related