Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Plot histogram using Python with different colors for positive and negative values

I did the following plot using Python:

import matplotlib.pyplot as plt
plt.hist([x*100 for x in relativeError], bins = 100)
plt.xlabel("Relative Error [%]")
plt.ylabel("#samples")
plt.axvline(x=0, linestyle='--',linewidth=1, color='grey')

enter image description here

But what I really want is to have different colors depending on whether the value is positive or negative.

like image 257
rocker996 Avatar asked Feb 18 '26 07:02

rocker996


2 Answers

You can just colorize the bars after the fact.

import numpy as np
import matplotlib.pyplot as plt

x = np.random.normal(-20, 15, 5000)

_, _, bars = plt.hist(x, bins = 100, color="C0")
for bar in bars:
    if bar.get_x() > 0:
        bar.set_facecolor("C1")
plt.xlabel("Relative Error [%]")
plt.ylabel("#samples")
plt.axvline(x=0, linestyle='--',linewidth=1, color='grey')
plt.show()

enter image description here

If instead you want to plot a bar chart of the histogrammed values (like the other answer suggests), it would rather look like

import numpy as np
import matplotlib.pyplot as plt

x = np.random.normal(-20, 15, 5000)

hist, edges = np.histogram(x, bins=100)

colors = np.array(["C0", "C1"])[(edges[:-1] > 0).astype(int)]
plt.bar(edges[:-1], hist, width=np.diff(edges), align="edge", color=colors)
plt.xlabel("Relative Error [%]")
plt.ylabel("#samples")
plt.axvline(x=0, linestyle='--',linewidth=1, color='grey')
plt.show()
like image 69
ImportanceOfBeingErnest Avatar answered Feb 19 '26 20:02

ImportanceOfBeingErnest


First, you need to compute the heights and positions of the bars for the histogram. Then, you you need to create a mask to filter the positive and negative data. Finally, you plot each of the subset of bars separately, and you set the colour at each call of the function plt.bar().

Example with fake data that looks like yours:

import matplotlib.pyplot as plt
import numpy as np

# generate fake data
N = 1000
data = np.random.normal(loc=-1, size=N) # with average -1

n_bins = 100
heights, bins, _ = plt.hist(data, bins=n_bins) # get positions and heights of bars

bin_width = np.diff(bins)[0]
bin_pos = bins[:-1] + bin_width / 2

plt.figure()

mask = (bin_pos >= 0)

# plot data in two steps
plt.bar(bin_pos[mask], heights[mask], width=bin_width, color='C1')
plt.bar(bin_pos[~mask], heights[~mask], width=bin_width, color='C0')

plt.xlabel("Relative Error [%]")
plt.ylabel("#samples")
plt.axvline(x=0, linestyle='--',linewidth=1, color='grey')

plt.show()

enter image description here

like image 21
presenter Avatar answered Feb 19 '26 19:02

presenter