import os, sys
import glob
sys.path.append("..")
import matplotlib
import pandas as pd
import numpy as np
from pandas import DataFrame
import matplotlib.pyplot as plt
import matplotlib.patheffects as path_effects
from matplotlib.patches import Polygon
def extract_coordinates_from_excel(xls_dataframe: DataFrame):
df = xls_dataframe
data = df.iloc[:, :3].dropna()
data2 = df.iloc[:, 4:6].dropna(how="all").replace(np.nan, 0)
tags = data2.iloc[:, 0]
water = data2.iloc[:, 1]
names = data.iloc[:, 0]
x_coords = data.iloc[:, 1]
y_coords = data.iloc[:, 2]
coordinates_dict = {
"names": names,
"x_coords": x_coords,
"y_coords": y_coords,
"tags": tags,
"water_flow": water,
}
return coordinates_dict
def plot_data_with_triangles(
plt, data, triangle_side_length=0.1, rotation_angle=0, vertical_offset=None
):
offset = 30
rotation_angle += offset
radius = triangle_side_length / (2 * np.sin(np.pi / 3))
if vertical_offset is None:
vertical_offset = radius
for point in data:
x, y = point
angle = np.radians(rotation_angle)
triangle_x = [
x + radius * np.cos(angle),
x + radius * np.cos(angle + 2 * np.pi / 3),
x + radius * np.cos(angle + 4 * np.pi / 3),
]
triangle_y = [
y + vertical_offset + radius * np.sin(angle),
y + vertical_offset + radius * np.sin(angle + 2 * np.pi / 3),
y + vertical_offset + radius * np.sin(angle + 4 * np.pi / 3),
]
plt.fill(triangle_x, triangle_y, color="blue")
def plot_coordinates(
coordinates_dict, output_name: str = "", title: str = "", debug: bool = False
):
names = coordinates_dict["names"]
x_coords = coordinates_dict["x_coords"]
y_coords = coordinates_dict["y_coords"]
if names[0] == "右岸":
x_coords = x_coords.max() - x_coords
plt.plot(x_coords, y_coords, linestyle="-", color="black", zorder=2)
plt.fill_between(x_coords, y_coords, color="white", zorder=1)
plt.xlabel("起点距(m)")
plt.ylabel("高程(m)")
xlim_min = 0
xlim_max = x_coords.max()
ylim_min = y_coords.min() - 1
ylim_max = max(coordinates_dict["water_flow"].max(), y_coords.max()) + 1
plt.xlim(xlim_min, xlim_max)
plt.ylim(ylim_min, ylim_max)
x = []
y = []
white_border = path_effects.Stroke(linewidth=3, foreground="white")
annotate_font_size = 12
full_polygon_x = [*x_coords] + [x_coords.max(), 0]
full_polygon_y = [*y_coords] + [y_coords.max(), y_coords.max()]
minIndex = np.argmin(y_coords)
water_data = sorted(
[
[coordinates_dict["tags"][i], e]
for i, e in enumerate(coordinates_dict["water_flow"])
],
key=(lambda x: x[1]),
)
for index, each_water in enumerate(water_data):
if each_water[1] == coordinates_dict["water_flow"].max():
xytext_y = each_water[1] + annotate_font_size / 100
elif each_water[1] == coordinates_dict["water_flow"].min():
xytext_y = each_water[1] - annotate_font_size / 50
else:
xytext_y = each_water[1] + (annotate_font_size / 150)
each_label = each_water[0]
y.append(each_water[1] + 0.05)
x.append(x_coords[minIndex])
if index % 2 == 1:
label = f" {round(each_water[1],2)}m {each_label}"
ha = "left"
else:
label = f"{round(each_water[1],2)}m {each_label} "
ha = "right"
plt.annotate(
label,
(x_coords[minIndex], each_water[1]),
xytext=(x_coords[minIndex], xytext_y),
ha=ha,
fontsize=annotate_font_size,
).set_path_effects(
[white_border, path_effects.Normal()]
)
plt.axhline(y=each_water[1], color="r", linestyle="-", zorder=0)
plt.scatter(x, y, marker="v", color="b", s=50, zorder=5)
text_xy_offset = 15
left_text_x = xlim_min + (xlim_max - xlim_min) / text_xy_offset
left_text_y = ylim_max - (ylim_max - ylim_min) / text_xy_offset
left_text_xy = [left_text_x, left_text_y]
plt.annotate(
"左岸",
left_text_xy,
xytext=left_text_xy,
ha="center",
fontsize=annotate_font_size,
zorder=5,
)
right_text_x = xlim_max - (xlim_max - xlim_min) / text_xy_offset
right_text_y = ylim_max - (ylim_max - ylim_min) / text_xy_offset
right_text_xy = [right_text_x, right_text_y]
plt.annotate(
"右岸",
right_text_xy,
xytext=right_text_xy,
ha="center",
fontsize=annotate_font_size,
zorder=5,
)
plt.xticks()
plt.yticks()
plt.grid(True, zorder=2)
if title:
plt.title(title)
else:
plt.title(os.path.basename(output_name))
if debug:
plt.show()
else:
plt.savefig(output_name)
def main(target_dir: str, width: int = 1200, height: int = 768, output_dir: str = None):
"""
@Description 处理目录下面的所有.xlsx文件
- param target_dir :{str} 目标目录,绝对路径
"""
xlsx_list = glob.glob(f"{target_dir}/*.xlsx")
xls_list = glob.glob(f"{target_dir}/*.xls")
target_list = xlsx_list + xls_list
for each_xlsx in target_list:
xls = pd.ExcelFile(each_xlsx)
sheet_names = xls.sheet_names
basename = os.path.splitext(os.path.basename(each_xlsx))[0]
for each_sheet_name in sheet_names:
try:
plt.figure(figsize=(width / 100, height / 100))
df = xls.parse(each_sheet_name)
data = extract_coordinates_from_excel(df)
output_name = f"{basename}_{each_sheet_name}"
output_path = os.path.join(
output_dir or target_dir, f"{output_name}.png"
)
plot_coordinates(data, title=output_name, output_name=output_path)
except Exception as e:
print("文件处理错误,请检查: ")
print(each_xlsx)
print("sheet: ", each_sheet_name)
print("【错误信息】: ", e)
continue
if __name__ == "__main__":
width = 1200
height = 768
matplotlib.rcParams["font.family"] = "SimHei"
input_path = os.path.abspath("./data")
output_path = os.path.abspath("./jpg")
file_path = os.path.join(input_path, "抚河.xlsx")
main(input_path, width, height, output_dir=output_path)