def _finish_plot_depth_vs_tvu_qc(self): self.tvu_qc_ax.grid() self.tvu_qc_ax.set_xlim((round(self.tvu_qc_info.min / 0.1) * 0.1, self.tvu_qc_ax.get_xlim()[-1])) self.tvu_qc_ax.set_ylim(self.tvu_qc_ax.get_ylim()[::-1]) self.tvu_qc_fig.text(.5, .90, 'Grid source: %s, total nodes: %s' % (self.tvu_qc_info.basename, '{:,}'.format( self.tvu_qc_info.nr_of_nodes)), fontsize=12, ha='center') self.tvu_qc_ax.set_ylabel('Depth') png_file = "%s.QAv5.depth_vs_tvu_qc.png" % os.path.splitext( self.grids.current_basename)[0] png_path = os.path.join(self.output_folder, png_file) png_path = Helper.truncate_too_long(png_path, left_truncation=True) self.tvu_qc_fig.text(.5, .94, 'Node Depth vs. TVU QC', fontsize=18, ha='center') sub_title_txt = "Full TVU QC range" sub_title = self.tvu_qc_fig.text(.5, .86, sub_title_txt, fontsize=11, ha='center') self.tvu_qc_ax.set_xlabel(self.tvu_qc_info.histo_x_label) x_min, x_max = self.tvu_qc_ax.get_xlim() out_path = Helper.truncate_too_long(png_path.replace( '.png', '.full_range.png'), left_truncation=True) self.tvu_qc_fig.savefig(out_path, dpi=144, format='png') if x_max > 1.0: # plot zoom on good data, if applicable self.tvu_qc_ax.set_xlim((x_min, 1.0)) sub_title_txt = "Zoom on good data (TVU QC < 1.0)" sub_title.set_text(sub_title_txt) out_path = Helper.truncate_too_long(png_path.replace( '.png', '.zoom_on_good_data.png'), left_truncation=True) self.tvu_qc_fig.savefig(out_path, dpi=144, format='png')
def write_tin(cls, feature_list_a, feature_list_b, path, list_of_list=True): if not os.path.exists(os.path.dirname(path)): raise RuntimeError("the passed path does not exist: %s" % path) path = Helper.truncate_too_long(path) if not isinstance(feature_list_a, list): raise RuntimeError( "the passed parameter as feature_list_a is not a list: %s" % type(feature_list_a)) if not isinstance(feature_list_b, list): raise RuntimeError( "the passed parameter as feature_list_b is not a list: %s" % type(feature_list_b)) s57 = S57() s57.create_tin_file(filename=path, geo2edges_a=feature_list_a, geo2edges_b=feature_list_b, list_of_list=list_of_list)
def _finish_plot_depth_vs_density(self): if self.density_info.nr_of_nodes > 1000: self.density_ax.set_xscale('log') self.density_ax.get_xaxis().set_major_formatter(ScalarFormatter()) self.density_ax.grid() self.density_ax.set_xlim((round(self.density_info.min / 0.1) * 0.1, self.density_ax.get_xlim()[-1])) self.density_ax.set_ylim(self.density_ax.get_ylim()[::-1]) self.density_fig.text(.5, .90, 'Grid source: %s, total nodes: %s' % (self.density_info.basename, '{:,}'.format( self.density_info.nr_of_nodes)), fontsize=12, ha='center') self.density_ax.set_ylabel('Depth') png_file = "%s.QAv5.depth_vs_density.png" % os.path.splitext( self.grids.current_basename)[0] png_path = os.path.join(self.output_folder, png_file) png_path = Helper.truncate_too_long(png_path, left_truncation=True) title = self.density_fig.text(.5, .94, 'Node Depth vs. Sounding Density', fontsize=18, ha='center') self.density_ax.set_xlabel('Soundings per node') self.density_fig.savefig(png_path, dpi=144, format='png')
def write(cls, feature_list, path): if not os.path.exists(os.path.dirname(path)): raise RuntimeError("the passed path does not exist: %s" % path) path = Helper.truncate_too_long(path) if not isinstance(feature_list, list): raise RuntimeError("the passed parameter as feature_list is not a list: %s" % type(feature_list)) # generating header header = str() header += "[SVP_VERSION_2]\n" header += "%s\n" % path # generating body body = str() date_string = "%s" % datetime.now().strftime("%Y-%j %H:%M:%S") for m, ft in enumerate(feature_list): dd_lon = ft[0] dd_lat = ft[1] lon_d, lon_m, lon_s = Gd.dd2dms(dd_lon) lat_d, lat_m, lat_s = Gd.dd2dms(dd_lat) position_string = "{0:02d}:{1:02d}:{2:05.2f} {3:02d}:{4:02d}:{5:05.2f}".format(int(lat_d), int(lat_m), lat_s, int(lon_d), int(lon_m), lon_s) body += "Section " + date_string + " " + position_string + " Created by hyo2.qc\n" body += " 1.00 1500.00\n" body += " 15.00 1500.00\n" # open the file for writing with open(path, 'w') as fid: fid.write(header + body)
def write_bluenotes(cls, feature_list, path, list_of_list=True): if not os.path.exists(os.path.dirname(path)): raise RuntimeError("the passed path does not exist: %s" % path) path = Helper.truncate_too_long(path) if not isinstance(feature_list, list): raise RuntimeError( "the passed parameter as feature_list is not a list: %s" % type(feature_list)) if os.path.splitext(path)[-1] == '.shp': path = path[:-4] GdalAux() # create the data source try: ds = GdalAux.create_ogr_data_source( ogr_format=GdalAux.ogr_formats['ESRI Shapefile'], output_path=path) lyr = cls._create_ogr_point_lyr_and_fields(ds) except RuntimeError as e: logger.error("%s" % e) return if list_of_list: if len(feature_list[0]) != len(feature_list[1]): raise RuntimeError("invalid input for list of list") tmp_list = feature_list feature_list = list() for i, x in enumerate(tmp_list[0]): if len(tmp_list) >= 4: feature_list.append( [x, tmp_list[1][i], tmp_list[2][i], tmp_list[3][i]]) else: feature_list.append([x, tmp_list[1][i], tmp_list[2][i]]) for feature in feature_list: ft = ogr.Feature(lyr.GetLayerDefn()) ft.SetField('note', feature[2]) if len(feature) >= 4: ft.SetField('info', feature[3]) pt = ogr.Geometry(ogr.wkbPoint25D) pt.SetPoint(0, feature[0], feature[1]) try: ft.SetGeometry(pt) except Exception as e: RuntimeError("%s > pt: %s, %s" % (e, feature[0], feature[1])) if lyr.CreateFeature(ft) != 0: raise RuntimeError("Unable to create feature") ft.Destroy() return True
def write_bluenotes(cls, feature_list, path, list_of_list=True): if not os.path.exists(os.path.dirname(path)): raise RuntimeError("the passed path does not exist: %s" % path) path = Helper.truncate_too_long(path) if not isinstance(feature_list, list): raise RuntimeError( "the passed parameter as feature_list is not a list: %s" % type(feature_list)) s57 = S57() s57.create_blue_notes_file(filename=path, geo2notes=feature_list, list_of_list=list_of_list)
def write_soundings(cls, feature_list, path, list_of_list=False): """Feature list as list of long, lat, depth""" if not os.path.exists(os.path.dirname(path)): raise RuntimeError("the passed path does not exist: %s" % path) path = Helper.truncate_too_long(path) if not isinstance(feature_list, list): raise RuntimeError( "the passed parameter as feature_list is not a list: %s" % type(feature_list)) s57 = S57() s57.create_soundings_file(filename=path, geo3s=feature_list, list_of_list=list_of_list)
def write_soundings(cls, feature_list, path): """Feature list as list of long, lat, depth""" if not os.path.exists(os.path.dirname(path)): raise RuntimeError("the passed path does not exist: %s" % path) path = Helper.truncate_too_long(path) if not isinstance(feature_list, list): raise RuntimeError( "the passed parameter as feature_list is not a list: %s" % type(feature_list)) if os.path.splitext(path)[-1] == '.shp': path = path[:-4] GdalAux() # create the data source try: ds = GdalAux.create_ogr_data_source( ogr_format=GdalAux.ogr_formats['ESRI Shapefile'], output_path=path) lyr = cls._create_ogr_point_lyr_and_fields(ds) except RuntimeError as e: logger.error("%s" % e) return for feature in feature_list: ft = ogr.Feature(lyr.GetLayerDefn()) ft.SetField('info', "%.1f" % feature[2]) pt = ogr.Geometry(ogr.wkbPoint25D) pt.SetPoint(0, feature[0], feature[1], feature[2]) try: ft.SetGeometry(pt) except Exception as e: RuntimeError("%s > pt: %s, %s, %s" % (e, feature[0], feature[1], feature[2])) if lyr.CreateFeature(ft) != 0: raise RuntimeError("Unable to create feature") ft.Destroy() return True
def generate_pdf(self, path: str, title: str = "Document", use_colors: bool = False, small: bool = False) -> bool: """Generate a multiple-page document, with passed title and list of strings""" # this function heavily relies on PySide for pdf creation, the import is local # to the function so that the class can still be used also without Pyside try: from PySide2 import QtGui from PySide2 import QtCore from PySide2 import QtPrintSupport except (ImportError, ValueError, IOError): logger.warning( "PySide2 is not properly installed, thus you cannot create a pdf file" ) self.display() return False # some preliminary tests if len(path) == 0: logger.warning("The passed file path is empty") return False path = os.path.abspath(path) if '.pdf' not in path.lower(): logger.warning( "The passed file name has not the pdf extension: %s" % path) return False path = Helper.truncate_too_long(path) if len(self.records) == 0: logger.warning("The passed string list is empty") return False # # INITIAL SETTINGS # logger.debug("output: %s" % path) # delete the passed filename if it already exists if os.path.exists(path): os.remove(path) # prepare some drawing tools blue_pen = QtGui.QPen(QtGui.QColor(30, 30, 255)) red_pen = QtGui.QPen(QtGui.QColor(255, 30, 30)) green_pen = QtGui.QPen(QtGui.QColor(30, 200, 30)) gray_pen = QtGui.QPen(QtGui.QColor(120, 120, 120)) black_pen = QtGui.QPen(QtGui.QColor(30, 30, 30)) if small: big_font = QtGui.QFont("Arial", 9) normal_font = QtGui.QFont("Arial", 6) bold_font = QtGui.QFont("Arial", 6, QtGui.QFont.Bold) small_font = QtGui.QFont("Arial", 5) else: big_font = QtGui.QFont("Arial", 10) normal_font = QtGui.QFont("Arial", 8) bold_font = QtGui.QFont("Arial", 8, QtGui.QFont.Bold) small_font = QtGui.QFont("Arial", 7) lc_flags = QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter | QtCore.Qt.TextWordWrap cc_flags = QtCore.Qt.AlignCenter | QtCore.Qt.TextWordWrap # create the printer for pdf printer = QtPrintSupport.QPrinter( QtPrintSupport.QPrinter.HighResolution) printer.setCreator("HydrOffice") printer.setDocName("HydrOffice.pdf") printer.setOutputFormat(QtPrintSupport.QPrinter.PdfFormat) printer.setPageSize(QtPrintSupport.QPrinter.A4) printer.setOrientation(QtPrintSupport.QPrinter.Portrait) printer.setOutputFileName(path) page_rect = printer.pageRect() doc_width = page_rect.width() doc_height = page_rect.height() doc_margin = page_rect.x() # print(printer.getPageMargins(QtGui.QPrinter.DevicePixel)) # logger.info("Canvas: %sx%s" % (doc_width, doc_height)) # logger.info("Margin: %s" % doc_margin) # check if everything is ok if not printer.isValid(): logger.warning("the PDF printer is not valid") return False # # ACTUAL PRINTING # page_nr = 1 # a counter for pages section_nr = 1 row_counter = 1 if small: row_height = 330 else: row_height = 220 # this represents the height of a single row of text max_rows = (doc_height - 2 * doc_margin) / row_height hor_pad = row_height / 2 # logger.info("rows for page: %i" % max_rows) # here we start painting to the printer painter = QtGui.QPainter() if not painter.begin(printer): logger.warning("not painter begin on printer") return False def print_page_template(): """Internal helper function that print borders, logo, time stamp, etc.""" # external border painter.setPen(gray_pen) border_area = QtCore.QRect(doc_margin, doc_margin, doc_width - 2 * doc_margin, doc_height - 2 * doc_margin) painter.drawRect(border_area) # make top-area top_area = QtCore.QRect(doc_margin, doc_margin, doc_width - 2 * doc_margin, row_height * 2) painter.drawRect(top_area) # logo hyo_logo_path = os.path.join(AppInfo().app_media_path, 'poweredby.png') if not os.path.exists(hyo_logo_path): raise RuntimeError("Unable to find logo: %s" % hyo_logo_path) hyo_logo = QtGui.QPixmap(hyo_logo_path) # print("logo size: %sx%s" % (hyo_logo.width(), hyo_logo.height())) logo_area = QtCore.QRect( doc_width / 2 - hyo_logo.width() / 2, doc_margin + (row_height * 2 - hyo_logo.height()) / 2, hyo_logo.width(), hyo_logo.height()) painter.drawPixmap(logo_area, hyo_logo) # make bottom-area bottom_area = QtCore.QRect(doc_margin, doc_height - doc_margin - row_height, doc_width - 2 * doc_margin, row_height) painter.drawRect(bottom_area) # time-stamp now_time = datetime.datetime.now() painter.setFont(small_font) painter.drawText( bottom_area, cc_flags, "time-stamp: %s, %s v.%s" % (now_time.strftime("%a, %d %b %Y %H:%M:%S"), self.lib_name, self.lib_version)) # page number page_area = QtCore.QRect(doc_width - doc_margin - 2 * row_height, doc_height - doc_margin - row_height, 2 * row_height, row_height) # painter.drawRect(page_area) painter.drawText(page_area, lc_flags, "Page %s" % page_nr) # set back to 'normal' font painter.setPen(black_pen) painter.setFont(normal_font) return True print_page_template() row_area = QtCore.QRect(doc_margin + hor_pad, doc_margin, doc_width - 2 * doc_margin - 2 * hor_pad, row_height) # painter.drawRect(row_area) first_page = True for content_item in self.records: # title document only for the first page if first_page: # document title if small: row_counter = 4 else: row_counter = 3 painter.setPen(blue_pen) painter.setFont(big_font) row_area.moveTo(row_area.x(), row_area.y() + row_counter * row_height) painter.drawText(row_area, cc_flags, title) # painter.drawRect(row_area) # row_counter += 1 # set back to 'normal' font painter.setPen(black_pen) painter.setFont(normal_font) first_page = False # manage a new page creation if row_counter >= (max_rows - 4): if not printer.newPage(): logger.warning( "Failed in flushing page to disk, disk full?") return False page_nr += 1 print_page_template() row_area = QtCore.QRect( doc_margin + hor_pad, doc_margin + row_height, doc_width - 2 * doc_margin - 2 * hor_pad, row_height) row_counter = 1 row_area.moveTo(row_area.x(), row_area.y() + row_height) # painter.drawRect(row_area) last_item = content_item.split(' ')[-1] if last_item.isdigit(): if int(last_item) > 0: # troubles -> red pen if use_colors: painter.setPen(red_pen) painter.drawText(row_area, lc_flags, "- " + content_item) if use_colors: painter.setPen(black_pen) else: # all good -> black pen painter.drawText(row_area, lc_flags, "- " + content_item) elif last_item == "[SKIP_REP]": # skip report for this item if use_colors: painter.setPen(gray_pen) painter.drawText(row_area, lc_flags, "- " + content_item.rsplit(' ', 1)[0]) if use_colors: painter.setPen(black_pen) elif last_item == "[CHECK]" or last_item == "[TOTAL]": # the string is a section separator # leave an empty row row_area.moveTo(row_area.x(), row_area.y() + row_height) row_counter += 1 # write a numbered sections painter.setFont(bold_font) painter.drawText(row_area, lc_flags, "%s. %s" % (section_nr, content_item.rsplit( ' ', 1)[0])) # cut the final token painter.setFont(normal_font) section_nr += 1 elif last_item == "[SKIP_CHK]": # the string is a section separator if use_colors: painter.setPen(gray_pen) # leave an empty row row_area.moveTo(row_area.x(), row_area.y() + row_height) row_counter += 1 # write a numbered sections painter.setFont(bold_font) painter.drawText(row_area, lc_flags, "%s. %s" % (section_nr, content_item.rsplit( ' ', 1)[0])) # cut the final token painter.setFont(normal_font) section_nr += 1 if use_colors: painter.setPen(black_pen) elif last_item == "OK": # no issues, green ok if use_colors: painter.setPen(green_pen) painter.drawText(row_area, lc_flags, content_item) if use_colors: painter.setPen(black_pen) else: painter.drawText(row_area, lc_flags, content_item) row_counter += 1 # print("page %s, row %s" % (page_nr, row_counter)) # # FINISHING THE PRINTING # painter.end() return True
def write_tin(cls, feature_list_a, feature_list_b, path, list_of_list=True): if not os.path.exists(os.path.dirname(path)): raise RuntimeError("the passed path does not exist: %s" % path) path = Helper.truncate_too_long(path) if not isinstance(feature_list_a, list): raise RuntimeError("the passed parameter as feature_list_a is not a list: %s" % type(feature_list_a)) if not isinstance(feature_list_b, list): raise RuntimeError("the passed parameter as feature_list_b is not a list: %s" % type(feature_list_b)) if os.path.splitext(path)[-1] == '.kml': path = path[:-4] GdalAux() # create the data source try: ds = GdalAux.create_ogr_data_source(ogr_format=GdalAux.ogr_formats['KML'], output_path=path) lyr = cls._create_ogr_line_lyr_and_fields(ds) except RuntimeError as e: logger.error("%s" % e) return if list_of_list: if len(feature_list_a[0]) != len(feature_list_a[1]): raise RuntimeError("invalid input for list of list") if len(feature_list_b[0]) != len(feature_list_b[1]): raise RuntimeError("invalid input for list of list") if len(feature_list_a) != len(feature_list_b): raise RuntimeError("invalid input for list of list") tmp_list_a = feature_list_a feature_list_a = list() for i, x in enumerate(tmp_list_a[0]): feature_list_a.append([x, tmp_list_a[1][i]]) tmp_list_b = feature_list_b feature_list_b = list() for i, x in enumerate(tmp_list_b[0]): feature_list_b.append([x, tmp_list_b[1][i]]) for i, point in enumerate(feature_list_a): ft = ogr.Feature(lyr.GetLayerDefn()) ft.SetField('note', "tin edge") ln = ogr.Geometry(ogr.wkbLineString) ln.AddPoint(point[0], point[1]) ln.AddPoint(feature_list_b[i][0], feature_list_b[i][1]) try: ft.SetGeometry(ln) except Exception as e: RuntimeError("%s > ln: %s, %s / %s, %s" % (e, point[0], point[1], feature_list_b[i][0], feature_list_b[i][1])) if lyr.CreateFeature(ft) != 0: raise RuntimeError("Unable to create feature") ft.Destroy() return True
def run(self): logger.info( "parameters for Grid QA: force-tvu-qc=%s, has_depth=%s, has_product_uncertainty=%s, " "has_density=%s, has_tvu_qc=%s" % (self.force_tvu_qc, self.has_depth, self.has_product_uncertainty, self.has_density, self.has_tvu_qc)) logger.debug("modes -> objection detection: %s, full_coverage: %s" % (self.objection_detection, self.full_coverage)) if not self.has_depth: logger.critical("unable to identify the depth layer") return False success = True self.bathy_dict = defaultdict(int) self.density_dict = defaultdict(int) self.tvu_qc_dict = defaultdict(int) self.pct_od_dict = defaultdict(int) self.pct_cc_dict = defaultdict(int) self._init_infos() if self._depth_vs_density: self._init_plot_depth_vs_density() if self._depth_vs_tvu_qc: self._init_plot_depth_vs_tvu_qc() layers = list() if self.has_depth: layers.append(self.grids.depth_layer_name()) if self.has_product_uncertainty: layers.append(self.grids.product_uncertainty_layer_name()) if self.has_density: layers.append(self.grids.density_layer_name()) if self.has_tvu_qc: layers.append(self.grids.tvu_qc_layer_name()) logger.debug("selected layers: %s" % (layers, )) while self.grids.read_next_tile(layers=layers): if self.progress is not None: if self.progress.value < 50: self.progress.add(quantum=10) elif self.progress.value < 75: self.progress.add(quantum=1) elif self.progress.value < 90: self.progress.add(quantum=0.1) elif self.progress.value <= 99: self.progress.add(quantum=0.0001) # logger.debug("new tile") self._run_slice() self.grids.clear_tiles() # self._memory_info() # bathy self.bathy_dict = OrderedDict( sorted(self.bathy_dict.items(), key=lambda t: t[0])) bathy_counts = np.array(list(self.bathy_dict.values())) bathy_density = bathy_counts / bathy_counts.sum() bathy_cumsum = np.cumsum(bathy_density) bathy_bins = np.array(list(self.bathy_dict.keys())) / self.bathy_mul self.bathy_info.mode = bathy_bins[bathy_counts.argmax()] # noinspection PyTypeChecker self.bathy_info.p2_5 = bathy_bins[np.searchsorted(bathy_cumsum, 0.025)] # noinspection PyTypeChecker self.bathy_info.q1 = bathy_bins[np.searchsorted(bathy_cumsum, 0.25)] # noinspection PyTypeChecker self.bathy_info.median = bathy_bins[np.searchsorted(bathy_cumsum, 0.5)] # noinspection PyTypeChecker self.bathy_info.q3 = bathy_bins[np.searchsorted(bathy_cumsum, 0.75)] # noinspection PyTypeChecker self.bathy_info.p97_5 = bathy_bins[np.searchsorted( bathy_cumsum, 0.975)] # print("bathy: %s" % self.bathy_dict) # print("bathy: %s" % self.bathy_info) # save the histogram as png if self._hist_depth: bathy_png_file = "%s.QAv5.depth.png" % os.path.splitext( self.grids.current_basename)[0] bathy_png_path = os.path.join(self.output_folder, bathy_png_file) bathy_png_path = Helper.truncate_too_long(bathy_png_path, left_truncation=True) GridQAV5.plot_hysto(layer_name="Depth", bins=bathy_bins, density=bathy_density, bin_width=(1 / self.bathy_mul), grid_info=self.bathy_info, png_path=bathy_png_path) # density if self.has_density: self.density_dict = OrderedDict( sorted(self.density_dict.items(), key=lambda t: t[0])) # logger.debug("density dict: %s" % (self.density_dict, )) density_counts = np.array(list(self.density_dict.values())) density_density = density_counts / density_counts.sum() density_cumsum = np.cumsum(density_density) density_bins = np.array(list( self.density_dict.keys())) / self.density_mul if len(density_counts) > 0: self.density_info.mode = density_bins[density_counts.argmax()] # noinspection PyTypeChecker self.density_info.p2_5 = density_bins[np.searchsorted( density_cumsum, 0.025)] # noinspection PyTypeChecker self.density_info.q1 = density_bins[np.searchsorted( density_cumsum, 0.25)] # noinspection PyTypeChecker self.density_info.median = density_bins[np.searchsorted( density_cumsum, 0.5)] # noinspection PyTypeChecker self.density_info.q3 = density_bins[np.searchsorted( density_cumsum, 0.75)] # noinspection PyTypeChecker self.density_info.p97_5 = density_bins[np.searchsorted( density_cumsum, 0.975)] self.density_info.pct_of_passed_nodes = self.density_info.nr_of_passed_nodes / \ float(self.density_info.nr_of_nodes) if self.density_info.pct_of_passed_nodes >= 0.95: logger.debug( "%.2f%% of grid nodes are populated with at least 5 soundings" % (self.density_info.pct_of_passed_nodes * 100.0)) else: logger.warning( "%.2f%% of grid nodes are populated with at least 5 soundings (it should be >= 95%%)" % (self.density_info.pct_of_passed_nodes * 100.0)) success = False self.density_info.fail_left = 5 # print("density: %s" % self.density_dict) # print("density: %s" % self.density_info) # save the histogram as png if self._hist_density: density_png_file = "%s.QAv5.density.png" % os.path.splitext( self.grids.current_basename)[0] density_png_path = os.path.join(self.output_folder, density_png_file) density_png_path = Helper.truncate_too_long( density_png_path, left_truncation=True) GridQAV5.plot_hysto(layer_name="Density", bins=density_bins, density=density_density, bin_width=(1 / self.density_mul), grid_info=self.density_info, png_path=density_png_path) # save the depth vs. density plot as png if self._depth_vs_density: self._finish_plot_depth_vs_density() # delete the density array self.density_values = None # tvu qc if (self.has_tvu_qc and not self.force_tvu_qc) or self.has_product_uncertainty: if len(self.tvu_qc_dict.values()) > 0: self.tvu_qc_dict = OrderedDict( sorted(self.tvu_qc_dict.items(), key=lambda t: t[0])) tvu_qc_counts = np.array(list(self.tvu_qc_dict.values())) tvu_qc_density = tvu_qc_counts / tvu_qc_counts.sum() tvu_qc_cumsum = np.cumsum(tvu_qc_density) tvu_qc_bins = np.array(list( self.tvu_qc_dict.keys())) / self.tvu_qc_mul self.tvu_qc_info.mode = tvu_qc_bins[tvu_qc_counts.argmax()] # noinspection PyTypeChecker self.tvu_qc_info.p2_5 = tvu_qc_bins[np.searchsorted( tvu_qc_cumsum, 0.025)] # noinspection PyTypeChecker self.tvu_qc_info.q1 = tvu_qc_bins[np.searchsorted( tvu_qc_cumsum, 0.25)] # noinspection PyTypeChecker self.tvu_qc_info.median = tvu_qc_bins[np.searchsorted( tvu_qc_cumsum, 0.5)] # noinspection PyTypeChecker self.tvu_qc_info.q3 = tvu_qc_bins[np.searchsorted( tvu_qc_cumsum, 0.75)] # noinspection PyTypeChecker self.tvu_qc_info.p97_5 = tvu_qc_bins[np.searchsorted( tvu_qc_cumsum, 0.975)] self.tvu_qc_info.pct_of_passed_nodes = self.tvu_qc_info.nr_of_passed_nodes / float( self.tvu_qc_info.nr_of_nodes) if self.tvu_qc_info.pct_of_passed_nodes >= 0.95: logger.debug( "%.2f%% of grid nodes meets the maximum allowable TVU" % (self.tvu_qc_info.pct_of_passed_nodes * 100.0)) else: logger.warning( "%.2f%% of grid nodes meets the maximum allowable TVU (it should be >= 95%%)" % (self.tvu_qc_info.pct_of_passed_nodes * 100.0)) success = False self.tvu_qc_info.fail_right = 1 # print("tvu qc: %s" % self.tvu_qc_dict) # print("tvu qc: %s" % self.tvu_qc_info) # save the histogram as png if self._hist_tvu_qc: tvu_qc_png_file = "%s.QAv5.tvu_qc.png" % os.path.splitext( self.grids.current_basename)[0] tvu_qc_png_path = os.path.join(self.output_folder, tvu_qc_png_file) tvu_qc_png_path = Helper.truncate_too_long( tvu_qc_png_path, left_truncation=True) GridQAV5.plot_hysto(layer_name="TVU QC", bins=tvu_qc_bins, density=tvu_qc_density, bin_width=(1 / self.tvu_qc_mul), grid_info=self.tvu_qc_info, png_path=tvu_qc_png_path) # save the depth vs. tvu qc plot as png if self._depth_vs_tvu_qc: self._finish_plot_depth_vs_tvu_qc() # delete the array self.tvu_qc_values = None # del self.grids.tvu_qc # res pct if self.grids.is_vr(): # - PCT OD if self.objection_detection: self.pct_od_dict = OrderedDict( sorted(self.pct_od_dict.items(), key=lambda t: t[0])) # logger.debug("%s" % dict(self.pct_od_dict)) pct_od_counts = np.array(list(self.pct_od_dict.values())) pct_od_density = pct_od_counts / pct_od_counts.sum() pct_od_cumsum = np.cumsum(pct_od_density) pct_od_bins = np.array(list( self.pct_od_dict.keys())) / self.pct_od_mul self.pct_od_info.mode = pct_od_bins[pct_od_counts.argmax()] # noinspection PyTypeChecker self.pct_od_info.p2_5 = pct_od_bins[np.searchsorted( pct_od_cumsum, 0.025)] # noinspection PyTypeChecker self.pct_od_info.q1 = pct_od_bins[np.searchsorted( pct_od_cumsum, 0.25)] # noinspection PyTypeChecker self.pct_od_info.median = pct_od_bins[np.searchsorted( pct_od_cumsum, 0.5)] # noinspection PyTypeChecker self.pct_od_info.q3 = pct_od_bins[np.searchsorted( pct_od_cumsum, 0.75)] # noinspection PyTypeChecker self.pct_od_info.p97_5 = pct_od_bins[np.searchsorted( pct_od_cumsum, 0.975)] self.pct_od_info.pct_of_passed_nodes = self.pct_od_info.nr_of_passed_nodes / float( self.pct_od_info.nr_of_nodes) if self.pct_od_info.pct_of_passed_nodes >= 0.95: logger.debug( "%.2f%% of grid nodes meets the coarsest allowable resolution" % (self.pct_od_info.pct_of_passed_nodes * 100.0)) else: logger.warning( "%.2f%% of grid nodes meets the coarsest allowable resolution (it should be >= 95%%)" % (self.pct_od_info.pct_of_passed_nodes * 100.0)) success = False self.pct_od_info.fail_right = 1 # print("pct od: %s" % self.pct_od_dict) # print("pct od: %s" % self.pct_od_info) # save the histogram as png if self._hist_pct_res: pct_od_png_file = "%s.QAv5.pct_res.obj_det.png" % os.path.splitext( self.grids.current_basename)[0] pct_od_png_path = os.path.join(self.output_folder, pct_od_png_file) pct_od_png_path = Helper.truncate_too_long( pct_od_png_path, left_truncation=True) GridQAV5.plot_hysto(layer_name="RES OD", bins=pct_od_bins, density=pct_od_density, bin_width=0.1, grid_info=self.pct_od_info, png_path=pct_od_png_path) # delete the array self.pct_od_values = None # - PCT CC if self.full_coverage: self.pct_cc_dict = OrderedDict( sorted(self.pct_cc_dict.items(), key=lambda t: t[0])) # logger.debug("%s" % dict(self.pct_cc_dict)) pct_cc_counts = np.array(list(self.pct_cc_dict.values())) pct_cc_density = pct_cc_counts / pct_cc_counts.sum() pct_cc_cumsum = np.cumsum(pct_cc_density) pct_cc_bins = np.array(list( self.pct_cc_dict.keys())) / self.pct_cc_mul self.pct_cc_info.mode = pct_cc_bins[pct_cc_counts.argmax()] # noinspection PyTypeChecker self.pct_cc_info.p2_5 = pct_cc_bins[np.searchsorted( pct_cc_cumsum, 0.025)] # noinspection PyTypeChecker self.pct_cc_info.q1 = pct_cc_bins[np.searchsorted( pct_cc_cumsum, 0.25)] # noinspection PyTypeChecker self.pct_cc_info.median = pct_cc_bins[np.searchsorted( pct_cc_cumsum, 0.5)] # noinspection PyTypeChecker self.pct_cc_info.q3 = pct_cc_bins[np.searchsorted( pct_cc_cumsum, 0.75)] # noinspection PyTypeChecker self.pct_cc_info.p97_5 = pct_cc_bins[np.searchsorted( pct_cc_cumsum, 0.975)] self.pct_cc_info.pct_of_passed_nodes = self.pct_cc_info.nr_of_passed_nodes / float( self.pct_cc_info.nr_of_nodes) if self.pct_cc_info.pct_of_passed_nodes >= 0.95: logger.debug( "%.2f%% of grid nodes meets the coarsest allowable resolution" % (self.pct_cc_info.pct_of_passed_nodes * 100.0)) else: logger.warning( "%.2f%% of grid nodes meets the coarsest allowable resolution (it should be >= 95%%)" % (self.pct_cc_info.pct_of_passed_nodes * 100.0)) success = False self.pct_cc_info.fail_right = 1 # print("pct od: %s" % self.pct_cc_dict) # print("pct od: %s" % self.pct_cc_info) # save the histogram as png if self._hist_pct_res: pct_cc_png_file = "%s.QAv5.pct_res.full_cov.png" % os.path.splitext( self.grids.current_basename)[0] pct_cc_png_path = os.path.join(self.output_folder, pct_cc_png_file) pct_cc_png_path = Helper.truncate_too_long( pct_cc_png_path, left_truncation=True) GridQAV5.plot_hysto(layer_name="RES FC", bins=pct_cc_bins, density=pct_cc_density, bin_width=0.1, grid_info=self.pct_cc_info, png_path=pct_cc_png_path) # delete the array self.pct_cc_values = None return success