diff --git a/QT/main_3.ui b/QT/main_3.ui new file mode 100644 index 0000000..8db4a68 --- /dev/null +++ b/QT/main_3.ui @@ -0,0 +1,300 @@ + + + Form + + + + 0 + 0 + 790 + 757 + + + + Form + + + + + + + + + + 请导入数据文件 + + + + + + + 选择文件 + + + + + + + + + + + levels: + + + + + + + 14 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + gWeight: + + + + + + + 15 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 图例颜色选择 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + colorbar选择 + + + + + + + + + + + 请导入井文件 + + + + + + + 选择文件 + + + + + + + + + + + 油井颜色选择 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 水井颜色选择 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 包围盒 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 长短轴 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 轴长 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 轴向 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 清除数据 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 切换比例 + + + + + + + + + + + + + + + diff --git a/main_4.py b/main_4.py new file mode 100644 index 0000000..eddd056 --- /dev/null +++ b/main_4.py @@ -0,0 +1,464 @@ +# -*- coding: utf-8 -*- +import sys +from PySide6.QtWidgets import QApplication, QMainWindow, QGraphicsView, QFileDialog, QColorDialog +from PySide6.QtUiTools import QUiLoader +from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas +from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar +from matplotlib.figure import Figure +import matplotlib.pyplot as plt +from PySide6.QtWidgets import QVBoxLayout +import CREAT +import numpy as np +import matplotlib as mpl +from matplotlib.path import Path +from matplotlib.patches import Patch +from PySide6.QtGui import QPalette +import random +from scipy.spatial import ConvexHull +# plt.legend(prop={'family': 'SimHei', 'size': 15}) + + +class MainWindow(QMainWindow): + def __init__(self): + super().__init__() + self.toolbar = None + self.canvas = None + self.file_paths = [] + self.get_color = lambda n: list(map(lambda i: "#" + "%06x" % random.randint(0, 0xFFFFFF),range(n))) + self.color = self.get_color(100) # 图例颜色选择值 + self.colorbar = 'jet' + self.num = len(self.color) # 记录选择颜色的次数 + self.oilwell_color = 'k' + self.waterwell_color = 'k' + self.chose = 0 + self.num = 0 + self.box = 0 + self.axes = 0 + self.angle_axes = 0 + self.length_axes = 0 + self.datachange = 0 + self.wellchange = 0 + # 加载UI文件 + self.ui = QUiLoader().load('QT/main_3.ui') + self.color_bar() + self.ui.legend_color.clicked.connect(self.legend_color_chose) # 选择图例颜色 + self.ui.colorbar_chose.currentTextChanged.connect(self.update_colorbar) # 更新colorbar + self.ui.chose_oilwell_color.clicked.connect(lambda: self.oil_well_color()) # 选择油井颜色 + self.ui.chose_oilwell_color.clicked.connect(lambda: self.plot_density()) # 更新油井颜色 + self.ui.chose_waterwell_color.clicked.connect(lambda: self.water_well_color()) # 选择水井颜色 + self.ui.chose_waterwell_color.clicked.connect(lambda: self.plot_density()) # 更新水井颜色 + # 更新图窗 + self.ui.graphicsView.repaint() + self.ui.graphicsView.update() + self.graphics_layout = QVBoxLayout(self.ui.graphicsView) + + self.ui.chose_datafile_button.clicked.connect(self.choose_datafile) + self.ui.chose_wellfile_button.clicked.connect(self.choose_wellfile) + + self.ui.data_file_lineEdit.textChanged.connect(lambda: self.data_change()) + self.ui.well_file_lineEdit.textChanged.connect(lambda: self.well_change()) + # 绘制或清除数据和画布 + self.ui.clear_data.clicked.connect(lambda: self.clear_data()) + + # 绘图设置中心比例 + self.ui.center_scale.clicked.connect(lambda: self.center_scale()) + self.ui.center_scale.clicked.connect(lambda: self.plot_density()) + self.ui.level_chose.valueChanged.connect(lambda: self.plot_density()) + self.ui.gWeight_chose.valueChanged.connect(lambda: self.plot_density()) + + # 绘制bounding——box + self.ui.pushButton.clicked.connect(lambda: self.bounding_box()) + + self.ui.pushButton_2.clicked.connect(lambda: self.Axes()) + + self.ui.pushButton_3.clicked.connect(lambda: self.axes_angles()) + self.ui.pushButton_4.clicked.connect(lambda: self.axes_length()) + + def data_change(self): + if self.datachange == 1: + self.plot_density() + self.dat_c = 0 + + def well_change(self): + if self.wellchange == 1: + self.plot_density() + self.well_c = 0 + + def bounding_box(self): + if self.box == 0: + self.box = 1 + else: + self.box = 0 + self.plot_density() + + def Axes(self): + if self.axes==0: + self.axes=1 + else: + self.axes=0 + self.plot_density() + + def axes_angles(self): + if self.angle_axes==0: + self.angle_axes=1 + else: + self.angle_axes=0 + self.plot_density() + + def axes_length(self): + if self.length_axes==0: + self.length_axes=1 + else: + self.length_axes=0 + self.plot_density() + + def self_levels(self): + self.levels = self.ui.level_chose.value() # 选择层参数 + self.plot_density() + + def self_gWeight(self): + self.gWeight = self.self.ui.gWeight_chose.value() + self.plot_density() + + def scene_fig(self): + fig = Figure() + # 在Figure对象中添加子图 + ax = fig.add_subplot(111) + return fig, ax + + def canvas_adjust(self, fig): + if self.canvas is not None: + # 从布局中删除旧的 canvas 和 toolbar + item = self.graphics_layout.takeAt(0) + while item: + widget = item.widget() + if widget: + widget.setParent(None) + item = self.graphics_layout.takeAt(0) + self.graphics_layout.removeWidget(self.canvas) + self.canvas = FigureCanvas(fig) + self.toolbar = NavigationToolbar(self.canvas, self.ui.graphicsView) + self.toolbar.setParent(self.canvas) + self.graphics_layout.addWidget(self.canvas) + self.adjustSize() + + def choose_datafile(self): + self.datachange = 0 + file_dialog = QFileDialog(self) + file_dialog.setFileMode(QFileDialog.ExistingFiles) + if file_dialog.exec(): + self.file_paths += file_dialog.selectedFiles() + self.ui.data_file_lineEdit.setText(','.join(self.file_paths)) + self.plot_density() + + def choose_wellfile(self): + self.wellchange=0 + file_dialog = QFileDialog(self) + file_dialog.setFileMode(QFileDialog.ExistingFiles) + if file_dialog.exec(): + file_paths = file_dialog.selectedFiles() + self.ui.well_file_lineEdit.setText(','.join(file_paths)) + self.plot_density() + + def legend_color_chose(self): + col = QColorDialog.getColor() + self.color[self.num] = col.name() + self.num += 1 + self.plot_density() + + def oil_well_color(self): + col = QColorDialog.getColor() + self.oilwell_color = col.name() + + def water_well_color(self): + col = QColorDialog.getColor() + self.waterwell_color = col.name() + + def color_bar(self): + self.ui.colorbar_chose.addItem("jet") + self.ui.colorbar_chose.addItem("viridis") + self.ui.colorbar_chose.addItem("coolwarm") + self.ui.colorbar_chose.addItem('plasma') + self.ui.colorbar_chose.addItem("magma") + self.ui.colorbar_chose.addItem("inferno") + + def update_colorbar(self): + colorbar_name = self.ui.colorbar_chose.currentText() + self.colorbar = plt.get_cmap(colorbar_name) + self.plot_density() + + def clear_data(self): + self.file_paths = [] + self.color = self.get_color(100) + self.num = 0 + self.chose = 0 + self.box = 0 + self.axes = 0 + self.angle_axes = 0 + self.length_axes = 0 + self.datachange = 0 + self.wellchange = 0 + self.ui.data_file_lineEdit.clear() + self.ui.well_file_lineEdit.clear() + self.canvas.figure.clf() # 清除画布上的内容 + self.canvas.draw() + + def center_scale(self): + if self.chose == 0: + self.chose = 1 + else: + self.chose = 0 + self.num = 0 + + def plot_density(self): + fig, ax = self.scene_fig() + data_name = self.ui.data_file_lineEdit.text().split(',') # 文件输入 =================1 + level_nums = self.ui.level_chose.value() # 层参数 =================2 + gWeight = self.ui.gWeight_chose.value() # 权重输入 =================3 + self.datachange=1 + data = CREAT.create() + legend_elements = [] + if self.num == len(data_name): + self.num = 0 + for i in range(len(data_name)): + data.data_pre(data_name[i]) + data.contours_pre(level_nums, gWeight) + + """画出密度等高线""" + f = data.f + x_min, x_max = data.x_range[0], data.x_range[1] + y_min, y_max = data.y_range[0], data.y_range[1] + levels = data.levels + + xx, yy = np.mgrid[x_min:x_max:200j, y_min:y_max:200j] + # 填充等高线图中间的区域 + + if len(data_name) > 1: + color_i = self.color[i] # """ 自动选择图例的颜色""" =================4 + level = [levels[0], levels[-1]] + ff = ax.contourf(xx, yy, f, levels=level, colors=color_i, alpha=1, zorder=len(data_name) - i) + # 生成图例 + legend_elements.append(Patch(facecolor=color_i, label='第'+f'{i+1}'+'次')) + if i == len(data_name)-1: + ax.legend(handles=legend_elements, loc='upper right', prop={'family': 'SimHei', 'size': 10}) + else: + # colorbars = 'jet' # 输入选择的colorbar =================5 + cmap = mpl.colormaps.get_cmap(self.colorbar) + colors = cmap(np.linspace(0, 1, level_nums)) + ff = ax.contourf(xx, yy, f, levels=levels, colors=colors[0:level_nums], alpha=0.5, + zorder=len(data_name) - i) + # 生成colorbar + sm = mpl.cm.ScalarMappable(cmap=cmap, norm=mpl.colors.Normalize(vmin=ff.zmin, vmax=ff.zmax)) + sm.set_array([]) + fig.colorbar(sm, ax=ax) + + ax.set_xlabel('X') + ax.set_ylabel('Y') + ax.set_title('Density Distribution') + + # 画包围盒 + # 计算凸包 + hull = ConvexHull(np.array(data.contours)) + hull_points = np.array(data.contours)[hull.vertices, :] + # 计算凸包的协方差矩阵 + hull_cov = np.cov(hull_points, rowvar=False) + # 对协方差矩阵进行SVD分解 + u, s, vt = np.linalg.svd(hull_cov) + # 计算OBB包围盒的坐标轴和长度 + axes = vt.T + # 将点云变换到以重心为原点的坐标系下 + transformed_points = np.dot(np.array(data.contours), vt) + # 计算变换后的点云的最小包围盒 + min_point = np.min(transformed_points, axis=0) + max_point = np.max(transformed_points, axis=0) + x_max, y_max = max_point[0], max_point[1] + x_min, y_min = min_point[0], min_point[1] + # 4个顶点坐标 + vertices = np.array([ + [x_min, y_min], [x_max, y_min], [x_max, y_max], [x_min, y_max]]) + vertices = np.dot(vertices, axes) + if self.box==1: + # 计算所有棱的端点坐标 + ed_1 = [0, 1, 2, 3] + ed_2 = [1, 2, 3, 0] + for i, j in zip(np.array(ed_1), np.array(ed_2)): + ax.plot([vertices[i][0], vertices[j][0]], [vertices[i][1], vertices[j][1]]) + # 标注轴向 + direct1 = vertices[0] - vertices[1] + direct2 = vertices[2] - vertices[1] + ang_1 = np.arccos(np.dot(direct1, np.array(([0, 1]))) / np.linalg.norm(direct1)) / np.pi * 180 + ang_2 = np.arccos(np.dot(direct2, np.array(([0, 1]))) / np.linalg.norm(direct2)) / np.pi * 180 + # 标注长短轴 + if np.linalg.norm(vertices[0] - vertices[1]) >= np.linalg.norm(vertices[1] - vertices[2]): + label1 = '长轴' + label2 = '短轴' + else: + label1 = '短轴' + label2 = '长轴' + # 画长短轴 + center = [0, 0] + if self.axes == 1: + ax.quiver(center[0], center[1], np.dot(axes[0],vertices[0])*axes[0][0], + np.dot(axes[0],vertices[0])*axes[0][1], angles='xy', scale=1.03, + scale_units='xy', width=0.002, zorder=len(data_name) + 1) + ax.quiver(center[0], center[1], np.dot(axes[0], vertices[2]) * axes[0][0], + np.dot(axes[0], vertices[2]) * axes[0][1], angles='xy', scale=1.03, + scale_units='xy', width=0.002, zorder=len(data_name) + 1) + ax.quiver(center[0], center[1], np.dot(axes[1], vertices[1]) * axes[1][0], + np.dot(axes[1], vertices[1]) * axes[1][1], angles='xy', scale=1.03, + scale_units='xy', width=0.002, zorder=len(data_name) + 1) + ax.quiver(center[0], center[1], np.dot(axes[1], vertices[3]) * axes[1][0], + np.dot(axes[1], vertices[3]) * axes[1][1], angles='xy', scale=1.03, + scale_units='xy', width=0.002, zorder=len(data_name) + 1) + if self.length_axes == 1: + len_1 = np.abs(np.dot(axes[0], vertices[0])) + len_2 = np.abs(np.dot(axes[0], vertices[2])) + len_3 = np.abs(np.dot(axes[1], vertices[1])) + len_4 = np.abs(np.dot(axes[1], vertices[3])) + if vertices[0][0]-vertices[1][0] >= 0: + lb1 = '右半轴长' + lb2 = '左半轴长' + else: + lb1 = '左半轴长' + lb2 = '右半轴长' + if vertices[2][0]-vertices[1][0] >= 0: + lb3 = '右半轴长' + lb4 = '左半轴长' + else: + lb3 = '左半轴长' + lb4 = '右半轴长' + center = [0, 0] + if ang_1<=90: + rota1=-ang_1 + else: + rota1=180-ang_1 + if ang_2<=90: + rota2=ang_2 + else: + rota2=180-ang_2 + ax.text(center[0] + 1 / 3 * (vertices[0][0] / 2 - vertices[1][0] / 2), + center[1] + 1 / 3 * (vertices[0][1] / 2 - vertices[1][1] / 2), + label1+lb1 + f'{round(len_1,2)}m', + fontdict={'size': '8', 'color': 'k', 'family': 'SimHei'}, rotation=rota1) # 标出距离 + ax.text(center[0]+2/3*(-vertices[0][0] / 2 + vertices[1][0] / 2), + center[1] + 2/3*(-vertices[0][1] / 2 + vertices[1][1] / 2), + label1+ lb2 + f'{round(len_2, 2)}m', + fontdict={'size': '8', 'color': 'k', 'family': 'SimHei'}, rotation=rota1) # 标出距离 + ax.text(center[0] + 1/2 * (vertices[2][0] / 2 - vertices[1][0] / 2), + center[1] + 1 / 2 * (vertices[2][1] / 2 - vertices[1][1] / 2), + label2+lb3 + f'{round(len_3, 2)}m', + fontdict={'size': '8', 'color': 'k', 'family': 'SimHei'}, rotation=rota2) # 标出距离 + ax.text(center[0] + 1 / 2 * (-vertices[2][0] / 2 + vertices[1][0] / 2), + center[1] + 1 / 2 * (-vertices[2][1] / 2 + vertices[1][1] / 2), + label2+ lb4 + f'{round(len_4, 2)}m', + fontdict={'size': '8', 'color': 'k', 'family': 'SimHei'}, rotation=rota2) # 标出距离 + if self.angle_axes == 1: + if direct1[1]>=0: + N='NE' + S='NW' + else: + N = 'NW' + S = 'NE' + if ang_1 > 90: + ang_1 = 180 - ang_1 + ax.text(center[0] + (vertices[1][0] / 2 - vertices[0][0] / 2), + center[1] + (vertices[1][1] / 2 - vertices[0][1] / 2), + label1 + N + f'{round(ang_1, 0)}$^\circ$', + fontdict={'size': '8', 'color': 'k', 'family': 'SimHei'}, rotation=ang_1) + else: + ax.text(center[0] + (vertices[0][0] / 2 - vertices[1][0] / 2), + center[1] + (vertices[0][1] / 2 - vertices[1][1] / 2), + label1 + N + f'{round(ang_1, 0)}$^\circ$', + fontdict={'size': '8', 'color': 'k', 'family': 'SimHei'}, rotation=-ang_1) + if ang_2 > 90: + ang_2=180-ang_2 + ax.text(center[0] + (vertices[1][0] / 2 - vertices[2][0] / 2), + center[1] + (vertices[1][1] / 2 - vertices[2][1] / 2), + label2 + S + f'{round(ang_2, 0)}$^\circ$', + fontdict={'size': '8', 'color': 'k', 'family': 'SimHei'}, rotation=ang_2) + else: + ax.text(center[0] + (vertices[2][0] / 2 - vertices[1][0] / 2), + center[1] + (vertices[2][1] / 2 - vertices[1][1] / 2), + label2 + S + f'{round(ang_2, 0)}$^\circ$', + fontdict={'size': '8', 'color': 'k', 'family': 'SimHei'}, rotation=ang_2) + + wells_name = self.ui.well_file_lineEdit.text() # 井文件输入 =================6 + if wells_name == '': + self.canvas_adjust(fig) + else: + wells = CREAT.well_to_edge() + wells.wells_name_and_position(wells_name) + wells.welltoedge_distance(data.contours) + self.wellchange = 1 + + """画井位信息""" + typee = wells.type + points = wells.position + namee = wells.name + min_distance = wells.min_distance + contours_p = wells.welltoedge_points + x_len = ((np.array(points)[:, 0].max()-np.array(points)[:, 0].min())//100+2)*100 + y_len = ((np.array(points)[:, 1].max()-np.array(points)[:, 1].min())//100+2)*100 + if self.chose == 1: + max_x = max(np.array([(np.array(points)[:, 0].max()//100+1)*100, (np.array(points)[:, 1].max()//100+1)*100, data.x_range[1], data.y_range[1]])) + min_x = max(np.array([(np.array(points)[:, 0].min()//100-1)*100, (np.array(points)[:, 1].min()//100-1)*100, data.x_range[0], data.y_range[0]])) + max_x = max(max_x, -min_x) + ax.set_xlim([-max_x, max_x]) + ax.set_ylim([-max_x, max_x]) + x_len = max(x_len, y_len) + y_len = x_len + + for i in range(len(points)): + is_inside = False # 标记点是否在等高线内部 + if np.linalg.norm(contours_p[i]) >= np.linalg.norm(points[i]): + is_inside = True + if typee[i][0] == 0: + # oil_color = 'black' # 输入油井颜色选择 =================8 + ax.scatter(points[i][0], points[i][1], marker='o', edgecolors=self.oilwell_color, facecolors='none', s=70) + ax.scatter(points[i][0], points[i][1], marker='o', edgecolors=self.oilwell_color, facecolors='none', s=40, + linewidths=0.5) + ax.scatter(points[i][0], points[i][1], marker='o', edgecolors=self.oilwell_color, facecolors='none', s=20) + if wells.angle[i] <= 90: + ax.text(points[i][0] - 1/35*x_len, points[i][1] - 1/30*y_len, f'{namee[i][0]}', + fontdict={'size': '8', 'color': 'b'}) # 井名信息 + elif wells.angle[i] > 270: + ax.text(points[i][0] + 3/175*x_len, points[i][1] - 1/40*y_len, f'{namee[i][0]}', + fontdict={'size': '8', 'color': 'b'}) # 井名信息 + else: + ax.text(points[i][0] - 3/80*x_len, points[i][1] + 3/175*y_len, f'{namee[i][0]}', + fontdict={'size': '8', 'color': 'b'}) # 井名信息 + if not is_inside: + # 绘制油井边缘最短距离点的箭头并标出距离 + ax.quiver(points[i][0], points[i][1], contours_p[i][0] - points[i][0], + contours_p[i][1] - points[i][1], + angles='xy', scale=1.03, + scale_units='xy', width=0.002, zorder=len(data_name) + 1) # 绘制箭头 + if np.linalg.norm(np.array(points[i])-np.array(contours_p[i])) > 50: + ax.text(points[i][0] * 1 / 2 + contours_p[i][0] * 1 / 2 + min_distance[i] / 18, + points[i][1] * 1 / 2 + contours_p[i][1] * 1 / 2 - min_distance[i] / 18, + f'{round(min_distance[i], 2)}m', + fontdict={'size': '8', 'color': 'm'}) # 标出距离 + else: + if wells.angle[i] <= 90: + ax.text(points[i][0]-3/70*x_len, points[i][1]+1/40*y_len, f'{round(min_distance[i], 2)}m', + fontdict={'size': '8', 'color': 'm'}) # 标出距离 + elif wells.angle[i] > 270: + ax.text(points[i][0] - 1/35*x_len, points[i][1] + 1/30*y_len, f'{round(min_distance[i], 2)}m', + fontdict={'size': '8', 'color': 'm'}) # 标出距离 + else: + ax.text(points[i][0] + 3/140*x_len, points[i][1] - 1/40*y_len, f'{round(min_distance[i], 2)}m', + fontdict={'size': '8', 'color': 'm'}) # 标出距离 + else: + # water_color = 'black' # 水井颜色 =================9 + ax.scatter(points[i][0], points[i][1], marker='o', edgecolors=self.waterwell_color, facecolors=self.waterwell_color, s=70, zorder=len(data_name)+1) + ax.text(points[i][0] + 15, points[i][1] - 15, f'{namee[i][0]}', + fontdict={'size': '8', 'color': 'b'}, zorder=len(data_name) + 2) # 井名信息 + continue + self.canvas_adjust(fig) + + +if __name__ == '__main__': + app = QApplication([]) + stats = MainWindow() + stats.ui.show() + app.exec()