Skip to content
Advertisement

Control the facecolor of histograms

In the following histogram,

import numpy as np
import matplotlib.pyplot as plt
tinter = [0.8253909999999998, 0.8804020000000001, 0.14202099999999973, 0.7727520000000005, 1.1040220000000005, 0.10714699999999944, 0.5750040000000016, 0.7876929999999973, 0.8980040000000002, 1.1478490000000008, 0.44635099999999994, 1.052067000000001, 0.4327469999999991, 0.3272960000000005, 0.26918099999999967, 0.3854459999999982, 0.1827140000000007, 0.8867760000000011, 0.7774879999999982, 0.21082900000000038, 0.6758939999999996, 0.4335760000000022, 0.6791699999999992, 0.7758439999999993, 0.15755200000000258, 0.1414289999999987, 0.36975599999999886, 0.8993549999999999, 0.6577640000000002, 1.043728999999999, 0.19952800000000082, 0.12645200000000045, 0.3454990000000002, 0.9054520000000004, 0.7165229999999987, 0.9425269999999983, 0.7159280000000052, 0.7413279999999958, 0.12669900000000212, 0.2822880000000012, 0.3690029999999993, 0.7246340000000018, 0.4718329999999966, 0.7580859999999987, 0.744059, 0.19344999999999857, 0.12031900000000206, 0.47543600000000197, 0.437542999999998, 0.44232000000000227, 0.5250109999999992, 0.17673200000000122, 0.2440649999999991, 0.31524799999999686, 0.7674680000000009, 0.7837700000000041, 1.1910290000000003, 0.14404899999999543, 0.21560399999999902, 0.19931500000000568, 0.27113699999999596, 0.728234999999998, 0.5061920000000057, 0.6459329999999994, 0.7817450000000008, 0.8265129999999985, 0.17931199999999592, 0.30208600000000274, 0.32583699999999993, 0.41771599999999864]
n, bins, patches = plt.hist(x=tinter, bins='auto', color='#0504aa',
                            alpha=0.7, rwidth=0.9,)
plt.grid(axis='y', alpha=0.35)
plt.xlabel('time [s]')
plt.ylabel('Frequency')
plt.title('Hit interval')

enter image description here

I would like to set two different colors for the bars of the histogram. There is a precedent question (this link), but the solution sets the bars’ colors in a range, e.g., bars 0 to 3 of one color.

This is a different problem since I would like to differentiate two zones in the histogram in general. I do not exactly how the particular histogram is and how many bars are. In the example above, the separation of colors should be at 0.6: left of time=0.6s of one color and right of time=0.6 of another. If it is not possible to make a bar of two colors (in the example, a range of time values is covered in the bar including 0.6), the separation of colors should go from the lowest bar in the example (bar of time=0.2) to the bar of time=0.6 included. And, in the example, the last four bars (above time=0.6s) of another color.

For example, in this example the values of n and bins that gives ‘plt.hist()` are:

n = array([16., 11., 10.,  3., 16.,  8.,  3.,  3.])
bins=array([0.107147  , 0.24263225, 0.3781175 , 0.51360275, 0.649088  , 0.78457325, 0.9200585 , 1.05554375, 1.191029  ])

I would like bars with n 16, 11, 10 and 3 of one color different of the other group of bars with n 16, 8, 3,3, and make it for a general histogram plot.

Advertisement

Answer

You could loop through the bars and test whether it is completely to the right of the separation, completely to the left or crosses it. You change the bar’s color correspondingly.

When a bar crosses the separator, the bar gets the color for the left area and its size is narrowed to touch the separator. A copy of the bar can be added, with the right-area color and its x-position moved.

import matplotlib.pyplot as plt
import numpy as np
from copy import copy

tinter = [0.82539, 0.8804, 0.14202, 0.77275, 1.10402, 0.10715, 0.575, 0.78769, 0.898, 1.14785, 0.44635, 1.05207, 0.43275, 0.3273, 0.26918, 0.38545, 0.18271, 0.88678, 0.77749, 0.21083, 0.67589, 0.43358, 0.67917, 0.77584, 0.15755, 0.14143, 0.36976, 0.89935, 0.65776, 1.04373, 0.19953, 0.12645, 0.3455, 0.90545, 0.71652, 0.94253, 0.71593, 0.74133, 0.1267, 0.28229, 0.369, 0.72463, 0.47183, 0.75809, 0.74406, 0.19345, 0.12032, 0.47544, 0.43754, 0.44232, 0.52501, 0.17673, 0.24406, 0.31525, 0.76747, 0.78377, 1.19103, 0.14405, 0.2156, 0.19932, 0.27114, 0.72823, 0.50619, 0.64593, 0.78175, 0.82651, 0.17931, 0.30209, 0.32584, 0.41772]
n, bins, patches = plt.hist(x=tinter, bins='auto', color='#0504aa', alpha=0.7, rwidth=0.9)
plt.grid(axis='y', alpha=0.35)
plt.xlabel('time [s]')
plt.ylabel('Frequency')
plt.title('Hit interval')
separator = 0.6
left_color = 'turquoise'
right_color = 'tomato'
for bar in patches:
    x, y = bar.get_xy()
    w = bar.get_width()
    if x > separator:
        bar.set_color(right_color)
    else:
        bar.set_color(left_color)
        if x + w > separator:
            bar.set_width(separator-x)
            new_bar = copy(bar)
            new_bar.set_x(separator)
            new_bar.set_width(x+w-separator)
            new_bar.set_color(right_color)
            plt.gca().add_patch(new_bar)
plt.show()

histogram with two colors

If you want the complete bar that contains the separator value to be one color, you can leave out the block below if x + w > separator:.

n, bins, patches = plt.hist(x=tinter, bins='auto', color='#0504aa', alpha=0.7, rwidth=0.9)
plt.grid(axis='y', alpha=0.35)
plt.xlabel('time [s]')
plt.ylabel('Frequency')
plt.title('Hit interval')
separator = 0.6
left_color = 'turquoise'
right_color = 'tomato'
for bar in patches:
    x, y = bar.get_xy()
    w = bar.get_width()
    if x > separator:
        bar.set_color(right_color)
    else:
        bar.set_color(left_color)
plt.show()

histogram with two colors without splitting

User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement