class RelatedOrders(BaseDynamicData): """Simple script to (dynamically) relay query and result data from the ItemRecommendation module in URL request then HTML table format. """ def __init__(self): BaseDynamicData.__init__(self) self.requestData["searchStr"] = "" self.requestData["analysisStatus"] = "1" self.requestData["sim_patient_id"] = "" self.requestData["sim_time"] = "" self.requestData["sourceTables"] = "stride_order_proc,stride_order_med" # Default comma-separated list of source tables to expect orders to reside in self.requestData["queryItemIds"] = "" self.requestData["targetItemIds"] = "" self.requestData["excludeItemIds"] = "" self.requestData["excludeCategoryIds"] = "" self.requestData["timeDeltaMax"] = "86400" # Look for recommendations likely within 24 hours self.requestData["sortField"] = "" self.requestData["enableRecommender"] = "True" # By default, asssume recommender is enabled self.requestData["displayFields"] = "" #"prevalence","PPV","RR","P-YatesChi2" self.requestData["sortReverse"] = "True" self.requestData["nPreCols"] = "1" self.requestData["groupByCategory"] = "True" self.requestData["resultCount"] = "10" # Default for related order search self.requestData["invertQuery"] = "" self.requestData["showCounts"] = "" self.requestData["countPrefix"] = "patient_" self.requestData["aggregationMethod"] = "weighted" self.requestData["title"] = "Order Search Results" self.requestData["fieldHeaders"] = "" self.requestData[ "dataRows"] = '<tr><td colspan=100 align=center height=200><img src="../../resource/ajax-loader.gif"></td></tr>' self.addHandler("searchStr", RelatedOrders.action_orderSearch.__name__) self.addHandler("RelatedOrders", RelatedOrders.action_default.__name__) def action_orderSearch(self): """Search for orders by query string""" manager = SimManager() query = ClinicalItemQuery() query.parseParams(self.requestData) query.sourceTables = self.requestData["sourceTables"].split(",") results = manager.clinicalItemSearch(query) lastModel = None for dataModel in results: dataModel["controls"] = CONTROLS_TEMPLATE % dataModel dataModel["nPreCols"] = self.requestData["nPreCols"] dataModel["category_description.format"] = "" if lastModel is None or lastModel[ "category_description"] != dataModel[ "category_description"]: dataModel[ "category_description.format"] = "<b>%s</b>" % dataModel[ "category_description"] # Only show category if new lastModel = dataModel colNames = ["controls", "description"] # "name" for order code. ,"category_description.format" lastModel = None htmlLines = list() for dataModel in results: newCategory = (lastModel is None or lastModel["category_description"] != dataModel["category_description"]) showCategory = (self.requestData["groupByCategory"] and newCategory) # Limit category display if many repeats if showCategory: htmlLines.append(CATEGORY_HEADER_TEMPLATE % dataModel) htmlLines.append( self.formatRowHTML(dataModel, colNames, showCategory)) lastModel = dataModel self.requestData["dataRows"] = str.join("\n", htmlLines) def action_default(self): """Look for related orders by association / recommender methods""" # If patient is specified then modify query and exclusion list based on items already ordered for patient recentItemIds = set() if self.requestData["sim_patient_id"]: patientId = int(self.requestData["sim_patient_id"]) simTime = int(self.requestData["sim_time"]) # Track recent item IDs (orders, diagnoses, unlocked results, etc. that related order queries will be based off of) manager = SimManager() recentItemIds = manager.recentItemIds(patientId, simTime) # Recommender Instance to test on self.recommender = ItemAssociationRecommender() self.recommender.dataManager.dataCache = webDataCache # Allow caching of data for rapid successive queries query = RecommenderQuery() if self.requestData["sortField"] == "": self.requestData["sortField"] = "P-YatesChi2-NegLog" # P-Fisher-NegLog should yield better results, but beware, much longer to calculate query.parseParams(self.requestData) if len(query.excludeItemIds) == 0: query.excludeItemIds = self.recommender.defaultExcludedClinicalItemIds( ) if len(query.excludeCategoryIds) == 0: query.excludeCategoryIds = self.recommender.defaultExcludedClinicalItemCategoryIds( ) #query.fieldList.extend( ["prevalence","PPV","RR"] ); displayFields = list() if self.requestData["displayFields"] != "": displayFields = self.requestData["displayFields"].split(",") # Exclude items already ordered for the patient from any recommended list query.excludeItemIds.update(recentItemIds) if not query.queryItemIds: # If no specific query items specified, then use the recent patient item IDs query.queryItemIds.update(recentItemIds) recommendedData = self.recommender(query) if len(recommendedData) > 0: # Denormalize results with links to clinical item descriptions self.recommender.formatRecommenderResults(recommendedData) # Display fields should append Format suffix to identify which version to display, but use original for header labels (self.requestData["fieldHeaders"], displayFieldsFormatSuffixed ) = self.prepareDisplayHeaders(displayFields) # Format for HTML and add a control field for interaction with the data for dataModel in recommendedData: self.prepareResultRow(dataModel, displayFields) # Try organize by category if self.requestData["groupByCategory"]: recommendedData = self.recommender.organizeByCategory( recommendedData) colNames = ["controls"] # "name" for code. ,"category_description" colNames.extend(displayFieldsFormatSuffixed) colNames.extend(["description"]) lastModel = None htmlLines = list() for dataModel in recommendedData: newCategory = (lastModel is None or lastModel["category_description"] != dataModel["category_description"]) showCategory = (self.requestData["groupByCategory"] and newCategory) # Limit category display if many repeats if showCategory: htmlLines.append(CATEGORY_HEADER_TEMPLATE % dataModel) htmlLines.append( self.formatRowHTML(dataModel, colNames, showCategory)) lastModel = dataModel self.requestData["dataRows"] = str.join("\n", htmlLines) def prepareDisplayHeaders(self, displayFields): showCounts = (self.requestData["showCounts"].lower() not in FALSE_STRINGS) fieldHeadersHTML = "" for displayField in displayFields: fieldHeadersHTML += '<th nowrap>' + displayField + '</th>' if showCounts: fieldHeadersHTML += '<th>' + str.join('</th><th>', CORE_FIELDS) + '</th>' displayFieldsFormatSuffixed = list() for field in displayFields: displayFieldsFormatSuffixed.append('%sFormat' % field) if showCounts: for field in CORE_FIELDS: displayFieldsFormatSuffixed.append('%sFormat' % field) return (fieldHeadersHTML, displayFieldsFormatSuffixed) def prepareResultRow(self, dataModel, displayFields): dataModel["controls"] = CONTROLS_TEMPLATE % dataModel dataModel["nPreCols"] = len(displayFields) + 1 # Track spacer columns leading up to order description. +1 for control column dataModel["name"] = dataModel["name"].replace(",", "-") if "nB" in dataModel: if "nAB" not in dataModel: # Baseline query without query items, use matching numbers to ensure calculations will have something to process dataModel["nAB"] = dataModel["nB"] dataModel["nA"] = dataModel["N"] nAB = dataModel["nAB"] nA = dataModel["nA"] nB = dataModel["nB"] N = dataModel["N"] contStats = ContingencyStats(nAB, nA, nB, N) contStats.normalize(truncateNegativeValues=False) for field in displayFields: if field not in dataModel: # Unavailable field, see if it is a derived field that can be calculated dataModel[field] = contStats[field] if field in CORE_FIELDS: pass elif field in PERCENT_FIELDS: # Format as a percentage dataModel["%sFormat" % field] = "%d%%" % (dataModel[field] * 100) elif abs(dataModel[field]) < 0.01: # Allow formatting for very small values dataModel["%sFormat" % field] = "%.0e" % dataModel[field] elif abs(dataModel[field]) < 1: # Smaller value, show more significant digits dataModel["%sFormat" % field] = "%.2f" % dataModel[field] else: # Default just format as limited floating point values dataModel["%sFormat" % field] = "%.1f" % dataModel[field] for field in CORE_FIELDS: # Count fields express as integers, assuming available at all if field in BASELINE_FIELDS: dataModel["%sFormat" % field] = "%d" % dataModel[field] else: # May have small virtual counts from derived scenarios if dataModel[field] > 10: dataModel["%sFormat" % field] = "%.1f" % dataModel[field] else: dataModel["%sFormat" % field] = "%.2f" % dataModel[field] def formatRowHTML(self, dataModel, colNames, showCategory=True): """Specific formatting for row data elements """ htmlList = list() htmlList.append('<tr valign=top>') for col in colNames: if col == "category_description": # Blank out repeat categories if showCategory: htmlList.append( '<td align=center><b>%(category_description)s</b></td>' % dataModel) else: htmlList.append('<td></td>') elif col == "description": htmlList.append('<td align=left>') htmlList.append(DESCRIPTION_TEMPLATE % dataModel) # Only include related link if recommender is enabled if self.requestData['enableRecommender'] == "True": htmlList.append(RELATED_LINK_TEMPLATE % dataModel) htmlList.append('</td>') else: htmlList.append('<td align=right>%s</td>' % dataModel[col]) htmlList.append('</tr>') return str.join("\n", htmlList)
# Keep track of each guideline name set itemIdsByAdmitDxId = dict() for admitDxId, sectionName, guidelineName, itemId, itemName, itemDescription, itemCount in resultsTable: if admitDxId not in itemIdsByAdmitDxId: itemIdsByAdmitDxId[admitDxId] = set() itemIdsByAdmitDxId[admitDxId].add(itemId) admitDxIdSectionGuidelineNameTuples.add( (admitDxId, sectionName, guidelineName)) recommender = ItemAssociationRecommender() for admitDxId, itemIds in itemIdsByAdmitDxId.iteritems(): print >> sys.stderr, admitDxId, len(itemIds) recQuery = RecommenderQuery() recQuery.excludeItemIds = recommender.defaultExcludedClinicalItemIds() recQuery.excludeCategoryIds = recommender.defaultExcludedClinicalItemCategoryIds( ) recQuery.queryItemIds = [admitDxId] recQuery.timeDeltaMax = timedelta(1) # Within one day recQuery.countPrefix = "patient_" recQuery.limit = TOP_ITEM_COUNT # Top results by P-value recQuery.sortField = "P-YatesChi2-NegLog" results = recommender(recQuery) #recommender.formatRecommenderResults(results); for result in results: itemIds.add(result["clinical_item_id"]) #print >> sys.stderr, result["description"]; print >> sys.stderr, admitDxId, len(itemIds)