https://faxue.inmoke.com

dir_path)def get_last_dir(self

state):缓冲距离复选框状态改变# 启用或禁用缓冲距离输入框self.buffer_spin.setEnabled(state == Qt.Checked)if state == Qt.Checked:self.buffer_spin.setToolTip(边界周边多少米内视为交界区域\n设为0则不进行交界分析)self.status_text.append(#10003; 已启用缓冲距离功能)else:self.buffer_spin.setToolTip(缓冲距离功能已禁用)self.status_text.append(#10003; 已禁用缓冲距离, nrows=5, QSplitter)from PyQt5.QtCore import Qt, '.xls']:df = pd.read_excel(self.data_file, 100, geometry=geometry,检查缓冲区if not in_original:for j, j, 0, 'latitude', app_name)def save_last_path(self, gdf):处理KML区域数据# 确定区域名称列if self.kml_name_column and self.kml_name_column in gdf.columns:gdf = gdf.rename(columns={self.kml_name_column: 'name'})else:# 尝试自动检测possible_name_cols = ['Name'。

'lon'。

'y']for pattern in lat_patterns:for i, _ = QFileDialog.getOpenFileName(self, count in mark_counts.items():stats += f {mark}: {count}个\nself.message.emit(stats)self.progress.emit(100)# 发送完成信号self.finished.emit(result_df)except Exception as e:error_msg = f处理失败:\n{str(e)}\n\n{traceback.format_exc()}self.error.emit(error_msg)# ==================== 主应用程序 ====================class ConfigurableKMLMarkerApp(QWidget):可配置的KML标记应用程序def __init__(self):super().__init__()self.data_file = Noneself.kml_file = Noneself.result_df = Noneself.kml_name_column = None# 初始化配置管理器self.config_manager = ConfigManager()self.initUI()# 加载上次的设置self.load_last_settings()def load_last_settings(self):加载上次的设置try:# 加载缓冲距离设置use_buffer, _ = QFileDialog.getOpenFileName(self, geometry, 纬度={column_mapping['lat']})# 3. 读取KML文件self.message.emit(正在读取KML文件...)gdf = self.read_kml_file()self.progress.emit(25)self.message.emit(fKML文件读取成功, pyqtSignal, sep=None, key, len(df.columns))# 设置表格self.result_table.setRowCount(max_rows)self.result_table.setColumnCount(max_cols)# 设置表头headers = df.columns.tolist()[:max_cols]self.result_table.setHorizontalHeaderLabels(headers)# 填充数据for i in range(max_rows):for j in range(max_cols):value = str(df.iloc[i。

stop:0 #3498db,共 {len(gdf)} 个区域)# 4. 处理KML区域gdf = self.process_kml_regions(gdf)# 5. 创建站点几何self.message.emit(正在创建站点几何...)geometry = [Point(xy) for xy in zip(df[column_mapping['lon']],QTableWidgetItem, 'lon', default)def save_buffer_settings(self, f'结果已成功导出到:\n{file_path}')self.status_text.append(f\n#10003; 结果已导出到: {os.path.basename(file_path)})except Exception as e:QMessageBox.critical(self, '导出结果',目前使用体验蛮不错, path):保存最后使用的路径if path: # 只保存有效路径# 保存文件的目录而不是完整路径dir_path = os.path.dirname(path)if dir_path: # 确保目录路径有效self.settings.setValue(flast_{key}_dir, index=False。

'latin1']:try:df = pd.read_csv(self.data_file, '警告', '请先选择KML文件!')return# 简化版的列选择对话框dialog = QDialog(self)dialog.setWindowTitle('选择KML列')dialog.setGeometry(400, Courier New,kml_name_column=None, QProgressBar, 'gbk', use_buffer=False, '警告'。

0, file_path)self.status_text.append(f\n#10003; 数据文件已选择: {os.path.basename(file_path)})# 尝试预览文件try:if file_path.endswith('.xlsx') or file_path.endswith('.xls'):df_preview = pd.read_excel(file_path, tb))print(f未捕获的异常:\n{error_msg})# 尝试显示错误对话框try:msg_box = QMessageBox()msg_box.setIcon(QMessageBox.Critical)msg_box.setWindowTitle(未处理的异常)msg_box.setText(f发生未处理的异常:\n{str(value)})msg_box.setDetailedText(error_msg)msg_box.exec_()except:passsys.exit(1)sys.excepthook = exception_hook# 运行主函数main() ------------------------------------ 打包单文件: 链接: https://yun.139.com/shareweb/#/w/i/2sUfEKCGvrqir 复制内容打开移动云盘PC客户端, 'name'。

QColor# ==================== 配置管理器 ====================class ConfigManager:配置管理器, QComboBox, meters):将米近似转换为度# 平均地球半径(米)R = 6371000# 1度纬度(米)meters_per_degree_lat = R * np.pi / 180# 1度经度(米)随纬度变化meters_per_degree_lon = R * np.pi / 180 * np.cos(np.radians(lat))# 返回近似的度数值return meters / ((meters_per_degree_lat + meters_per_degree_lon) / 2)def create_buffer(self, '涉及区域列表'] + [col for col in result_df.columnsif col not in ['区域标记'。

dir_path)def get_last_dir(self。

'gb2312',进行精确匹配if not use_buffer or buffer_distance = 0:for i,QPushButton, 'x']for pattern in lon_patterns:for i, buffer in enumerate(buffers):if point.within(buffer):point_region_indices[i].append(j)return point_region_indices# ==================== 数据处理线程 ====================class ConfigurableKMLMarkerThread(QThread):可配置的KML标记线程, 'centroid'):center = geometry.centroidlat = center.yelse:lat = 0# 转换为度buffer_degrees = self.meters_to_degrees_approximation(lat, 255。

cache_key)buffers.append(buffer)# 使用缓冲区进行分析for i, '名称',use_buffer=self.use_buffer, cache_key=None):创建缓冲区(带缓存)if distance_meters = 0:return geometry# 检查缓存if cache_key and cache_key in self._cached_buffers:return self._cached_buffers[cache_key]try:# 获取几何中心点if hasattr(geometry, file_path)QMessageBox.information(self, 1, '警告', 'lat', '处理错误', engine='python')else:df = pd.read_csv(self.data_file, encoding='utf-8', app_name=KMLMarkerApp):self.settings = QSettings(MyCompany, 2,支持缓冲距离开关progress = pyqtSignal(int)message = pyqtSignal(str)finished = pyqtSignal(pd.DataFrame)error = pyqtSignal(str)def __init__(self, '.join(cols[:5])}{'...' if len(cols) 5 else ''})except Exception as e:self.status_text.append(f 文件预览失败: {str(e)})def select_kml_file(self):选择KML文件# 获取上次使用的目录last_dir = self.config_manager.get_last_dir(kml)file_path。

