Skip to content

Commit

Permalink
- NewCset authoring now shows whats included/excluded due to descendants
Browse files Browse the repository at this point in the history
- Tried to implement mapping stuff but not actually sure the algorithm
  used in OHDSI/Enclave (include descendants of mapped? or include
  mapped of descendants?)
- Renamed get_possible_replacement_concepts to get_similar_concepts so
  it could get mapped to conncepts, but not using that currently.
- If going to use it, already added concept_mappings to api definitions
  in DataGetter
  • Loading branch information
Sigfried committed Nov 11, 2024
1 parent 78c1d93 commit 91e3fb1
Show file tree
Hide file tree
Showing 7 changed files with 182 additions and 127 deletions.
57 changes: 39 additions & 18 deletions backend/routes/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -584,8 +584,42 @@ def single_n3c_comparison_rpt(pair: str):
return rpt[0] if rpt else None


def get_possible_replacement_concepts(concept_ids):
"""Get replacement concepts for multiple concept IDs in a single query"""
@router.post("/get-similar-concepts")
def get_similar_concepts(concept_ids: List[Union[int, str]], which: str = 'all' ) -> Dict:
"""Get similar concepts for multiple concept IDs in a single query
Args:
concept_ids: List of concept IDs (can be integers or strings)
which: Relationship type filter ('all', 'to', or 'from')
"""
concept_ids = [int(cid) for cid in concept_ids]
if which == 'all': # all similar for possible replacement suggestions for codeset comparisons
rels = [
'Maps to',
'Maps to value',
'Mapped from',
'Mapped from value',
'Concept alt_to from',
'Concept alt_to to',
'Concept poss_eq from',
'Concept poss_eq to',
'Concept replaced by',
'Concept replaces',
'Concept same_as from',
'Concept same_as to',
'Concept was_a from',
'Concept was_a to'
]
elif which == 'to': # what OHDSI includeMapped usually does, I think
rels = [
'Maps to',
'Maps to value',
]
elif which == 'from': # what OHDSI includeMapped should do, I think
rels = [
'Mapped from',
'Mapped from value',
]

with get_db_connection() as con:
q = """
SELECT
Expand All @@ -599,24 +633,11 @@ def get_possible_replacement_concepts(concept_ids):
FROM concept_relationship cr
JOIN concepts_with_counts c2 ON cr.concept_id_2 = c2.concept_id
WHERE concept_id_1 = ANY(:concept_ids)
AND relationship_id in (
'Maps to',
'Mapped from',
'Concept alt_to from',
'Concept alt_to to',
'Concept poss_eq from',
'Concept poss_eq to',
'Concept replaced by',
'Concept replaces',
'Concept same_as from',
'Concept same_as to',
'Concept was_a from',
'Concept was_a to'
)
AND relationship_id = ANY(:rels)
AND concept_id_1 != concept_id_2
GROUP BY 1,2,3,4,5,6;
"""
results = sql_query(con, q, {'concept_ids': list(concept_ids)})
results = sql_query(con, q, {'concept_ids': list(concept_ids), 'rels': rels})

# Organize results by source concept
replacements_by_concept = {}
Expand Down Expand Up @@ -683,7 +704,7 @@ def format_codeset_info(cset: dict) -> str:

# Get all replacement suggestions in one query
if removed:
all_replacements = get_possible_replacement_concepts(removed_cids)
all_replacements = get_similar_concepts(removed_cids)

