fix(db): return data unchanged instead of NULL when no covariates found#4000
fix(db): return data unchanged instead of NULL when no covariates found#4000anshul23102 wants to merge 3 commits into
Conversation
arrhenius.scaling.traits() and filter_sunleaf_traits() both set
data <- NULL in their else-branch, contradicting the documented
behaviour ("data with no matching covariates will be unchanged").
When no temperature covariates exist for any observation, the correct
response is to return the input data unchanged (equivalent to assuming
all measurements were taken at missing.temp = 25 degC, making the
Arrhenius scaling a no-op). Returning NULL instead caused a hard crash
in query.trait.data() at nrow(NULL) whenever Vcmax, root_respiration_rate,
leaf_respiration_rate_m2, or stem_respiration_rate were queried for
species with no temperature covariate recorded in BETYdb.
filter_sunleaf_traits() has the identical bug: when no canopy_layer
covariate is available, all measurements should pass through unfiltered,
not be silently discarded.
6ed1fc0 to
823ed4f
Compare
|
@dlebauer since I think you originally wrote these bits many many years ago, I was looking for your feedback on which is wrong here, the code or the documentation (i.e., do we want to remove these traits if they lack covariates, or assume they correspond to defaults?). If the documentation is wrong, sounds like there are other fixed downstream that are needed |
|
When I implemented this, the default of 25C for missing measurement temperature seemed more defensible, given the dataset that we had. But now, for a temperature-dependent trait with unknown measurement or reference temperature, I think it is safer to either filter those rows out or error rather than silently assume 25C; leave it to the user to explicitly make the decision to fill in missing temperature covariate data. I think that the sunleaf case is different because the method of taking these measurements from top of canopy seems more standardized. |
|
Thanks for the context @dlebauer. That distinction makes sense.
I can update the PR whichever way you'd like. The original crash (argument is of length zero in nrow()) still needs addressing regardless of which policy we pick. |
|
I vote for 2 + warning: drop rows missing covariates, but send the user a warning letting them know that you've done so (e.g. "X rows of data on Y are dropped due to missing covariate date") |
|
I agree with @mdietze that there values should be dropped with warning. Thanks @anshul23102 ! |
|
Thanks for the decision. Here's my plan before I update the code:
Does this sound right to both of you, or should filter_sunleaf_traits follow the same drop + warn approach? |
|
Looks good to me except:
Returns empty data frame iff no input rows have covariates, else returns with rows that had covariates. And please make sure to update docs accordingly and add tests - these don't have to comprehensively cover all inputs, just the key functionality. |
Bug
arrhenius.scaling.traits()andfilter_sunleaf_traits()both setdata <- NULLwhen no matching covariates are found, contradicting their own documentation.arrhenius.scaling.traits()The docstring says:
But the else-branch does:
This function is called in
query.trait.data()forVcmax,root_respiration_rate,leaf_respiration_rate_m2, andstem_respiration_rate. When no temperature covariate is recorded in BETYdb for a species,databecomesNULL, and the very next lineif (nrow(result) == 0)throws:The entire trait query pipeline crashes silently. The
missing.temp = 25parameter was designed to handle exactly this case (assume 25°C → scaling is a no-op), but it is never reached.filter_sunleaf_traits()The same
data <- NULLpattern: when nocanopy_layercovariate exists, all observations should pass through unfiltered. Instead they are all discarded.Fix
Remove
data <- NULLfrom both else-branches so the functions fall through toreturn(data)unchanged, as documented.Impact
Any PEcAn meta-analysis run that queries a temperature-sensitive trait for a species with no temperature covariate in BETYdb will crash at
query.trait.data(). This is a common situation for less-studied species or older database entries.