'KML文件中没有找到属性列')returnlayout.addWidget(QLabel('请选择区域名称列:'))combo = QComboBox()combo.addItem('自动检测', buffer_distance# ==================== 空间分析工具 ====================class EnhancedSpatialAnalyzer:增强版空间分析工具, '请先选择KML文件!')return# 获取参数use_buffer = self.buffer_checkbox.isChecked()buffer_distance = self.buffer_spin.value() if use_buffer else 0# 保存当前设置self.save_current_settings()# 更新界面状态self.process_btn.setEnabled(False)self.export_btn.setEnabled(False)self.progress_bar.setVisible(True)self.progress_bar.setValue(0)# 清空之前的结果self.result_table.setRowCount(0)self.result_table.setColumnCount(0)# 显示开始信息self.status_text.append(f\n{'='*50})self.status_text.append(f开始处理...)self.status_text.append(f数据文件: {os.path.basename(self.data_file)})self.status_text.append(fKML文件: {os.path.basename(self.kml_file)})if use_buffer:self.status_text.append(f处理模式: 缓冲距离 ({buffer_distance}米))else:self.status_text.append(f处理模式: 精确匹配 (无缓冲))self.status_text.append(f{'='*50})# 创建并启动处理线程self.thread = ConfigurableKMLMarkerThread(self.data_file。

(polygon, buffer_distance, file_path)self.kml_name_column = Noneself.kml_col_label.setText('自动检测')self.status_text.append(f\n#10003; KML文件已选择: {os.path.basename(file_path)})def select_kml_column(self):选择KML列(简化版)if not self.kml_file:QMessageBox.warning(self, '警告',尝试使用数据文件所在目录if not last_export_dir and self.data_file:last_export_dir = os.path.dirname(self.data_file)# 构建默认文件名default_filename = f'站点标记结果_{time.strftime(%Y%m%d_%H%M%S)}.xlsx'if last_export_dir:default_path = os.path.join(last_export_dir, engine='openpyxl')else:df_preview = pd.read_csv(file_path,f处理过程中发生错误:\n\n{error_msg[:1000]}...)# 恢复界面状态self.process_btn.setEnabled(True)self.progress_bar.setVisible(False)def display_result(self, 2,'Excel文件 (*.xlsx *.xls);;CSV文件 (*.csv);;所有文件 (*.*)')if file_path:self.data_file = file_pathself.data_path_label.setText(f已选择: {os.path.basename(file_path)})# 保存路径到配置self.config_manager.save_last_path(data, key, value)def get_setting(self, polygon_names, df):检测数据列column_mapping = {}columns_lower = [str(col).lower() for col in df.columns]# 站点名称列name_patterns = ['站点', QSpinBox, j])item = QTableWidgetItem(value)# 为交界站点添加背景色if j == 0 and '涉及区域数' in df.columns and df.iloc[i。

sans-serif;}QGroupBox {font-weight: bold;border: 1px solid #ccc;border-radius: 5px;margin-top: 10px;padding-top: 10px;}QGroupBox::title {subcontrol-origin: margin;left: 10px;padding: 0 5px 0 5px;}QPushButton {padding: 8px 15px;border-radius: 4px;border: 1px solid #ccc;background-color: #f0f0f0;}QPushButton:hover {background-color: #e0e0e0;}QPushButton:disabled {background-color: #f5f5f5;color: #999;}QTextEdit {border: 1px solid #ccc;border-radius: 4px;font-family: Consolas, 1)# KML列设置param_layout.addWidget(QLabel('KML名称列:'), 下载次数: 0) 下载附件 效果图 2026-2-9 12:57 上传 ------------------------------------ 完整源码如下: [Python] 纯文本查看 复制代码 KML站点归属范围标记工具根据KML多边形区域标记站点归属区域import osimport sysimport timeimport tracebackimport warningsimport geopandas as gpdimport numpy as npimport pandas as pdfrom shapely.geometry import Pointwarnings.filterwarnings('ignore')from PyQt5.QtWidgets import (QApplication, crs='EPSG:4326')self.progress.emit(35)# 6. 空间分析self.message.emit(正在进行空间分析...)# 准备数据points = list(points_gdf.geometry)polygons = list(gdf.geometry)polygon_names = list(gdf['name'])# 执行空间分析point_region_indices = self.spatial_analyzer.fast_spatial_analysis(points, col in enumerate(columns_lower):if pattern in col:column_mapping['lat'] = df.columns[i]breakif 'lat' in column_mapping:break# 如果没找到。

y1:0,use_buffer, default=None):获取设置return self.settings.value(key, encoding=encoding)self.message.emit(f使用编码: {encoding})breakexcept:continueelse:df = pd.read_csv(self.data_file。

buffer_distance)def load_buffer_settings(self):加载缓冲距离设置use_buffer = self.settings.value(use_buffer,共 {len(df)} 行)# 2. 检测数据列column_mapping = self.detect_columns(df)# 使用用户指定的列名(如果有)if self.data_name_column and self.data_name_column in df.columns:column_mapping['name'] = self.data_name_column# 检查必要的列required_cols = ['name', stop:1 #2ecc71);color: white;border-radius: 8px;)title_label.setAlignment(Qt.AlignCenter)main_layout.addWidget(title_label)# 创建主分割器splitter = QSplitter(Qt.Horizontal)# 左侧控制面板control_panel = self.create_control_panel()splitter.addWidget(control_panel)# 右侧结果面板result_panel = self.create_result_panel()splitter.addWidget(result_panel)splitter.setSizes([350, '小区', col)layout.addWidget(combo)# 按钮btn_layout = QHBoxLayout()ok_btn = QPushButton('确定')cancel_btn = QPushButton('取消')def on_accept():self.kml_name_column = combo.currentData()if self.kml_name_column:self.kml_col_label.setText(self.kml_name_column)self.status_text.append(f#10003; 已选择KML区域名称列: {self.kml_name_column})else:self.kml_col_label.setText('自动检测')self.status_text.append(#10003; 使用自动检测KML区域名称列)dialog.accept()ok_btn.clicked.connect(on_accept)cancel_btn.clicked.connect(dialog.reject)btn_layout.addWidget(ok_btn)btn_layout.addWidget(cancel_btn)layout.addLayout(btn_layout)except Exception as e:layout.addWidget(QLabel(f读取KML文件失败:\n{str(e)}))dialog.setLayout(layout)dialog.exec_()def process_data(self):开始处理数据# 检查文件if not self.data_file:QMessageBox.warning(self。

buffer_distance)except Exception as e:print(f保存设置失败: {str(e)})def initUI(self):初始化用户界面self.setWindowTitle('KML站点归属范围标记工具')self.setGeometry(100, QWidget,操作更方便哦 。

use_buffer。

用于保存和加载用户设置def __init__(self, 850])main_layout.addWidget(splitter)self.setLayout(main_layout)def create_control_panel(self):创建控制面板panel = QWidget()layout = QVBoxLayout(panel)# 文件选择组file_group = QGroupBox(文件选择)file_layout = QVBoxLayout()# 数据文件data_widget = QWidget()data_layout = QVBoxLayout(data_widget)data_layout.addWidget(QLabel('数据文件:'))self.data_path_label = QLabel('未选择文件')self.data_path_label.setWordWrap(True)self.data_path_label.setStyleSheet(background-color: #f9f9f9; padding: 8px; border: 1px solid #ddd;)data_layout.addWidget(self.data_path_label)data_btn = QPushButton('选择数据文件 (Excel/CSV)')data_btn.clicked.connect(self.select_data_file)data_layout.addWidget(data_btn)file_layout.addWidget(data_widget)# KML文件kml_widget = QWidget()kml_layout = QVBoxLayout(kml_widget)kml_layout.addWidget(QLabel('KML图层:'))self.kml_path_label = QLabel('未选择文件')self.kml_path_label.setWordWrap(True)self.kml_path_label.setStyleSheet(background-color: #f9f9f9; padding: 8px; border: 1px solid #ddd;)kml_layout.addWidget(self.kml_path_label)kml_btn = QPushButton('选择KML文件')kml_btn.clicked.connect(self.select_kml_file)kml_layout.addWidget(kml_btn)file_layout.addWidget(kml_widget)file_group.setLayout(file_layout)layout.addWidget(file_group)# 参数设置组param_group = QGroupBox(处理参数)param_layout = QGridLayout()# 缓冲距离复选框param_layout.addWidget(QLabel('启用缓冲距离:'), '涉及区域列表']]result_df = result_df[cols]self.progress.emit(90)# 8. 生成统计信息self.message.emit(正在生成统计信息...)boundary_sites = result_df[result_df['涉及区域数'] 1]boundary_count = len(boundary_sites)total_count = len(result_df)stats = f处理完成!\nstats += f总站点数: {total_count}\nif self.use_buffer and self.buffer_distance 0:stats += f交界站点数: {boundary_count} ({boundary_count/total_count*100:.1f}%)\nelse:stats += f精确匹配模式, QSettingsfrom PyQt5.QtGui import QFont, buffer_distance=0):快速空间分析use_buffer: 是否使用缓冲距离buffer_distance: 缓冲距离(米)n_points = len(points)# 预分配结果数组point_region_indices = [[] for _ in range(n_points)]# 如果不使用缓冲, points,感兴趣的小伙伴可以看看 选择物业点数据(需包含物业点名称和经纬度),使用前两列数值列if 'lon' not in column_mapping or 'lat' not in column_mapping:numeric_cols = df.select_dtypes(include=[np.number]).columnsif len(numeric_cols) = 2:if 'lon' not in column_mapping:column_mapping['lon'] = numeric_cols[0]if 'lat' not in column_mapping:column_mapping['lat'] = numeric_cols[1]return column_mappingdef process_kml_regions(self, '选择数据文件',未进行交界分析)def export_result(self):导出结果if self.result_df is None:QMessageBox.warning(self, 9)app.setFont(font)# 创建并显示主窗口window = ConfigurableKMLMarkerApp()window.show()# 应用程序事件循环sys.exit(app.exec_())if __name__ == '__main__':# 设置异常处理def exception_hook(exctype, QGridLayout,选择kml图层, distance_meters, polygons, index=False)# 保存导出路径到配置self.config_manager.save_last_path(export, x2:1, value, engine='openpyxl')elif file_ext == '.csv':# 尝试多种编码for encoding in ['utf-8',便在deepseek生成了一个, point in enumerate(points):# 先检查原始多边形in_original = Falsefor j,None,需要对城市大量物业点标记归属哪个区域, col in enumerate(columns_lower):if pattern in col:column_mapping['name'] = df.columns[i]breakif 'name' in column_mapping:break# 经度列lon_patterns = ['经度', monospace;}QTableWidget {border: 1px solid #ccc;border-radius: 4px;gridline-color: #eee;}QTableWidget::item {padding: 2px;})main_layout = QVBoxLayout()# 标题title_label = QLabel('KML站点归属范围标记工具')title_label.setStyleSheet(font-size: 24px;font-weight: bold;color: #2c3e50;padding: 15px;background: qlineargradient(x1:0, '请先选择数据文件!')returnif not self.kml_file:QMessageBox.warning(self,自己又是编程小白, '成功', 前{displayed_cols}列)# 根据是否启用缓冲距离显示不同的统计use_buffer = self.buffer_checkbox.isChecked()if use_buffer and '涉及区域数' in df.columns:boundary_count = len(df[df['涉及区域数'] 1])self.status_text.append(f交界站点数量: {boundary_count} ({boundary_count/total_rows*100:.1f}%))else:self.status_text.append(f精确匹配模式, 'Description']for col in possible_name_cols:if col in gdf.columns:gdf = gdf.rename(columns={col: 'name'})breakelse:# 创建默认名称gdf['name'] = [f区域{i+1} for i in range(len(gdf))]return gdfdef run(self):主处理函数try:self.progress.emit(5)# 显示处理模式if self.use_buffer:self.message.emit(f处理模式: 使用缓冲距离 ({self.buffer_distance}米))else:self.message.emit(处理模式: 精确匹配 (不使用缓冲))# 1. 读取数据文件self.message.emit(正在读取数据文件...)df = self.read_data_file()self.progress.emit(15)self.message.emit(f数据文件读取成功。

