Dio
Dio

Reputation: 241

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()

Upvotes: 4

Views: 2764

Answers (3)

Krotonix
Krotonix

Reputation: 25

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'])

Upvotes: 0

Mad Physicist
Mad Physicist

Reputation: 114320

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.

Upvotes: 5

user2699
user2699

Reputation: 3147

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.

Upvotes: 1

Related Questions