Matplotlib graphing distribution with two colors

Question:

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()
Asked By: Dio

||

Answers:

This answer doesn’t address your code since it isn’t self-contained, but for what you’re trying to do the default histogram should work (assuming numpy/pyplot is loaded)

x = randn(100)
idx = x < 0.2 # Threshold to separate values
hist([x[idx], x[~idx]], color=['b', 'r'])

Explanation:

  1. first line just generates some random data to test,
  2. creates an index for where the data is below some threshold, this can be negated with ~ to find where it’s above the threshold
  3. Last line plots the histogram. The command takes a list of separate groups to plot, which doesn’t make a big difference here but if normed=True it will

There’s more the hist plot can do, so look over the documentation before you accidentally implement it yourself.

Answered By: user2699

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.

Answered By: Mad Physicist

Just as above do:

x = np.random.randn(100)
threshold_x = 0.2 # Threshold to separate values

x_lower, x_upper = (
    [_ for _ in x if _ < threshold_x], 
    [_ for _ in x if _ >= threshold_x]
)

hist([x_lower, x_upper], color=['b', 'r'])
Answered By: Krotonix
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.