key。

type=str)def save_setting(self, df[column_mapping['lat']])]points_gdf = gpd.GeoDataFrame(df, 1,buffer_distance)# 连接信号self.thread.progress.connect(self.update_progress)self.thread.message.connect(self.update_status)self.thread.finished.connect(self.on_processing_finished)self.thread.error.connect(self.on_processing_error)# 启动线程self.thread.start()def update_progress(self, None)for col in columns:combo.addItem(col, buffer_distance = self.config_manager.load_buffer_settings()self.buffer_checkbox.setChecked(use_buffer)self.buffer_spin.setValue(buffer_distance)self.buffer_spin.setEnabled(use_buffer)self.status_text.append(#10003; 已加载上次的设置)except Exception as e:self.status_text.append(f加载设置失败: {str(e)})def save_current_settings(self):保存当前设置try:# 保存缓冲距离设置use_buffer = self.buffer_checkbox.isChecked()buffer_distance = self.buffer_spin.value()self.config_manager.save_buffer_settings(use_buffer, df):显示结果# 限制显示的行数和列数max_rows = min(200, buffer_distance):保存缓冲距离设置self.settings.setValue(use_buffer, 300)layout = QVBoxLayout()# 尝试读取KML列try:gdf = gpd.read_file(self.kml_file。

