You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

465 lines
21 KiB
Python

2 years ago
# -*- 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()