0

This is a followup question to below link answered by @JohanC.

Credits to (https://stackoverflow.com/users/12046409/johanc):

Python: Filling colors between curves and axes & to regionalize the areas

How do I plot a curve in between the red and blue curves by equidistant to both? I tried by improvising the codes but the green curve is skewed to the red curve due to logspace.


import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
from scipy import interpolate

xmin, xmax = 2000, 7000
ymin, ymax = 10, 50000
# a grid of 6 x,y coordinates for both curves
x_grid = np.array([2000, 3000, 4000, 5000, 6000, 7000])
y_blue_grid = np.array([15, 100, 200, 300, 400, 500])
y_red_grid = np.array([20, 400, 10000, 500000, 500000, 500000])
y_avg_grid = np.array([17.5, 250, 5100, 250150, 250200, 250250])

# create interpolating curves in logspace
tck_red = interpolate.splrep(x_grid, np.log(y_red_grid), s=0)
tck_blue = interpolate.splrep(x_grid, np.log(y_blue_grid), s=0)
tck_avg = interpolate.splrep(x_grid, np.log(y_avg_grid), s=0)
x = np.linspace(xmin, xmax)
yr = np.exp(interpolate.splev(x, tck_red, der=0))
yb = np.exp(interpolate.splev(x, tck_blue, der=0))
yavg = np.exp(interpolate.splev(x, tck_avg, der=0))



# create the background image; it is created fully in logspace
# the background (z) is zero between the curves, negative in the blue zone and positive in the red zone
# the values are close to zero near the curves, gradually increasing when they are further
xbg = np.linspace(xmin, xmax, 50)
ybg = np.linspace(np.log(ymin), np.log(ymax), 50)
z = np.zeros((len(ybg), len(xbg)), dtype=float)
for i, xi in enumerate(xbg):
    yi_r = interpolate.splev(xi, tck_red, der=0)
    yi_b = interpolate.splev(xi, tck_blue, der=0)
#    yi_avg = interpolate.splev(xi, tck_avg, der=0)
    for j, yj in enumerate(ybg):
        if yi_b >= yj:
            z[j][i] = (yj - yi_b)
        elif yi_r <= yj:
            z[j][i] = (yj - yi_r)

fig, ax2 = plt.subplots(figsize=(8, 8))

# draw the background image, set vmax and vmin to get the desired range of colors;
# vmin should be -vmax to get the white at zero
ax2.imshow(z, origin='lower', extent=[xmin, xmax, np.log(ymin), np.log(ymax)], aspect='auto', cmap='bwr', vmin=-12, vmax=12, interpolation='bilinear', zorder=-2)
ax2.set_ylim(ymin=np.log(ymin), ymax=np.log(ymax)) # the image fills the complete background
ax2.set_yticks([]) # remove the y ticks of the background image, they are confusing
ax = ax2.twinx()  # draw the main plot using the twin y-axis
ax.set_yscale('log')
ax.plot(x, yr, label="Warm", color='crimson')
ax.plot(x, yb, label="Blue", color='dodgerblue')
ax.plot(x, yavg, label="Comfort", color='green')
ax2.set_xlabel('Color Temperature (K)')
ax.set_ylabel('Illuminance (lux)')
ax.set_title('Kruithof Curve',fontsize=16)
ax.legend()
ax.set_xlim(xmin=xmin, xmax=xmax)
ax.set_ylim(ymin=ymin, ymax=ymax)
ax.grid(True, which='major', axis='y')
ax.grid(True, which='minor', axis='y', ls=':')
ax.yaxis.tick_left() # switch the twin axis to the left
ax.yaxis.set_label_position('left')
ax2.grid(True, which='major', axis='x')
ax2.xaxis.set_major_formatter(mticker.StrMethodFormatter('{x:.0f}')) # show x-axis in Kelvin
ax.text(5000, 2000, 'Pleasing', fontsize=16)
ax.text(5000, 20, 'Appears bluish', fontsize=16)
ax.text(2300, 15000, 'Appears reddish', fontsize=16)
plt.show()


Output:

enter image description here

The desired output is as below, i.e. to get a yellow line. The yellow line is not for a graphical purpose only, but I also need the values for further use.

enter image description here

Thank you.

siva
  • 2,105
  • 4
  • 20
  • 37
  • What is your definition of equidistant? Because there are different ways that this is possible. – SKPS Feb 17 '20 at 20:40
  • I would recommend posting this question to math.stackexchange.com – SKPS Feb 17 '20 at 20:43
  • @SKPS hi. by equidistant, I mean, centered in between the red and blue curves. – siva Feb 18 '20 at 02:00
  • 1
    As per your logic, the equidistant curve will be weirdly skewed up around 4500K. Best option would be moving a circle of varying radii between curves. I would recommend reading [this](https://www.mathcurve.com/courbes2d.gb/equidistance/equidistance.shtml). – SKPS Feb 18 '20 at 02:42
  • I realize this is grave digging, but I have a very similar problem. I understand that the this so-called equdistant or middle curve goes through the centers of the circles, tangent to both curves. But I don't have even the slightet idea how to start to code this in Python. – user2882635 Apr 20 '21 at 12:26

0 Answers0