Skip to content

Commit d961043

Browse files
authored
Merge pull request #1719 from microbiomedata/1681-nom-processed-sample-data
Add additional NOM metadata to data portal
2 parents 29698c9 + a819207 commit d961043

File tree

2 files changed

+69
-9
lines changed

2 files changed

+69
-9
lines changed

nmdc_server/ingest/omics_processing.py

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,24 @@ def find_parent_process(output_id: str, mongodb: Database) -> Optional[dict[str,
6666
return None
6767

6868

69-
def get_biosample_input_ids(input_id: str, mongodb: Database, results: set) -> set[Any]:
69+
def get_biosample_input_ids(
70+
input_id: str,
71+
mongodb: Database,
72+
results: set[str],
73+
sampled_portions: set[str],
74+
direct_input: bool,
75+
) -> set[Any]:
7076
"""
7177
Given an input ID return all biosample objects that are included in the input resource.
7278
7379
OmicsProcessing objects can take Biosamples or ProcessedSamples as inputs. Work needs to be done
7480
to determine which biosamples make up a given ProcessedSample. This function recursively tries
7581
to determine those Biosamples.
82+
83+
As a side effect, a set of `sampled_portion` values gets populated. Whether or not a processed
84+
samples' `sampled_portion`s get added to the set is driven by the `direct_input` parameter. Only
85+
processed samples which are inputs directly to a data generation will have their
86+
`sampled_portion`s added.
7687
"""
7788
# Base case, the input is already a biosample
7889
biosample_collection: Collection = mongodb["biosample_set"]
@@ -87,25 +98,32 @@ def get_biosample_input_ids(input_id: str, mongodb: Database, results: set) -> s
8798
if not query:
8899
return results
89100

90-
processed_sample_id = query[0]["id"]
101+
processed_sample = query[0]
102+
processed_sample_id = processed_sample["id"]
103+
sampled_portion = set(processed_sample.get("sampled_portion", []))
104+
# only store sampled portion values for immediate input to a data generation
105+
if direct_input and sampled_portion:
106+
sampled_portions.update(sampled_portion)
91107

92108
# Recursive case. For processed samples find the process that created it,
93109
# and check the inputs of that process.
94110
parent_process = find_parent_process(processed_sample_id, mongodb)
95111
if parent_process:
96112
for parent_input_id in parent_process["has_input"]:
97-
get_biosample_input_ids(parent_input_id, mongodb, results)
113+
get_biosample_input_ids(parent_input_id, mongodb, results, sampled_portions, False)
98114
return results
99115

100116

101-
def get_configuration_name(mongodb: Database, configuration_id: str, config_map) -> Optional[str]:
117+
def get_configuration_property(
118+
mongodb: Database, configuration_id: str, key: str, config_map
119+
) -> Optional[str]:
102120
config_set = "configuration_set"
103121
if configuration_id in config_map:
104122
config_record = config_map[configuration_id]
105123
else:
106124
config_record = mongodb[config_set].find_one({"id": configuration_id})
107125
config_map[configuration_id] = config_record
108-
return config_record["name"] if config_record else None
126+
return config_record[key] if config_record else None
109127

110128

111129
def get_poolable_replicate_manifest(
@@ -134,8 +152,13 @@ def load_omics_processing(db: Session, obj: Dict[str, Any], mongodb: Database, l
134152
logger = get_logger(__name__)
135153
input_ids: list[str] = obj.pop("has_input", [""])
136154
biosample_input_ids: set[str] = set()
155+
sampled_portions: set[str] = set()
137156
for input_id in input_ids:
138-
biosample_input_ids.union(get_biosample_input_ids(input_id, mongodb, biosample_input_ids))
157+
biosample_input_ids.union(
158+
get_biosample_input_ids(input_id, mongodb, biosample_input_ids, sampled_portions, True)
159+
)
160+
if sampled_portions:
161+
obj["sampled_portions"] = list(sampled_portions)
139162

140163
obj["biosample_inputs"] = []
141164
biosample_input_objects = []
@@ -161,14 +184,20 @@ def load_omics_processing(db: Session, obj: Dict[str, Any], mongodb: Database, l
161184

162185
# Get configuration info
163186
mass_spec_config_id = obj.pop("has_mass_spectrometry_configuration", None)
164-
mass_spec_config_name = get_configuration_name(mongodb, mass_spec_config_id, config_map)
187+
mass_spec_config_name = get_configuration_property(
188+
mongodb, mass_spec_config_id, "name", config_map
189+
)
190+
mass_spec_polarity_mode = get_configuration_property(
191+
mongodb, mass_spec_config_id, "polarity_mode", config_map
192+
)
165193
if mass_spec_config_name:
166194
obj["mass_spectrometry_configuration_name"] = mass_spec_config_name
167195
obj["mass_spectrometry_configuration_id"] = mass_spec_config_id
196+
obj["mass_spectrometry_config_polarity_mode"] = mass_spec_polarity_mode
168197

169198
chromatography_config_id = obj.pop("has_chromatography_configuration", None)
170-
chromatography_config_name = get_configuration_name(
171-
mongodb, chromatography_config_id, config_map
199+
chromatography_config_name = get_configuration_property(
200+
mongodb, chromatography_config_id, "name", config_map
172201
)
173202
if chromatography_config_name:
174203
obj["chromatography_configuration_name"] = chromatography_config_name

web/src/components/DataObjectTable.vue

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
<script lang="ts">
2+
// @ts-ignore
3+
import NmdcSchema from 'nmdc-schema/nmdc_schema/nmdc_materialized_patterns.yaml';
24
import {
35
computed, defineComponent, PropType, reactive,
46
} from '@vue/composition-api';
@@ -90,20 +92,43 @@ export default defineComponent({
9092
value: false,
9193
});
9294
95+
function nomMetadataString(item: {
96+
massSpecPolarityMode: string,
97+
eluentIntroductionCategory: string,
98+
sampledPortions: string,
99+
}): string {
100+
return [item.eluentIntroductionCategory, item.sampledPortions, item.massSpecPolarityMode].filter((value) => !!value).join(', ');
101+
}
102+
93103
function getOmicsDataWithInputIds(omicsProcessing: OmicsProcessingResult) {
94104
const biosampleInputIds = (omicsProcessing.biosample_inputs as BiosampleSearchResult[]).map((input) => input.id);
95105
const annotations = omicsProcessing.annotations as Record<string, string | string[]>;
96106
return omicsProcessing.omics_data.map((omics) => {
107+
const { EluentIntroductionCategoryEnum, PolarityModeEnum, SamplePortionEnum } = NmdcSchema.enums;
97108
const omicsCopy = { ...omics };
98109
omicsCopy.inputIds = biosampleInputIds;
99110
if (annotations.mass_spectrometry_configuration_id) {
100111
omicsCopy.massSpecConfigId = annotations.mass_spectrometry_configuration_id || '';
101112
omicsCopy.massSpecConfigName = annotations.mass_spectrometry_configuration_name || '';
113+
const polarityMode = annotations.mass_spectrometry_config_polarity_mode
114+
? `${PolarityModeEnum.permissible_values[annotations.mass_spectrometry_config_polarity_mode].text} mode`
115+
: '';
116+
omicsCopy.massSpecPolarityMode = polarityMode;
102117
}
103118
if (annotations.chromatography_configuration_id) {
104119
omicsCopy.chromConfigId = annotations.chromatography_configuration_id || '';
105120
omicsCopy.chromConfigName = annotations.chromatography_configuration_name || '';
106121
}
122+
if (annotations.eluent_introduction_category) {
123+
omicsCopy.eluentIntroductionCategory = EluentIntroductionCategoryEnum.permissible_values[annotations.eluent_introduction_category].title;
124+
}
125+
if (annotations.sampled_portions.length) {
126+
const displaySampledPortions = (annotations.sampled_portions as string[]).map((sampledPortion: string) => (
127+
SamplePortionEnum.permissible_values[sampledPortion].title
128+
|| SamplePortionEnum.permissible_values[sampledPortion].text
129+
));
130+
omicsCopy.sampledPortions = displaySampledPortions.join(', ');
131+
}
107132
return omicsCopy;
108133
});
109134
}
@@ -170,6 +195,7 @@ export default defineComponent({
170195
termsDialog,
171196
getRelatedBiosampleIds,
172197
metaproteomicCategoryEnumToDisplay,
198+
nomMetadataString,
173199
};
174200
},
175201
});
@@ -219,6 +245,11 @@ export default defineComponent({
219245
<br>
220246
<b>{{ metaproteomicCategoryEnumToDisplay[item.omics_data.metaproteomics_analysis_category] }}</b>
221247
</span>
248+
<span v-if="omicsType === 'Organic Matter Characterization' && nomMetadataString(item.omics_data)">
249+
<br>
250+
<b>Data Generation: </b> NOM via
251+
{{ nomMetadataString(item.omics_data) }}
252+
</span>
222253
<br>
223254
<div v-if="getRelatedBiosampleIds(item.omics_data).length">
224255
<v-icon>

0 commit comments

Comments
 (0)