使用精确匹配)# 保存设置self.save_current_settings()def select_data_file(self):选择数据文件# 获取上次使用的目录last_dir = self.config_manager.get_last_dir(data)file_path,buffer_distance=self.buffer_distance)self.progress.emit(70)# 7. 生成结果self.message.emit(正在生成结果...)# 创建结果列表results = []for i,self.kml_file, encoding='utf-8', # 自动检测数据列self.kml_name_column,支持可选的缓冲距离def __init__(self):self._cached_buffers = {}@staticmethoddef meters_to_degrees_approximation(lat, QFileDialog,网上找了个工具使用需要付费, 'name']for pattern in name_patterns:for i, True, Arial。

len(df))max_cols = min(10, item)# 自动调整列宽self.result_table.resizeColumnsToContents()# 显示统计信息total_rows = len(df)displayed_rows = max_rowsdisplayed_cols = max_colsself.status_text.append(f\n结果统计:)self.status_text.append(f总数据行数: {total_rows})self.status_text.append(f显示数据: 前{displayed_rows}行, polygon in enumerate(polygons):if point.within(polygon):point_region_indices[i].append(j)break # 找到第一个匹配的区域就停止else:# 使用缓冲区buffers = []for j, df.columns.get_loc('涉及区域数')] 1:item.setBackground(QColor(255,不进行交界分析\n# 显示前5个最常见的标记mark_counts = result_df['区域标记'].value_counts().head(5)stats += \n前5个区域标记:\nfor mark, '选择KML文件', error_msg):处理错误# 在状态栏显示错误self.status_text.append(f\n#10007; 处理失败)self.status_text.append(f错误信息: {error_msg[:500]}{'...' if len(error_msg) 500 else ''})# 显示详细错误对话框QMessageBox.critical(self。

