Reputation: 692
I am using matplotlib to plot a series of horizontal lines that overlap. I would like to indicate (in a very rough way) how much overlap there is via transparency. For example if I have ten lines and 5 of them overlap over a certain interval, I would like that interval to have an alpha value of 0.5. If all of them overlap over a certain interval then the interval should have an alpha value of 1.0. The following code should illustrate what I want:
import matplotlib.pyplot as plt
y = [1,1,1,1,1,1,1,1,1,1]
x_start = [0,0,0,0,0,0,0,0,0,0]
x_end = [1,2,3,4,5,6,7,8,9,10]
plt.hlines(y, x_start, x_end, linewidth=7, colors='red', alpha=0.1)
plt.hlines(1.2, 0, 10, linewidth=7, colors='red', alpha=1)
plt.ylim(0.8, 1.4)
plt.show()
I would like the transparency of the red from x=0 to x=1 for the line at y=1 to be the same as that of the horizontal line at y=1.2 (not transparent at all). However this is not the case.
Is there a way to achieve what I want with matplotlib and the alpha values? I will know the total number of lines that can possibly overlap (i.e., how many lines overlapping should correspond to 0 transparency).
Upvotes: 3
Views: 3063
Reputation: 692
Thanks to @cphlewis who got me pointed in the right direction I now have an approximation that works well enough for my needs.
My problem is much easier than the general problem since I want to assign each line (layer) the exact same transparency level s
. If there are n=2
lines I want the transparency when both lines overlap to be close to 0, e.g. alpha=0.97
.
If n=2
and alpha=0.97
, solving
0.97 = s + s(1-s)
for s
yields s=0.827
.
Generalizing this for any n
leads to solving a polynomial where the coefficients are given by the n'th row of Pascal's triangle and where the sign of each coefficient is equal to
(-1)^(n + pos)
where pos
is the position of the coefficient in Pascal's triangle from left to right and where pos
starts at 1. Also, the last coefficient in Pascal's triangle is replaced with the desired alpha
value.
So for n=5
the polynomial to be solved is
s^5 - 5s^4 + 10s^3 - 10s^2 + 5s - 0.97 = 0
The following Python code solves for the smallest real root (which is the alpha
value that I want) given n
and alpha
(note that alpha < 1
).
import numpy as np
import scipy.linalg
num_lines = 5
end_alpha_value = 0.97 ## end_alpha_value must be in the interval (0, 1)
pascal_triangle = scipy.linalg.pascal(num_lines + 1, kind='lower')
print 'num_reps: 1, minimum real root: %.3f' % end_alpha_value
for i in range(2, num_lines + 1):
coeff_list = []
for j, coeff in enumerate(pascal_triangle[i][:i]):
coeff_list.append(coeff * ((-1)**(i+j+1)))
coeff_list.append(-end_alpha_value)
all_roots = np.roots(coeff_list)
real_roots = all_roots[np.isreal(all_roots)]
min_real_root = min(real_roots)
real_valued = min_real_root.real[abs(min_real_root.imag) < 1e-5]
print 'num_reps: %i, minimum real root: %.3f' % (i, real_valued[0])
For the case n=10
if the desired transparency is alpha=0.97
then s=0.296
resulting in the following output:
I believe what is going on shows up better using black as the color:
Upvotes: 3