def dist_to_ptv_centroids(study_instance_uid, roi_name): """ This function will recalculate the OARtoPTV centroid distance based on data in the SQL DB. :param study_instance_uid: uid as specified in SQL DB :param roi_name: roi_name as specified in SQL DB """ oar_centroid_string = DVH_SQL().query( 'dvhs', 'centroid', "study_instance_uid = '%s' and roi_name = '%s'" % (study_instance_uid, roi_name)) oar_centroid = np.array( [float(i) for i in oar_centroid_string[0][0].split(',')]) ptv_coordinates_strings = DVH_SQL().query( 'dvhs', 'roi_coord_string', "study_instance_uid = '%s' and roi_type like 'PTV%%'" % study_instance_uid) if ptv_coordinates_strings: ptvs = [ roi_form.get_planes_from_string(ptv[0]) for ptv in ptv_coordinates_strings ] tv = roi_geom.union(ptvs) ptv_centroid = np.array(roi_geom.centroid(tv)) data = float(np.linalg.norm(ptv_centroid - oar_centroid)) / 10. update_dvhs_table(study_instance_uid, roi_name, 'dist_to_ptv_centroids', round(float(data), 3))
def __init__(self, table_name, condition_str, unique=False): table_name = table_name.lower() if table_name in {'beams', 'dvhs', 'plans', 'rxs'}: self.table_name = table_name self.condition_str = condition_str self.cnx = DVH_SQL() # column names, use as property names column_cursor = self.cnx.get_column_names(table_name) for row in column_cursor: column = str(row).strip() if column not in {'roi_coord_string, distances_to_ptv'}: self.cursor = self.cnx.query(self.table_name, column, self.condition_str) if unique: rtn_list = get_unique_list(self.cursor_to_list()) else: rtn_list = self.cursor_to_list() setattr(self, column, rtn_list) else: print( 'Table name in valid. Please select from Beams, DVHs, Plans, or Rxs.' )
def update_spread_in_db(study_instance_uid, roi_name): """ This function will recalculate the spread of an roi based on data in the SQL DB. :param study_instance_uid: uid as specified in SQL DB :param roi_name: roi_name as specified in SQL DB """ coordinates_string = DVH_SQL().query( 'dvhs', 'roi_coord_string', "study_instance_uid = '%s' and roi_name = '%s'" % (study_instance_uid, roi_name)) roi = roi_tools.get_planes_from_string(coordinates_string[0][0]) spread = calc_spread(roi) spread = [str(round(v / 10., 3)) for v in spread] DVH_SQL().update( 'dvhs', 'spread_x', spread[0], "study_instance_uid = '%s' and roi_name = '%s'" % (study_instance_uid, roi_name)) DVH_SQL().update( 'dvhs', 'spread_y', spread[1], "study_instance_uid = '%s' and roi_name = '%s'" % (study_instance_uid, roi_name)) DVH_SQL().update( 'dvhs', 'spread_z', spread[2], "study_instance_uid = '%s' and roi_name = '%s'" % (study_instance_uid, roi_name))
def update_treatment_volume_overlap_in_db(study_instance_uid, roi_name): oar_coordinates_string = DVH_SQL().query( 'dvhs', 'roi_coord_string', "study_instance_uid = '%s' and roi_name = '%s'" % (study_instance_uid, roi_name)) ptv_coordinates_strings = DVH_SQL().query( 'dvhs', 'roi_coord_string', "study_instance_uid = '%s' and roi_type like 'PTV%%'" % study_instance_uid) if ptv_coordinates_strings: oar = get_planes_from_string(oar_coordinates_string[0][0]) ptvs = [] for ptv in ptv_coordinates_strings: ptvs.append(get_planes_from_string(ptv[0])) tv = get_union(ptvs) overlap = calc_roi_overlap(oar, tv) DVH_SQL().update( 'dvhs', 'ptv_overlap', round(float(overlap), 2), "study_instance_uid = '%s' and roi_name = '%s'" % (study_instance_uid, roi_name))
def treatment_volume_overlap(study_instance_uid, roi_name): """ This function will recalculate the PTV overlap of an roi based on data in the SQL DB. :param study_instance_uid: uid as specified in SQL DB :param roi_name: roi_name as specified in SQL DB """ oar_coordinates_string = DVH_SQL().query( 'dvhs', 'roi_coord_string', "study_instance_uid = '%s' and roi_name = '%s'" % (study_instance_uid, roi_name)) ptv_coordinates_strings = DVH_SQL().query( 'dvhs', 'roi_coord_string', "study_instance_uid = '%s' and roi_type like 'PTV%%'" % study_instance_uid) if ptv_coordinates_strings: oar = roi_form.get_planes_from_string(oar_coordinates_string[0][0]) ptvs = [ roi_form.get_planes_from_string(ptv[0]) for ptv in ptv_coordinates_strings ] tv = roi_geom.union(ptvs) overlap = roi_geom.overlap_volume(oar, tv) update_dvhs_table(study_instance_uid, roi_name, 'ptv_overlap', round(float(overlap), 2))
def __init__(self, uid=None, dvh_condition=None): """ This class will retrieve DVHs and other data in the DVH SQL table meeting the given constraints, it will also parse the DVH_string into python lists and retrieve the associated Rx dose :param uid: a list of allowed study_instance_uids in data set :param dvh_condition: a string in SQL syntax applied to a DVH Table query """ if uid: constraints_str = "study_instance_uid in ('%s')" % "', '".join(uid) if dvh_condition: constraints_str = " and " + constraints_str else: constraints_str = '' if dvh_condition: constraints_str = "(%s)%s" % (dvh_condition, constraints_str) self.query = dvh_condition else: self.query = '' cnx = DVH_SQL() # Get DVH data from SQL dvh_data = QuerySQL('DVHs', constraints_str) for key, value in dvh_data.__dict__.items(): if not key.startswith("__"): setattr(self, key, value) # Add these properties to dvh_data since they aren't in the DVHs SQL table self.count = len(self.mrn) self.rx_dose = [] self.bin_count = 0 for value in self.dvh_string: current_dvh_str = np.array(str(value).split(',')) current_size = np.size(current_dvh_str) if current_size > self.bin_count: self.bin_count = current_size self.dvh = np.zeros([self.bin_count, self.count]) # Get needed values not in DVHs table for i in range(self.count): # Get Rx Doses condition = "mrn = '%s' and study_instance_uid = '%s'" % ( self.mrn[i], self.study_instance_uid[i]) rx_dose_cursor = cnx.query('Plans', 'rx_dose', condition) self.rx_dose.append(rx_dose_cursor[0][0]) # Process dvh_string to numpy array, and pad with zeros at the end # so that all dvhs are the same length current_dvh = np.array(self.dvh_string[i].split(','), dtype='|S4').astype(np.float) current_dvh_max = np.max(current_dvh) if current_dvh_max > 0: current_dvh = np.divide(current_dvh, current_dvh_max) zero_fill = np.zeros(self.bin_count - len(current_dvh)) self.dvh[:, i] = np.concatenate((current_dvh, zero_fill))
def get_physician_from_uid(uid): cnx = DVH_SQL() condition = "study_instance_uid = '" + uid + "'" results = cnx.query('Plans', 'physician', condition) if len(results) > 1: print('Warning: multiple plans with this study_instance_uid exist') return str(results[0][0])
def rebuild_database(start_path): print('connecting to SQL DB') sqlcnx = DVH_SQL() print('connection established') sqlcnx.reinitialize_database() print('DB reinitialized with no data') dicom_to_sql(start_path=start_path, force_update=True) sqlcnx.cnx.close()
def beam_complexities(*condition): if condition: condition = condition[0] cnx = DVH_SQL() uids = cnx.get_unique_values('Beams', 'study_instance_uid', condition, return_empty=True) for uid in uids: beam_complexity(cnx, uid) cnx.close()
def update_all_plan_toxicity_grades(*condition): if condition: condition = condition[0] cnx = DVH_SQL() uids = cnx.get_unique_values('Plans', 'study_instance_uid', condition, return_empty=True) for uid in uids: update_plan_toxicity_grades(uid) cnx.close()
def reinitialize_roi_categories_in_database(): roi_map = DatabaseROIs() dvh_data = QuerySQL('DVHs', "mrn != ''") cnx = DVH_SQL() for i in range(0, len(dvh_data.roi_name)): uid = dvh_data.study_instance_uid[i] physician = get_physician_from_uid(uid) roi_name = dvh_data.roi_name[i] new_physician_roi = roi_map.get_physician_roi(physician, roi_name) new_institutional_roi = roi_map.get_institutional_roi( physician, roi_name) print(i, physician, new_institutional_roi, new_physician_roi, roi_name, sep=' ') condition = "study_instance_uid = '" + uid + "'" + "and roi_name = '" + roi_name + "'" cnx.update('DVHs', 'physician_roi', new_physician_roi, condition) cnx.update('DVHs', 'institutional_roi', new_institutional_roi, condition) cnx.close()
def validate_sql_connection(config=None, verbose=False): """ :param config: a dict with keys 'host', 'dbname', 'port' and optionally 'user' and 'password' :param verbose: boolean indicating if cmd line printing should be performed :return: """ valid = True if config: try: cnx = DVH_SQL(config) cnx.close() except: valid = False else: try: cnx = DVH_SQL() cnx.close() except: valid = False if verbose: if valid: print("SQL DB is alive!") else: print("Connection to SQL DB could not be established.") if not is_sql_connection_defined(): print( "ERROR: SQL settings are not yet defined. Please run:\n", " $ dvh settings --sql", sep="") return valid
def validate_sql_connection(*config, **kwargs): if config: try: cnx = DVH_SQL(config[0]) cnx.close() valid = True except: valid = False else: try: cnx = DVH_SQL() cnx.close() valid = True except: valid = False if not kwargs or ('verbose' in kwargs and kwargs['verbose']): if valid: print("SQL DB is alive!") else: print("Connection to SQL DB could not be established.") if not is_sql_connection_defined(): print( "ERROR: SQL settings are not yet defined. Please run:\n", " $ dvh settings --sql", sep="") return valid
def update_volumes_in_db(study_instance_uid, roi_name): coordinates_string = DVH_SQL().query( 'dvhs', 'roi_coord_string', "study_instance_uid = '%s' and roi_name = '%s'" % (study_instance_uid, roi_name)) roi = get_planes_from_string(coordinates_string[0][0]) volume = calc_volume(roi) DVH_SQL().update( 'dvhs', 'volume', round(float(volume), 2), "study_instance_uid = '%s' and roi_name = '%s'" % (study_instance_uid, roi_name))
def min_distances(study_instance_uid, roi_name): """ This function will recalculate the min, mean, median, and max PTV distances an roi based on data in the SQL DB. :param study_instance_uid: uid as specified in SQL DB :param roi_name: roi_name as specified in SQL DB """ oar_coordinates_string = DVH_SQL().query( 'dvhs', 'roi_coord_string', "study_instance_uid = '%s' and roi_name = '%s'" % (study_instance_uid, roi_name)) ptv_coordinates_strings = DVH_SQL().query( 'dvhs', 'roi_coord_string', "study_instance_uid = '%s' and roi_type like 'PTV%%'" % study_instance_uid) if ptv_coordinates_strings: oar_coordinates = roi_form.get_roi_coordinates_from_string( oar_coordinates_string[0][0]) ptvs = [ roi_form.get_planes_from_string(ptv[0]) for ptv in ptv_coordinates_strings ] tv_coordinates = roi_form.get_roi_coordinates_from_planes( roi_geom.union(ptvs)) try: data = roi_geom.min_distances_to_target(oar_coordinates, tv_coordinates) dth = roi_geom.dth(data) dth_string = ','.join(['%.3f' % num for num in dth]) data_map = { 'dist_to_ptv_min': round(float(np.min(data)), 2), 'dist_to_ptv_mean': round(float(np.mean(data)), 2), 'dist_to_ptv_median': round(float(np.median(data)), 2), 'dist_to_ptv_max': round(float(np.max(data)), 2), 'dth_string': dth_string } for key, value in listitems(data_map): update_dvhs_table(study_instance_uid, roi_name, key, value) except: print('dist_to_ptv calculation failure, skipping')
def update_roi_viewer_data(self): # if roi_name is an empty string (default selection), return an empty data set if not self.roi_select.value: return {'0': {'x': [], 'y': [], 'z': []}} roi_data = {} roi_coord_string = DVH_SQL().query( 'dvhs', 'roi_coord_string', "study_instance_uid = '%s' and roi_name = '%s'" % (self.uid_select.value, self.roi_select.value)) roi_planes = get_planes_from_string(roi_coord_string[0][0]) for z_plane in list(roi_planes): x, y, z = [], [], [] for polygon in roi_planes[z_plane]: initial_polygon_index = len(x) for point in polygon: x.append(point[0]) y.append(point[1]) z.append(point[2]) x.append(x[initial_polygon_index]) y.append(y[initial_polygon_index]) z.append(z[initial_polygon_index]) x.append(float('nan')) y.append(float('nan')) z.append(float('nan')) roi_data[z_plane] = {'x': x, 'y': y, 'z': z} self.roi_viewer_data[self.roi_number] = roi_data
def update_select_category2_values(self): new = self.select_category1.value table_new = self.selector_categories[new]['table'] var_name_new = self.selector_categories[new]['var_name'] new_options = DVH_SQL().get_unique_values(table_new, var_name_new) self.select_category2.options = new_options self.select_category2.value = new_options[0]
def check_tables(): initial_label = check_tables_button.label initial_button_type = check_tables_button.button_type try: tables = ['dvhs', 'plans', 'beams', 'rxs'] table_result = {} for table in tables: table_result[table] = DVH_SQL().check_table_exists(table) if all(table_result.values()): check_tables_button.button_type = 'success' check_tables_button.label = 'Success' else: check_tables_button.button_type = 'warning' check_tables_button.label = 'Fail' time.sleep(1.5) check_tables_button.button_type = initial_button_type check_tables_button.label = initial_label except: check_tables_button.button_type = 'warning' check_tables_button.label = 'No Connection' time.sleep(1.5) check_tables_button.button_type = initial_button_type check_tables_button.label = initial_label
def update_range_titles(self, reset_values=False): table = self.range_categories[self.select_category.value]['table'] var_name = self.range_categories[ self.select_category.value]['var_name'] min_value = DVH_SQL().get_min_value(table, var_name) self.text_min.title = 'Min: ' + str( min_value) + ' ' + self.range_categories[ self.select_category.value]['units'] max_value = DVH_SQL().get_max_value(table, var_name) self.text_max.title = 'Max: ' + str( max_value) + ' ' + self.range_categories[ self.select_category.value]['units'] if reset_values: self.text_min.value = str(min_value) self.text_max.value = str(max_value)
def update_tv_data(self): self.tv_data = {} uid = self.uid_select.value ptv_coordinates_strings = DVH_SQL().query( 'dvhs', 'roi_coord_string', "study_instance_uid = '%s' and roi_type like 'PTV%%'" % uid) if ptv_coordinates_strings: ptvs = [ get_planes_from_string(ptv[0]) for ptv in ptv_coordinates_strings ] tv_planes = get_union(ptvs) for z_plane in list(tv_planes): x, y, z = [], [], [] for polygon in tv_planes[z_plane]: initial_polygon_index = len(x) for point in polygon: x.append(point[0]) y.append(point[1]) z.append(point[2]) x.append(x[initial_polygon_index]) y.append(y[initial_polygon_index]) z.append(z[initial_polygon_index]) x.append(float('nan')) y.append(float('nan')) z.append(float('nan')) self.tv_data[z_plane] = {'x': x, 'y': y, 'z': z}
def update_dicom_catalogue(mrn, uid, dir_path, plan_file, struct_file, dose_file): if not plan_file: plan_file = "(NULL)" if not plan_file: struct_file = "(NULL)" if not plan_file: dose_file = "(NULL)" DVH_SQL().insert_dicom_file_row(mrn, uid, dir_path, plan_file, struct_file, dose_file)
def update_volumes_in_db(study_instance_uid, roi_name): """ This function will recalculate the volume of an roi based on data in the SQL DB. :param study_instance_uid: uid as specified in SQL DB :param roi_name: roi_name as specified in SQL DB """ coordinates_string = DVH_SQL().query( 'dvhs', 'roi_coord_string', "study_instance_uid = '%s' and roi_name = '%s'" % (study_instance_uid, roi_name)) roi = roi_tools.get_planes_from_string(coordinates_string[0][0]) volume = roi_tools.calc_volume(roi) DVH_SQL().update( 'dvhs', 'volume', round(float(volume), 2), "study_instance_uid = '%s' and roi_name = '%s'" % (study_instance_uid, roi_name))
def update_surface_area_in_db(study_instance_uid, roi_name): """ This function will recalculate the surface area of an roi based on data in the SQL DB. :param study_instance_uid: uid as specified in SQL DB :param roi_name: roi_name as specified in SQL DB """ coordinates_string = DVH_SQL().query( 'dvhs', 'roi_coord_string', "study_instance_uid = '%s' and roi_name = '%s'" % (study_instance_uid, roi_name)) roi = get_planes_from_string(coordinates_string[0][0]) surface_area = surface_area_of_roi(roi, coord_type="sets_of_points") DVH_SQL().update( 'dvhs', 'surface_area', round(float(surface_area), 2), "study_instance_uid = '%s' and roi_name = '%s'" % (study_instance_uid, roi_name))
def print_mrns(): mrns = DVH_SQL().get_unique_values('plans', 'mrn') if len(mrns) == 0: print("No plans have been imported") printed_mrns = [] for i in range(0, len(mrns)): current_mrn = mrns[i] if current_mrn not in printed_mrns: printed_mrns.append(current_mrn) print(current_mrn)
def update_centroid_in_db(study_instance_uid, roi_name): """ This function will recalculate the centroid of an roi based on data in the SQL DB. :param study_instance_uid: uid as specified in SQL DB :param roi_name: roi_name as specified in SQL DB """ coordinates_string = DVH_SQL().query( 'dvhs', 'roi_coord_string', "study_instance_uid = '%s' and roi_name = '%s'" % (study_instance_uid, roi_name)) roi = roi_tools.get_planes_from_string(coordinates_string[0][0]) centroid = roi_tools.calc_centroid(roi) centroid = [str(round(v, 3)) for v in centroid] DVH_SQL().update( 'dvhs', 'centroid', ','.join(centroid), "study_instance_uid = '%s' and roi_name = '%s'" % (study_instance_uid, roi_name))
def recalculate_total_mu(*custom_condition): if custom_condition: custom_condition = " AND " + custom_condition[0] else: custom_condition = '' # Get entire table beam_data = QuerySQL('Beams', "mrn != ''" + custom_condition) cnx = DVH_SQL() plan_mus = {} for i in range(0, len(beam_data.study_instance_uid)): uid = beam_data.study_instance_uid[i] beam_mu = beam_data.beam_mu[i] fxs = float(beam_data.fx_count[i]) if uid not in list(plan_mus): plan_mus[uid] = 0. plan_mus[uid] += beam_mu * fxs for uid in list(plan_mus): cnx.update('Plans', 'total_mu', str(round(plan_mus[uid], 1)), "study_instance_uid = '%s'" % uid) cnx.close()
def update_rois(self): new_options = DVH_SQL().get_unique_values( 'DVHs', 'roi_name', "study_instance_uid = '%s'" % self.uid_select.value) new_options.sort() self.roi_select['1'].options = new_options # default to an external like ROI if found if 'external' in new_options: self.roi_select['1'].value = 'external' elif 'ext' in new_options: self.roi_select['1'].value = 'ext' elif 'body' in new_options: self.roi_select['1'].value = 'body' elif 'skin' in new_options: self.roi_select['1'].value = 'skin' else: self.roi_select['1'].value = new_options[0] for i in range(2, 6): self.roi_select[str(i)].options = [''] + new_options self.roi_select[str(i)].value = ''
def update_min_distances_in_db(study_instance_uid, roi_name): """ This function will recalculate the min, mean, median, and max PTV distances an roi based on data in the SQL DB. :param study_instance_uid: uid as specified in SQL DB :param roi_name: roi_name as specified in SQL DB """ oar_coordinates_string = DVH_SQL().query( 'dvhs', 'roi_coord_string', "study_instance_uid = '%s' and roi_name = '%s'" % (study_instance_uid, roi_name)) ptv_coordinates_strings = DVH_SQL().query( 'dvhs', 'roi_coord_string', "study_instance_uid = '%s' and roi_type like 'PTV%%'" % study_instance_uid) if ptv_coordinates_strings: oar_coordinates = get_roi_coordinates_from_string( oar_coordinates_string[0][0]) ptvs = [ get_planes_from_string(ptv[0]) for ptv in ptv_coordinates_strings ] tv_coordinates = get_roi_coordinates_from_planes(get_union(ptvs)) try: min_distances = get_min_distances_to_target( oar_coordinates, tv_coordinates) DVH_SQL().update( 'dvhs', 'dist_to_ptv_min', round(float(np.min(min_distances)), 2), "study_instance_uid = '%s' and roi_name = '%s'" % (study_instance_uid, roi_name)) DVH_SQL().update( 'dvhs', 'dist_to_ptv_mean', round(float(np.mean(min_distances)), 2), "study_instance_uid = '%s' and roi_name = '%s'" % (study_instance_uid, roi_name)) DVH_SQL().update( 'dvhs', 'dist_to_ptv_median', round(float(np.median(min_distances)), 2), "study_instance_uid = '%s' and roi_name = '%s'" % (study_instance_uid, roi_name)) DVH_SQL().update( 'dvhs', 'dist_to_ptv_max', round(float(np.max(min_distances)), 2), "study_instance_uid = '%s' and roi_name = '%s'" % (study_instance_uid, roi_name)) except: print('dist_to_ptv calculation failure, skipping')
def update_cross_section_in_db(study_instance_uid, roi_name): """ This function will recalculate the centoid of an roi based on data in the SQL DB. :param study_instance_uid: uid as specified in SQL DB :param roi_name: roi_name as specified in SQL DB """ coordinates_string = DVH_SQL().query( 'dvhs', 'roi_coord_string', "study_instance_uid = '%s' and roi_name = '%s'" % (study_instance_uid, roi_name)) roi = roi_tools.get_planes_from_string(coordinates_string[0][0]) area = roi_tools.calc_cross_section(roi) DVH_SQL().update( 'dvhs', 'cross_section_max', area['max'], "study_instance_uid = '%s' and roi_name = '%s'" % (study_instance_uid, roi_name)) DVH_SQL().update( 'dvhs', 'cross_section_median', area['median'], "study_instance_uid = '%s' and roi_name = '%s'" % (study_instance_uid, roi_name))
def create_tables(): initial_label = create_tables_button.label initial_button_type = create_tables_button.button_type if initial_label == 'Cancel': create_tables_button.button_type = 'primary' create_tables_button.label = 'Create Tables' clear_tables_button.button_type = 'primary' clear_tables_button.label = 'Clear Tables' else: try: DVH_SQL().initialize_database() except: create_tables_button.button_type = 'warning' create_tables_button.label = 'No Connection' time.sleep(1.5) create_tables_button.button_type = initial_button_type create_tables_button.label = initial_label