自用准确度和处理效率还挺不错, tb):全局异常处理error_msg = ''.join(traceback.format_exception(exctype, last_dir,点击处理即可, buffer_distance=100):super().__init__()self.data_file = data_fileself.kml_file = kml_fileself.data_name_column = data_name_columnself.kml_name_column = kml_name_columnself.use_buffer = use_bufferself.buffer_distance = buffer_distanceself.spatial_analyzer = EnhancedSpatialAnalyzer()def read_data_file(self):读取数据文件file_ext = os.path.splitext(self.data_file)[1].lower()if file_ext in ['.xlsx', QTableWidget, 800)# 设置样式self.setStyleSheet(QWidget {font-family: Microsoft YaHei, f经度={column_mapping['lon']}, polygon_names, sep=None, '名称', f'导出结果时发生错误:\n{str(e)}')self.status_text.append(f\n#10007; 导出失败: {str(e)})# ==================== 应用程序入口 ====================def main():应用程序主函数# 创建应用程序app = QApplication(sys.argv)app.setStyle('Fusion')# 设置应用程序信息app.setApplicationName(KML站点归属范围标记工具)app.setApplicationVersion(2.0.0)# 设置组织信息(用于QSettings)app.setOrganizationName(MyCompany)# 设置全局字体font = QFont(Microsoft YaHei。

'导出失败', engine='python')if df.empty:raise ValueError(数据文件为空)return dfdef read_kml_file(self):读取KML文件try:gdf = gpd.read_file(self.kml_file。

distance_meters)# 创建缓冲区buffered = geometry.buffer(buffer_degrees)# 缓存结果if cache_key:self._cached_buffers[cache_key] = bufferedreturn bufferedexcept Exception as e:print(f创建缓冲区失败: {str(e)})return geometrydef fast_spatial_analysis(self, 0)self.buffer_spin = QSpinBox()self.buffer_spin.setRange(0, 'lat']for col in required_cols:if col not in column_mapping:raise Exception(f未找到{col}列。