# Add filtered replacement suggestions for removed concepts
for rec in removed:
Expand Down
3 changes: 3 additions & 0 deletions backend/routes/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@ async def concept_graph(


def get_all_descendants(G: nx.DiGraph, subgraph_nodes: Union[List[int], Set[int]], verbose=VERBOSE) -> Set:
# using this instead of get_missing_in_between_nodes. this way the front end has the entire
# descendant tree for all concepts being looked at
descendants: Set[int] = set()
for node in subgraph_nodes:
if G.has_node(node):
Expand Down Expand Up @@ -204,6 +206,7 @@ def filter_concepts(

# noinspection PyPep8Naming
def get_missing_in_between_nodes(G: nx.DiGraph, subgraph_nodes: Union[List[int], Set[int]], verbose=VERBOSE) -> Set:
# not using this anymore
missing_in_between_nodes = set()
missing_in_between_nodes_tmp = set()
subgraph_nodes = set(subgraph_nodes)
Expand Down
35 changes: 11 additions & 24 deletions frontend/src/components/CsetComparisonPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ import {
cellContents,
cellStyle,
getCodesetEditActionFunc,
getItem,
Legend,
newCsetAtlasWidget,
textCellForItem,
expandCset,
} from './NewCset';
import {FlexibleContainer} from './FlexibleContainer';
import {
Expand All @@ -65,8 +65,7 @@ import {isEqual} from '@react-sigma/core';
export async function fetchGraphData(props) {
let {dataGetter, codeset_ids, cids, newCset = {}} = props;
let promises = [ // these can run immediately
dataGetter.fetchAndCacheItems(dataGetter.apiCalls.cset_members_items,
codeset_ids),
dataGetter.fetchAndCacheItems(dataGetter.apiCalls.cset_members_items, codeset_ids),
dataGetter.fetchAndCacheItems(dataGetter.apiCalls.csets, codeset_ids),
];
// have to get concept_ids before fetching concepts
Expand Down Expand Up @@ -122,18 +121,8 @@ export async function fetchGraphData(props) {

if (!isEmpty(newCset)) {
selected_csets.push(newCset);
selected_csets = selected_csets.map(cset => {
cset = {...cset};
// not sure why these counts are needed...oh, maybe because we
// planned to update them and add them to the comparison UI somehow
cset.intersecting_concepts = 0;
cset.precision = 0;
cset.recall = 0;
cset.counts = {};
return cset;
});

csmi[newCset.codeset_id] = newCset.definitions;
// these will be modified once the concept graph is constructed
}

const concepts = Object.values(conceptLookup);
Expand Down Expand Up @@ -240,6 +229,10 @@ export function CsetComparisonPage() {
// let _gc = new GraphContainer({ ...graphData, concepts, specialConcepts, csmi });
// that looks redundant, unneeded. fixing now but not testing. hopefully won't break anything:
let _gc = new GraphContainer(graphData);
if (newCset) {
const expansion = await expandCset({newCset, graphContainer: _gc});
csmi[newCset.codeset_id] = expansion;
}

const {allRows, allRowsById} = _gc.setupAllRows(_gc.roots);

Expand Down Expand Up @@ -312,16 +305,12 @@ export function CsetComparisonPage() {

const nested = get(graphOptions, 'nested', true); // defaults to true but allows false to be set

const editAction = getCodesetEditActionFunc(
{csmi, newCset, newCsetDispatch});

const colDefs = getColDefs({
gc,
selected_csets,
concepts,
cids,
sizes,
editAction,
windowSize,
// hidden,
displayedRows,
Expand Down Expand Up @@ -787,7 +776,6 @@ function getColDefs(props) {
concepts,
cids,
sizes,
editAction,
windowSize,
hidden,
displayedRows,
Expand All @@ -799,6 +787,8 @@ function getColDefs(props) {
} = props;
const {nested, } = graphOptions;

const editAction = getCodesetEditActionFunc({csmi, newCset, newCsetDispatch});

let coldefs = [
{
name: 'Concept name',
Expand Down Expand Up @@ -1099,11 +1089,8 @@ function getColDefs(props) {
},
},
selector: row => {
const item = getItem({
codeset_id: cset_col.codeset_id,
concept_id: row.concept_id, csmi, newCset,
}) || {};
return !(item.item || item.csm);
const item = get(csmi, [cset_col.codeset_id, row.concept_id]) || {};
return !(item.item || item.csm); // why?
},
format: (row) => {
return cellContents({
Expand Down
Loading

0 comments on commit 91e3fb1

Please sign in to comment.