rmaia / pavo

tools for the analysis of color data in R
http://pavo.colrverse.com
GNU General Public License v2.0
68 stars 17 forks source link

Simulate spectra (take 2) #247

Closed thomased closed 1 year ago

thomased commented 1 year ago

Fix https://github.com/rmaia/pavo/issues/151. Moving discussion here from #185 because I started from scratch after completely forgetting that you'd already had a go at it @Bisaloo, then tried to merge them & screwed everything up, so just started again here (I'll learn git one day...).

Stuff to to discuss (partly from #185):

Thoughts welcome!

Working example:

# Single sigmoidal spectrum, with an inflection at 500 nm.
spec <- as.rspec(simulate_spec2(wl.inflect = 500))

# Single Gaussian spectrum, with a peak at 400 nm
spec2 <- as.rspec(simulate_spec2(wl.peak = 400))

# Combination of both Gaussian (with peak at 340 nm) and sigmoidal (with inflection
# at 560 nm)
spec3 <- as.rspec(simulate_spec2(wl.peak = 340, wl.inflect = 560))

# Double-Gaussian peaks of differing widths
spec4 <- as.rspec(simulate_spec2(wl.peak = c(340, 560), width.gauss = c(12, 40)))

# Complex spectrim with multi-Gaussian and single sigmoidal peak
spec5 <- as.rspec(simulate_spec2(wl.peak = c(340, 430), width.gauss = c(20, 60), wl.inflect = 575))

# Merge and plot
spectra <- merge(spec, spec2)
spectra <- merge(spectra, spec3)
spectra <- merge(spectra, spec4)
spectra <- merge(spectra, spec5)
explorespec(spectra, ylim = c(0, 100))
Screenshot 2023-06-02 at 3 34 00 pm
thomased commented 1 year ago

Awesome, many thanks for those edits & your thoughts. I'm with you on all points — I'll keep adjusting things along those lines and we can see how we like it.

thomased commented 1 year ago

Latest examples, from the help docs:

# Single ideal 'grey' reflectance spectrum, with 50% reflectance across 300 - 700 nm.
reflect0 <- simulate_spec(ylim = c(0, 50))

# Single sigmoidal spectrum, with a low-to-high inflection at 550 nm.
reflect1 <- simulate_spec(wl_inflect = 550)

# Single Gaussian spectrum, with a peak at 400 nm
reflect2 <- simulate_spec(wl_peak = 400)

# Combination of both Gaussian (with peak at 340 nm) and sigmoidal (with inflection
# at 560 nm)
reflect3 <- simulate_spec(wl_inflect = 560, wl_peak = 340)

# Double-Gaussian peaks of differing widths
reflect4 <- simulate_spec(wl_peak = c(340, 560), width_gauss = c(12, 40))

# Complex spectrum with single sigmoidal peak and multi-Gaussian peaks
reflect5 <- simulate_spec(wl_inflect = 575, wl_peak = c(340, 430), width_gauss = c(20, 60))

# Merge and plot
spectra <- Reduce(merge, list(reflect0, reflect1, reflect2, reflect3, reflect4, reflect5))
plot(spectra, lty = 1:5)
Screenshot 2023-06-09 at 3 21 46 pm
# Simulate a set of Gaussian reflectance curves with peaks varying between 400-600nm
# in increments of 10, then combine into a single rspec object, and plot the result
peaks <- seq(400, 600, 10)  # Peak locations
reflectances <- lapply(seq_along(peaks), function(x) simulate_spec(wl_peak = peaks[x]))  # Simulate
reflectances <- Reduce(merge, reflectances)  # Combine
plot(reflectances)  # Plot
Screenshot 2023-06-09 at 3 22 41 pm
# Simulate a set of Gaussian reflectance curves with a single peak at 500 nm, but
# with maximum reflectance varying from 30 to 90% in 10% increments, then combine
# into a single rspec object, and plot the result
ymax <- lapply(seq(30, 90, 10), function(x) c(0, x))  # Varying reflectance maxima
reflectances2 <- lapply(ymax, function(x) simulate_spec(wl_peak = 500, ylim = x))  # Simulate
reflectances2 <- Reduce(merge, reflectances2)  # Combine
plot(reflectances2)  # Plot
Screenshot 2023-06-09 at 3 23 35 pm
# To simulate non-reflectance spectra (like irradiances or radiances), it's often useful
# to explore more 'extreme' parameters. Here's a simple example which simulates
# natural daylight, as represented by the D65 standard daylight spectrum.
D65_real <- procspec(sensdata(illum = 'D65'), opt = 'smooth')  # Official D65 daylight spectrum
D65_sim <- simulate_spec(wl_peak = 400,
                         width_gauss = 1300,
                         skew_gauss = 10,
                         ylim = c(0, 1))  # Simulated D65
cor.test(D65_real$D65, D65_sim$spec_p400)  # >0.99 correlation
plot(merge(D65_real, D65_sim), lty = 1:2, ylab = 'Irradiance (%)')  # Merge and plot the two spectra
Screenshot 2023-06-09 at 3 24 59 pm
thomased commented 1 year ago

Absolutely no rush at all @Bisaloo, but if you want to cast another eye over it sometime it'd be appreciated. I think I'm basically happy with where it's at - just about ready to merge. Can always do some further fine-tuning before the next release of course. And happy to hear alternative views on any of the above points - I've just jotted down my thinking.