QTextEdit, 1)# 交界距离输入框param_layout.addWidget(QLabel('交界距离:'), 2)param_group.setLayout(param_layout)layout.addWidget(param_group)# 处理按钮self.process_btn = QPushButton('开始处理')self.process_btn.setStyleSheet(QPushButton {background-color: #3498db;color: white;font-weight: bold;padding: 12px;font-size: 14px;}QPushButton:hover {background-color: #2980b9;}QPushButton:disabled {background-color: #95a5a6;})self.process_btn.clicked.connect(self.process_data)layout.addWidget(self.process_btn)# 导出按钮self.export_btn = QPushButton('导出结果')self.export_btn.setEnabled(False)self.export_btn.setStyleSheet(QPushButton {background-color: #2ecc71;color: white;font-weight: bold;padding: 12px;font-size: 14px;}QPushButton:hover {background-color: #27ae60;}QPushButton:disabled {background-color: #95a5a6;})self.export_btn.clicked.connect(self.export_result)layout.addWidget(self.export_btn)layout.addStretch()return paneldef create_result_panel(self):创建结果面板panel = QWidget()layout = QVBoxLayout(panel)# 进度条self.progress_bar = QProgressBar()self.progress_bar.setVisible(False)layout.addWidget(self.progress_bar)# 状态信息self.status_text = QTextEdit()self.status_text.setReadOnly(True)self.status_text.setMaximumHeight(150)self.status_text.setText(欢迎使用KML站点归属范围标记工具\n\n请按以下步骤操作:\n1. 选择数据文件 (Excel/CSV格式)\n2. 选择KML图层文件\n3. 设置处理参数\n4. 点击'开始处理')layout.addWidget(self.status_text)# 结果表格result_group = QGroupBox(处理结果)result_layout = QVBoxLayout()self.result_table = QTableWidget()self.result_table.setAlternatingRowColors(True)self.result_table.horizontalHeader().setStretchLastSection(True)result_layout.addWidget(self.result_table)result_group.setLayout(result_layout)layout.addWidget(result_group)return paneldef on_buffer_checkbox_changed(self, 1200, driver='KML')if gdf.empty:raise ValueError(KML文件为空)# 修复几何问题gdf = gdf[~gdf.geometry.isnull()]gdf = gdf[gdf.geometry.is_valid]if gdf.empty:raise ValueError(KML文件中没有有效的几何数据)return gdfexcept Exception as e:# 尝试其他读取方式try:gdf = gpd.read_file(self.kml_file)return gdfexcept:raise Exception(f读取KML文件失败: {str(e)})def detect_columns(self, driver='KML')columns = [col for col in gdf.columns if col != 'geometry']if not columns:QMessageBox.warning(self。

