Search code examples
pythonmatplotlibprobability

Matplotlib graphing distribution with two colors


The goal here is to color value above a certain threshold into one color and values below this threshold into another color. The code below tries to just separate it into two histographs but it only looks balanced if the threshold is at 50%. I'm assuming I must play around with the discreetlevel variable.

finalutilityrange is some vector with a bunch of values(you must generate it to test the code), which I am trying to graph. The value deter is the value that determines whether they will be blue or red. discreetlevel is just the amount of bins I would want.

import random
import numpy as np
import matplotlib.pyplot as plt

discreetlevel = 10
deter = 2

for x in range(0,len(finalutilityrange)):
    if finalutilityrange[x-1]>=deter:
        piraterange.append(finalutilityrange[x-1])
    else:
        nonpiraterange.append(finalutilityrange[x-1])

plt.hist(piraterange,bins=discreetlevel,normed=False,cumulative=False,color = 'b')
plt.hist(nonpiraterange,bins=discreetlevel),normed=False,cumulative=False,color = 'r')
plt.title("Histogram")
plt.xlabel("Utlity")
plt.ylabel("Probability")
plt.show()

Solution

  • This solution is a bit more complex than @user2699's. I am just presenting it for completeness. You have full control over the patch objects that hist returns, so if you can ensure that the threshold you are using is exactly on a bin edge, it is easy to change to color of selected patches. You can do this because hist can accept a sequence of bin edges as the bins parameter.

    import numpy as np
    from matplotlib import pyplot as plt 
    
    # Make sample data
    finalutilityrange = np.random.randn(100)
    discreetlevel = 10
    deter = 0.2
    
    # Manually create `discreetlevel` bins anchored to  `deter`
    binsAbove = round(discreetlevel * np.count_nonzero(finalutilityrange > deter) / finalutilityrange.size)
    binsBelow = discreetlevel - binsAbove
    binwidth = max((finalutilityrange.max() - deter) / binsAbove,
                   (deter - finalutilityrange.min()) / binsBelow)
    bins = np.concatenate([
               np.arange(deter - binsBelow * binwidth, deter, binwidth),
               np.arange(deter, deter + (binsAbove + 0.5) * binwidth, binwidth)
    ])
    
    # Use the bins to make a single histogram
    h, bins, patches = plt.hist(finalutilityrange, bins, color='b')
    
    # Change the appropriate patches to red
    plt.setp([p for p, b in zip(patches, bins) if b >= deter], color='r')
    

    The result is a homogenous histogram with bins of different colors:

    enter image description here

    The bins may be a tad wider than if you did not anchor to deter. Either the first or last bin will generally go a little past the edge of the data.