message):更新状态信息self.status_text.append(message)def on_processing_finished(self,QGroupBox, name) in enumerate(zip(polygons, polygons, polygon in enumerate(polygons):if point.within(polygon):point_region_indices[i].append(j)in_original = Truebreak# 如果不在原始多边形内, 'utf-8-sig',然后可以记忆上次导入导出的路径和设置 结果图: 73a4887e-72a1-4322-bd32-c203dadc9a6b.png (52.58 KB, encoding='utf-8-sig')else:self.result_df.to_excel(file_path, '涉及区域数', use_buffer)self.settings.setValue(buffer_distance。

default_path, 2, QLabel, data_file, 1)select_col_btn = QPushButton('手动选择')select_col_btn.clicked.connect(self.select_kml_column)param_layout.addWidget(select_col_btn, point in enumerate(points):for j。

value):保存设置self.settings.setValue(key, '没有可导出的结果!')return# 获取上次使用的导出目录last_export_dir = self.config_manager.get_last_dir(export)# 如果没有上次的导出目录, 前5列: {'。

QVBoxLayout, 300, col in enumerate(columns_lower):if pattern in col:column_mapping['lon'] = df.columns[i]breakif 'lon' in column_mapping:break# 纬度列lat_patterns = ['纬度', y2:0, 'description'。

region_indices in enumerate(point_region_indices):if not region_indices:# 不在任何区域内mark = region_count = 0region_list = else:# 获取区域名称region_names = [polygon_names[idx] for idx in region_indices]region_names = list(set(region_names)) # 去重if len(region_names) == 1:mark = region_names[0]else:mark = + .join(sorted(region_names))region_count = len(region_names)region_list = , 'cell',将标记列放在前面cols = ['区域标记', data_name_column=None, 100, QHBoxLayout, type=bool)buffer_distance = self.settings.value(buffer_distance, encoding='utf-8')cols = df_preview.columns.tolist()self.status_text.append(f 文件预览: {len(cols)}列, 400。

result_df):处理完成self.result_df = result_df# 显示结果self.display_result(result_df)# 更新界面状态self.process_btn.setEnabled(True)self.export_btn.setEnabled(True)self.progress_bar.setVisible(False)self.status_text.append(\n#10003; 处理完成!)def on_processing_error(self。

'站名', polygon_names)):cache_key = f{name}_{buffer_distance}buffer = self.create_buffer(polygon。

default, '警告'。

'Excel文件 (*.xlsx);;CSV文件 (*.csv)')if file_path:try:# 确保文件有正确的扩展名if selected_filter == 'Excel文件 (*.xlsx)' and not file_path.endswith('.xlsx'):file_path += '.xlsx'elif selected_filter == 'CSV文件 (*.csv)' and not file_path.endswith('.csv'):file_path += '.csv'if file_path.endswith('.csv'):self.result_df.to_csv(file_path, 0)self.buffer_checkbox = QCheckBox()self.buffer_checkbox.setChecked(True)self.buffer_checkbox.stateChanged.connect(self.on_buffer_checkbox_changed)param_layout.addWidget(self.buffer_checkbox, default=):获取最后使用的目录return self.settings.value(flast_{key}_dir, 'longitude', type=int)return use_buffer,请手动选择)self.message.emit(f使用列: 名称={column_mapping['name']}, .join(sorted(region_names))# 获取原始数据行row = df.iloc[i].copy()row['区域标记'] = markrow['涉及区域数'] = region_countrow['涉及区域列表'] = region_listresults.append(row)# 创建结果DataFrameresult_df = pd.DataFrame(results)# 重新排列列, last_dir, kml_file, '涉及区域数', use_buffer=False, 5000)self.buffer_spin.setValue(100)self.buffer_spin.setSuffix( 米)self.buffer_spin.setToolTip(边界周边多少米内视为交界区域\n设为0则不进行交界分析)param_layout.addWidget(self.buffer_spin,然后可以选择是否拓展边界(默认不启用)。

QThread, QMessageBox, 200))item.setToolTip(交界站点 - 位于多个区域交界处)self.result_table.setItem(i, key, 'KML文件 (*.kml);;所有文件 (*.*)')if file_path:self.kml_file = file_pathself.kml_path_label.setText(f已选择: {os.path.basename(file_path)})# 保存路径到配置self.config_manager.save_last_path(kml,。

QDialog, value, QCheckBox。

由于工作需要, default_filename)else:default_path = default_filename# 选择保存路径file_path, nrows=5, 0)self.kml_col_label = QLabel('自动检测')self.kml_col_label.setStyleSheet(background-color: #f9f9f9; padding: 6px; border: 1px solid #ddd;)param_layout.addWidget(self.kml_col_label, value):更新进度self.progress_bar.setValue(value)def update_status(self, selected_filter = QFileDialog.getSaveFileName(self。

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。

相关文章阅读