{ "cells": [ { "cell_type": "markdown", "id": "c2af5362", "metadata": {}, "source": [ "## 0. CSV координаты в шейпфайл" ] }, { "cell_type": "code", "execution_count": 6, "id": "6fc7c48c", "metadata": {}, "outputs": [], "source": [ "import geopandas as gpd\n", "import pandas as pd\n", "import folium\n", "import os" ] }, { "cell_type": "code", "execution_count": null, "id": "e53da044", "metadata": {}, "outputs": [], "source": [ "# Считываем проекцию в формате WKT и сохраняем ее в переменной\n", "from pyproj import CRSa\n", "from shapely.geometry import LineString\n", "\n", "csv = '4_Маршруты_shapefiles (от Волковой)\\\\Исходники\\\\Орнитологический маршрут.csv'\n", "\n", "df = pd.read_csv(csv, sep=';', decimal=',')\n", "\n", "file_name = os.path.splitext(os.path.basename(csv))[0]\n", "\n", "# Создаем геометрию Point из координат\n", "geometry = gpd.points_from_xy(df['X'], df['Y'])\n", "\n", "# Создаем GeoDataFrame Gauss Kruger Zone 7= 20007\n", "gdf = gpd.GeoDataFrame(df, geometry=geometry, crs=32637)\n", "gdf.to_file(file_name + '.shp')" ] }, { "cell_type": "code", "execution_count": null, "id": "82b264e1", "metadata": {}, "outputs": [], "source": [ "gdf.explore(tiles='Esri.WorldImagery')" ] }, { "cell_type": "markdown", "id": "ab249f7b", "metadata": {}, "source": [ "#### МСК координаты в шейп (далее уже в полигон)" ] }, { "cell_type": "code", "execution_count": 1, "id": "d7f062ed", "metadata": {}, "outputs": [ { "ename": "NameError", "evalue": "name 'pd' is not defined", "output_type": "error", "traceback": [ "\u001b[31m---------------------------------------------------------------------------\u001b[39m", "\u001b[31mNameError\u001b[39m Traceback (most recent call last)", "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[1]\u001b[39m\u001b[32m, line 7\u001b[39m\n\u001b[32m 3\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01mshapely\u001b[39;00m\u001b[34;01m.\u001b[39;00m\u001b[34;01mgeometry\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m LineString\n\u001b[32m 5\u001b[39m csv = \u001b[33m'\u001b[39m\u001b[33mКладбище поселка Прикубанский.csv\u001b[39m\u001b[33m'\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m7\u001b[39m df = \u001b[43mpd\u001b[49m.read_csv(csv, sep=\u001b[33m'\u001b[39m\u001b[33m;\u001b[39m\u001b[33m'\u001b[39m, decimal=\u001b[33m'\u001b[39m\u001b[33m,\u001b[39m\u001b[33m'\u001b[39m)\n\u001b[32m 9\u001b[39m file_name = os.path.splitext(os.path.basename(csv))[\u001b[32m0\u001b[39m]\n\u001b[32m 11\u001b[39m \u001b[38;5;66;03m# Создаем геометрию Point из координат\u001b[39;00m\n", "\u001b[31mNameError\u001b[39m: name 'pd' is not defined" ] } ], "source": [ "# Считываем проекцию в формате WKT и сохраняем ее в переменной\n", "from pyproj import CRS\n", "from shapely.geometry import LineString\n", "\n", "csv = 'Кладбище поселка Прикубанский.csv'\n", "\n", "df = pd.read_csv(csv, sep=';', decimal=',')\n", "\n", "file_name = os.path.splitext(os.path.basename(csv))[0]\n", "\n", "# Создаем геометрию Point из координат\n", "geometry = gpd.points_from_xy(df['Y'], df['X'])\n", "\n", "# Создаем GeoDataFrame Gauss Kruger Zone 7= 20007\n", "from pyproj import CRS\n", "with open(r'F:\\PROJECT-Colormap\\Преобразования географических проекций (СК, ГСК-2011, МСК)\\МСК23 проекции Краснодар\\MCK-23_Zone_2N.prj', 'r') as f:\n", " msk23_2 = f.read()\n", "\n", "gdf = gpd.GeoDataFrame(df, geometry=geometry, crs=msk23_2)\n", "gdf.to_file(file_name + '.shp')" ] }, { "cell_type": "code", "execution_count": 14, "id": "77c500dd", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Shapefile с полигоном успешно сохранён: polygon.shp\n" ] } ], "source": [ "import geopandas as gpd\n", "import pandas as pd\n", "from shapely.geometry import Polygon\n", "\n", "# Читаем CSV\n", "df = pd.read_csv('Кладбище поселка Прикубанский.csv', delimiter=';', decimal=',')\n", "\n", "# Сортируем по столбцу с порядком точек (N)\n", "df_sorted = df.sort_values(by='N')\n", "\n", "# Создаём список координат (X, Y)\n", "coords = list(zip(df_sorted['Y'], df_sorted['X']))\n", "\n", "# Убедимся, что полигон замкнут (повторяем первую точку в конце)\n", "if coords[0] != coords[-1]:\n", " coords.append(coords[0])\n", "\n", "# Создаём полигон\n", "polygon = Polygon(coords)\n", "\n", "# Создаём GeoDataFrame с одним объектом\n", "gdf = gpd.GeoDataFrame(index=[0], geometry=[polygon])\n", "\n", "# Создаем GeoDataFrame Gauss Kruger Zone 7= 20007\n", "from pyproj import CRS\n", "with open(r'F:\\PROJECT-Colormap\\Преобразования географических проекций (СК, ГСК-2011, МСК)\\МСК23 проекции Краснодар\\MCK-23_Zone_2N.prj', 'r') as f:\n", " msk23_2 = f.read()\n", "gdf.set_crs(msk23_2, inplace=True)\n", "\n", "# Сохраняем в shapefile\n", "gdf.to_file('polygon.shp')\n", "\n", "print(\"Shapefile с полигоном успешно сохранён: polygon.shp\")\n" ] }, { "cell_type": "markdown", "id": "0971c4df", "metadata": {}, "source": [ "## 1. Преобразование файлов (shapefile, DXF) в различные координатные системы (в архивы и по папкам) - ОСНОВНОЕ ПО ООПТ" ] }, { "cell_type": "code", "execution_count": 2, "id": "7f795d2a-9b80-4097-861c-82525843e4dd", "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Collecting folium\n", " Downloading folium-0.20.0-py2.py3-none-any.whl.metadata (4.2 kB)\n", "Collecting branca>=0.6.0 (from folium)\n", " Downloading branca-0.8.2-py3-none-any.whl.metadata (1.7 kB)\n", "Requirement already satisfied: jinja2>=2.9 in c:\\users\\lenovo\\appdata\\local\\python\\pythoncore-3.14-64\\lib\\site-packages (from folium) (3.1.6)\n", "Requirement already satisfied: numpy in c:\\users\\lenovo\\appdata\\local\\python\\pythoncore-3.14-64\\lib\\site-packages (from folium) (2.4.2)\n", "Requirement already satisfied: requests in c:\\users\\lenovo\\appdata\\local\\python\\pythoncore-3.14-64\\lib\\site-packages (from folium) (2.32.5)\n", "Collecting xyzservices (from folium)\n", " Downloading xyzservices-2025.11.0-py3-none-any.whl.metadata (4.3 kB)\n", "Requirement already satisfied: MarkupSafe>=2.0 in c:\\users\\lenovo\\appdata\\local\\python\\pythoncore-3.14-64\\lib\\site-packages (from jinja2>=2.9->folium) (3.0.3)\n", "Requirement already satisfied: charset_normalizer<4,>=2 in c:\\users\\lenovo\\appdata\\local\\python\\pythoncore-3.14-64\\lib\\site-packages (from requests->folium) (3.4.4)\n", "Requirement already satisfied: idna<4,>=2.5 in c:\\users\\lenovo\\appdata\\local\\python\\pythoncore-3.14-64\\lib\\site-packages (from requests->folium) (3.11)\n", "Requirement already satisfied: urllib3<3,>=1.21.1 in c:\\users\\lenovo\\appdata\\local\\python\\pythoncore-3.14-64\\lib\\site-packages (from requests->folium) (2.6.3)\n", "Requirement already satisfied: certifi>=2017.4.17 in c:\\users\\lenovo\\appdata\\local\\python\\pythoncore-3.14-64\\lib\\site-packages (from requests->folium) (2026.1.4)\n", "Downloading folium-0.20.0-py2.py3-none-any.whl (113 kB)\n", "Downloading branca-0.8.2-py3-none-any.whl (26 kB)\n", "Downloading xyzservices-2025.11.0-py3-none-any.whl (93 kB)\n", "Installing collected packages: xyzservices, branca, folium\n", "\n", " ---------------------------------------- 3/3 [folium]\n", "\n", "Successfully installed branca-0.8.2 folium-0.20.0 xyzservices-2025.11.0\n", "Note: you may need to restart the kernel to use updated packages.\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "\n", "[notice] A new release of pip is available: 25.3 -> 26.0.1\n", "[notice] To update, run: C:\\Users\\Lenovo\\AppData\\Local\\Python\\pythoncore-3.14-64\\python.exe -m pip install --upgrade pip\n" ] } ], "source": [ "pip install folium" ] }, { "cell_type": "code", "execution_count": 1, "id": "a0c1ced4", "metadata": {}, "outputs": [], "source": [ "import geopandas as gpd\n", "import pandas as pd\n", "import folium\n", "import os" ] }, { "cell_type": "code", "execution_count": 2, "id": "68144dd6", "metadata": {}, "outputs": [], "source": [ "# Функция создания списка шейпфайлов для обработки\n", "def shp_lst(folder):\n", " lst = []\n", " for file in os.listdir(folder):\n", " if file.endswith(\".shp\"):\n", " lst.append(os.path.join(folder, file))\n", " print(lst[:2], '\\n', f'Всего: {len(lst)} файл(-а, -ов)')\n", " return lst" ] }, { "cell_type": "code", "execution_count": 3, "id": "7075b191", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\n", "Name: WGS 84\n", "Axis Info [ellipsoidal]:\n", "- Lat[north]: Geodetic latitude (degree)\n", "- Lon[east]: Geodetic longitude (degree)\n", "Area of Use:\n", "- name: World.\n", "- bounds: (-180.0, -90.0, 180.0, 90.0)\n", "Datum: World Geodetic System 1984 ensemble\n", "- Ellipsoid: WGS 84\n", "- Prime Meridian: Greenwich" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Считываем проекцию в формате WKT и сохраняем ее в переменной\n", "from pyproj import CRS\n", "with open(r'c:\\ГИС-проекты\\2025 - ООПТ\\ООПТ из Программы\\MSK23_prj\\Russia_Cadastre_23_1.prj', 'r') as f:\n", " #wkt = f.read()\n", " msk23_1 = f.read()\n", "# crs = CRS.from_wkt(wkt)\n", "\n", "with open(r'c:\\ГИС-проекты\\2025 - ООПТ\\ООПТ из Программы\\MSK23_prj\\Russia_Cadastre_23_2.prj', 'r') as f:\n", " msk23_2 = f.read()\n", "\n", "# msk23_1 = '+proj=tmerc +lat_0=0 +lon_0=37.98333333333 +k=1 +x_0=1300000 +y_0=-4511057.628 +ellps=krass +towgs84=23.57,-140.95,-78.9,0,0,0,0.22 +units=m +no_defs'\n", "# msk23_2 = '+proj=tmerc +lat_0=0 +lon_0=40.98333333333 +k=1 +x_0=2300000 +y_0=-4511057.628 +ellps=krass +towgs84=23.57,-140.95,-78.9,0,0,0,0.22 +units=m +no_defs'\n", "\n", "# Границы районов края со столбцом зон МСК23\n", "gdf_boundary = gpd.read_file(r'c:\\ГИС-проекты\\2025 - ООПТ\\ООПТ из Программы\\Слои КК\\Borders-adm-MSK-Zone.shp')\n", "# Преобразуем в WGS84\n", "gdf_boundary = gdf_boundary.to_crs(4326)\n", "gdf_boundary.crs" ] }, { "cell_type": "code", "execution_count": 4, "id": "5b2973a2", "metadata": {}, "outputs": [], "source": [ "# Создадим два фрейма с зонам МСК23 в проекции 4326 (для простоты)\n", "msk23_1_boundary = gdf_boundary[gdf_boundary['MSK23_Zone']==1].union_all()\n", "msk23_1_boundary = gpd.GeoDataFrame({'geometry': [msk23_1_boundary]}, crs=gdf_boundary.crs)\n", "\n", "msk23_2_boundary = gdf_boundary[gdf_boundary['MSK23_Zone']==2].union_all()\n", "msk23_2_boundary = gpd.GeoDataFrame({'geometry': [msk23_2_boundary]}, crs=gdf_boundary.crs)\n" ] }, { "cell_type": "code", "execution_count": 5, "id": "4c032512", "metadata": {}, "outputs": [], "source": [ "# Словарь для создания папки для района\n", "rayon_dic = {\n", " 'esk': 'Ейский район',\n", " 'kvk': 'Кавказский район',\n", " 'kln': 'Калининский район',\n", " 'knv': 'Каневской район',\n", " 'krl': 'Крыловский район',\n", " 'krm': 'Крымский район',\n", " 'ksh': 'Кущевский район',\n", " 'mst': 'Мостовской район',\n", " 'nvk': 'Новокубанский район',\n", " 'pvl': 'Павловский район',\n", " 'tbl': 'Тбилисский район',\n", " 'tps': 'Туапсинский район',\n", " 'usp': 'Успенский район',\n", " 'ulb': 'Усть-Лабинский район',\n", " 'anp': 'Анапский район',\n", " 'brh': 'Брюховецкий район',\n", " 'glj': 'Геленджикский район',\n", " 'nvp': 'Новопокровский район',\n", " 'nvr': 'Новороссийск',\n", " 'otr': 'Отрадненский район',\n", " 'sch': 'Сочи',\n", " 'svr': 'Северский район',\n", " 'tmr': 'Темрюкский район',\n", " 'shr': 'Щербиновский район'\n", "} " ] }, { "cell_type": "code", "execution_count": 6, "id": "3bea704d", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['C:\\\\ГИС-проекты\\\\2025 - ООПТ\\\\ООПТ из Программы\\\\Input_processing\\\\nvr-vasilevskie_osypi_pp_orz-new.shp'] \n", " Всего: 1 файл(-а, -ов)\n" ] } ], "source": [ "folder = r'C:\\ГИС-проекты\\2025 - ООПТ\\ООПТ из Программы\\Input_processing'\n", "shp_lst = shp_lst(folder)" ] }, { "cell_type": "code", "execution_count": 29, "id": "11a13016-0a7e-4746-8d1a-b70b2039aade", "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Collecting ezdxf\n", " Downloading ezdxf-1.4.3-py3-none-any.whl.metadata (9.9 kB)\n", "Collecting pyparsing>=2.0.1 (from ezdxf)\n", " Downloading pyparsing-3.3.2-py3-none-any.whl.metadata (5.8 kB)\n", "Requirement already satisfied: typing_extensions>=4.6.0 in c:\\users\\lenovo\\appdata\\local\\python\\pythoncore-3.14-64\\lib\\site-packages (from ezdxf) (4.15.0)\n", "Requirement already satisfied: numpy in c:\\users\\lenovo\\appdata\\local\\python\\pythoncore-3.14-64\\lib\\site-packages (from ezdxf) (2.4.2)\n", "Collecting fonttools (from ezdxf)\n", " Downloading fonttools-4.61.1-cp314-cp314-win_amd64.whl.metadata (116 kB)\n", "Downloading ezdxf-1.4.3-py3-none-any.whl (1.3 MB)\n", " ---------------------------------------- 0.0/1.3 MB ? eta -:--:--\n", " ---------------------------------------- 0.0/1.3 MB ? eta -:--:--\n", " ---------------------------------------- 0.0/1.3 MB ? eta -:--:--\n", " ------- -------------------------------- 0.3/1.3 MB ? eta -:--:--\n", " ------- -------------------------------- 0.3/1.3 MB ? eta -:--:--\n", " --------------- ------------------------ 0.5/1.3 MB 663.7 kB/s eta 0:00:02\n", " --------------- ------------------------ 0.5/1.3 MB 663.7 kB/s eta 0:00:02\n", " ----------------------- ---------------- 0.8/1.3 MB 626.9 kB/s eta 0:00:01\n", " ----------------------- ---------------- 0.8/1.3 MB 626.9 kB/s eta 0:00:01\n", " ------------------------------- -------- 1.0/1.3 MB 588.7 kB/s eta 0:00:01\n", " ------------------------------- -------- 1.0/1.3 MB 588.7 kB/s eta 0:00:01\n", " ------------------------------- -------- 1.0/1.3 MB 588.7 kB/s eta 0:00:01\n", " ------------------------------- -------- 1.0/1.3 MB 588.7 kB/s eta 0:00:01\n", " ------------------------------- -------- 1.0/1.3 MB 588.7 kB/s eta 0:00:01\n", " ------------------------------- -------- 1.0/1.3 MB 588.7 kB/s eta 0:00:01\n", " ------------------------------- -------- 1.0/1.3 MB 588.7 kB/s eta 0:00:01\n", " ------------------------------- -------- 1.0/1.3 MB 588.7 kB/s eta 0:00:01\n", " ---------------------------------------- 1.3/1.3 MB 371.6 kB/s 0:00:03\n", "Downloading pyparsing-3.3.2-py3-none-any.whl (122 kB)\n", "Downloading fonttools-4.61.1-cp314-cp314-win_amd64.whl (2.3 MB)\n", " ---------------------------------------- 0.0/2.3 MB ? eta -:--:--\n", " ---------------------------------------- 0.0/2.3 MB ? eta -:--:--\n", " ---------------------------------------- 0.0/2.3 MB ? eta -:--:--\n", " ---- ----------------------------------- 0.3/2.3 MB ? eta -:--:--\n", " ---- ----------------------------------- 0.3/2.3 MB ? eta -:--:--\n", " ---- ----------------------------------- 0.3/2.3 MB ? eta -:--:--\n", " --------- ------------------------------ 0.5/2.3 MB 389.7 kB/s eta 0:00:05\n", " --------- ------------------------------ 0.5/2.3 MB 389.7 kB/s eta 0:00:05\n", " --------- ------------------------------ 0.5/2.3 MB 389.7 kB/s eta 0:00:05\n", " ------------- -------------------------- 0.8/2.3 MB 463.1 kB/s eta 0:00:04\n", " ------------- -------------------------- 0.8/2.3 MB 463.1 kB/s eta 0:00:04\n", " ------------- -------------------------- 0.8/2.3 MB 463.1 kB/s eta 0:00:04\n", " ------------------ --------------------- 1.0/2.3 MB 432.6 kB/s eta 0:00:03\n", " ------------------ --------------------- 1.0/2.3 MB 432.6 kB/s eta 0:00:03\n", " ------------------ --------------------- 1.0/2.3 MB 432.6 kB/s eta 0:00:03\n", " ---------------------- ----------------- 1.3/2.3 MB 436.2 kB/s eta 0:00:03\n", " ---------------------- ----------------- 1.3/2.3 MB 436.2 kB/s eta 0:00:03\n", " ---------------------- ----------------- 1.3/2.3 MB 436.2 kB/s eta 0:00:03\n", " --------------------------- ------------ 1.6/2.3 MB 431.0 kB/s eta 0:00:02\n", " --------------------------- ------------ 1.6/2.3 MB 431.0 kB/s eta 0:00:02\n", " ------------------------------- -------- 1.8/2.3 MB 447.5 kB/s eta 0:00:02\n", " ------------------------------- -------- 1.8/2.3 MB 447.5 kB/s eta 0:00:02\n", " ------------------------------- -------- 1.8/2.3 MB 447.5 kB/s eta 0:00:02\n", " ------------------------------- -------- 1.8/2.3 MB 447.5 kB/s eta 0:00:02\n", " ------------------------------------ --- 2.1/2.3 MB 421.3 kB/s eta 0:00:01\n", " ------------------------------------ --- 2.1/2.3 MB 421.3 kB/s eta 0:00:01\n", " ------------------------------------ --- 2.1/2.3 MB 421.3 kB/s eta 0:00:01\n", " ---------------------------------------- 2.3/2.3 MB 421.1 kB/s 0:00:05\n", "Installing collected packages: pyparsing, fonttools, ezdxf\n", "\n", " ------------- -------------------------- 1/3 [fonttools]\n", " ------------- -------------------------- 1/3 [fonttools]\n", " ------------- -------------------------- 1/3 [fonttools]\n", " ------------- -------------------------- 1/3 [fonttools]\n", " ------------- -------------------------- 1/3 [fonttools]\n", " ------------- -------------------------- 1/3 [fonttools]\n", " -------------------------- ------------- 2/3 [ezdxf]\n", " -------------------------- ------------- 2/3 [ezdxf]\n", " -------------------------- ------------- 2/3 [ezdxf]\n", " -------------------------- ------------- 2/3 [ezdxf]\n", " -------------------------- ------------- 2/3 [ezdxf]\n", " -------------------------- ------------- 2/3 [ezdxf]\n", " -------------------------- ------------- 2/3 [ezdxf]\n", " ---------------------------------------- 3/3 [ezdxf]\n", "\n", "Successfully installed ezdxf-1.4.3 fonttools-4.61.1 pyparsing-3.3.2\n", "Note: you may need to restart the kernel to use updated packages.\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " WARNING: The scripts fonttools.exe, pyftmerge.exe, pyftsubset.exe and ttx.exe are installed in 'C:\\Users\\Lenovo\\AppData\\Local\\Python\\pythoncore-3.14-64\\Scripts' which is not on PATH.\n", " Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.\n", " WARNING: The script ezdxf.exe is installed in 'C:\\Users\\Lenovo\\AppData\\Local\\Python\\pythoncore-3.14-64\\Scripts' which is not on PATH.\n", " Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.\n", "\n", "[notice] A new release of pip is available: 25.3 -> 26.0.1\n", "[notice] To update, run: C:\\Users\\Lenovo\\AppData\\Local\\Python\\pythoncore-3.14-64\\python.exe -m pip install --upgrade pip\n" ] } ], "source": [ "pip install ezdxf" ] }, { "cell_type": "code", "execution_count": 9, "id": "d84b7e1a", "metadata": {}, "outputs": [], "source": [ "### Сохраняет файлы в папку с именем района, которая создается автоматически по трем первым буквам шейп-файла\n", "import ezdxf\n", "import os\n", "import zipfile\n", "import fiona\n", "\n", "# Функция для создания архива шейпа в той же папке\n", "# filepath - путь к файлу, outfolder - папка для сохранения\n", "def zip_shp(filepath, outfolder):\n", " filename = os.path.splitext(os.path.basename(filepath))[0]\n", " folder = os.path.dirname(filepath)\n", " with zipfile.ZipFile(outfolder + \"//\" + f'{filename}.zip', 'w') as zip_file:\n", " # Ищем файлы с одинаковым именем, но с разным расширением\n", " for file in os.listdir(folder):\n", " if os.path.splitext(file)[0] == filename:\n", " # Добавляем файл в архив\n", " zip_file.write(os.path.join(folder, file), file) \n", " # Удаляет файл\n", " os.remove(os.path.join(folder, file))" ] }, { "cell_type": "code", "execution_count": 5, "id": "f8000661-5fda-4f3a-b112-7248b1d2d8e4", "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Processing c:\\гис-проекты\\fiona-1.10.1-cp314-cp314-win_amd64.whl\n", "Note: you may need to restart the kernel to use updated packages.\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "WARNING: Requirement 'fiona-1.10.1-cp314-cp314-win_amd64.whl' looks like a filename, but the file does not exist\n", "ERROR: Could not install packages due to an OSError: [Errno 2] No such file or directory: 'C:\\\\ГИС-проекты\\\\fiona-1.10.1-cp314-cp314-win_amd64.whl'\n", "\n", "\n", "[notice] A new release of pip is available: 25.3 -> 26.0.1\n", "[notice] To update, run: C:\\Users\\Lenovo\\AppData\\Local\\Python\\pythoncore-3.14-64\\python.exe -m pip install --upgrade pip\n" ] } ], "source": [ "pip install GDAL-3.9.1-cp314-cp314-win_amd64.whl\n", "pip install fiona-1.10.1-cp314-cp314-win_amd64.whl" ] }, { "cell_type": "code", "execution_count": 11, "id": "b0cbd752", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "C:\\Users\\Lenovo\\AppData\\Local\\Temp\\ipykernel_14212\\3067829712.py:25: UserWarning: Geometry is in a geographic CRS. Results from 'centroid' are likely incorrect. Use 'GeoSeries.to_crs()' to re-project geometries to a projected CRS before this operation.\n", "\n", " if gdf.geometry.centroid.intersects(msk23_1_boundary).any():\n" ] } ], "source": [ "# Временная папка\n", "temp = 'temp'\n", "os.makedirs(temp, exist_ok=True)\n", " \n", "# Преобразуем все файлы в проекцию WGS84 и сохраняем в формате shape и DVG\n", "for shp in shp_lst:\n", " gdf = gpd.read_file(shp)\n", " # Создать папку для района\n", " outfolder = rayon_dic[os.path.basename(shp)[:3]] # берет первый три буквы названия файла и достает из словаря полное название района\n", " os.makedirs(outfolder, exist_ok=True)\n", " \n", " ### WGS84\n", " gdf = gdf.to_crs(4326)\n", " filepath = os.path.join(temp, os.path.splitext(os.path.basename(shp))[0]) + '_WGS84' + '.shp'\n", " gdf.to_file(filename=filepath, driver='ESRI Shapefile')\n", " zip_shp(filepath, outfolder)\n", " # DXF\n", " filepath = os.path.join(outfolder, os.path.splitext(os.path.basename(shp))[0]) + '_WGS84' + '.dxf'\n", " #gdf.geometry.to_file(filepath, driver=\"DXF\")\n", " gdf.geometry.to_file(filepath, driver=\"DXF\", engine='fiona')\n", " \n", " # Раздел с МСК23 (распределение по зонам)\n", " # Для определения делаем центроид полигона, если он внутри зоны МСК1, то это зона 1, если нет, то зона 2 (предварительно пришлось преобразовать WGS84 в Меркатор - не работало)\n", " # if gdf.to_crs(3857).geometry.centroid.intersects(msk23_1_boundary).any():\n", " if gdf.geometry.centroid.intersects(msk23_1_boundary).any():\n", " gdf = gdf.to_crs(msk23_1)\n", " filepath = os.path.join(temp, os.path.splitext(os.path.basename(shp))[0]) + '_MSK23_1' + '.shp'\n", " gdf.to_file(filename=filepath, driver='ESRI Shapefile')\n", " zip_shp(filepath, outfolder)\n", " # DXF\n", " filepath = os.path.join(outfolder, os.path.splitext(os.path.basename(shp))[0]) + '_MSK23_1' + '.dxf'\n", " gdf.geometry.to_file(filepath, driver=\"DXF\")\n", " else:\n", " gdf = gdf.to_crs(msk23_2)\n", " filepath = os.path.join(temp, os.path.splitext(os.path.basename(shp))[0]) + '_MSK23_2' + '.shp'\n", " gdf.to_file(filename=filepath, driver='ESRI Shapefile')\n", " zip_shp(filepath, outfolder)\n", " # DXF\n", " filepath = os.path.join(outfolder, os.path.splitext(os.path.basename(shp))[0]) + '_MSK23_2' + '.dxf'\n", " gdf.geometry.to_file(filepath, driver=\"DXF\")\n", "\n", "\n", " \n", "# with tempfile.TemporaryDirectory() as temp_dir:\n", "# temp_dir = Path(temp_dir)\n", "# localFile = 'myshapefile'\n", "\n", "# gdf.to_file(filename=temp_dir, driver='ESRI Shapefile')\n", "\n", "# archiveFile = shutil.make_archive(localFile, 'zip', temp_dir)\n", "# shutil.rmtree(temp_dir)\n", " \n", "# # Преобразуем данные в формат DWG-DXF\n", "# filepath = os.path.join(outfolder, os.path.splitext(os.path.basename(shp))[0]) + '.dxf'\n", " \n", "# # Create a new DXF document\n", "# doc = ezdxf.new(dxfversion='R2010')\n", "# # Add a new layer to the DXF document\n", "# msp = doc.modelspace()\n", "\n", "# # Iterate through the GeoDataFrame and add geometries to the DXF\n", "# for _, row in gdf.iterrows():\n", "# if row.geometry.type == 'Point':\n", "# msp.add_point((row.geometry.x, row.geometry.y))\n", "# elif row.geometry.type in ['LineString', 'MultiLineString']:\n", "# for line in row.geometry:\n", "# msp.add_lwpolyline(line.coords)\n", "# elif row.geometry.type in ['Polygon', 'MultiPolygon']:\n", "# for poly in row.geometry:\n", "# coords = list(poly.exterior.coords)\n", "# coords.append(coords[0]) # добавляем последнюю точку координат к началу списка координат\n", "# msp.add_lwpolyline(coords)\n", "\n", "# # Save the DXF file\n", "# doc.saveas(filepath)" ] }, { "cell_type": "markdown", "id": "0dff4cdd", "metadata": {}, "source": [ "##### Преобразование файлов в DXF" ] }, { "cell_type": "code", "execution_count": 87, "id": "a33bf66c", "metadata": {}, "outputs": [], "source": [ "for shp in shp_lst:\n", " gdf = gpd.read_file(shp)\n", " # Создать папку для района\n", " outfolder = rayon_dic[os.path.basename(shp)[:3]] # берет первый три буквы названия файла и достает из словаря полное название района\n", " os.makedirs(outfolder, exist_ok=True)\n", " \n", " # DXF\n", " filepath = os.path.join(outfolder, os.path.splitext(os.path.basename(shp))[0]) + '.dxf'\n", " gdf.geometry.to_file(filepath, driver=\"DXF\")" ] }, { "cell_type": "markdown", "id": "8f6d5884", "metadata": {}, "source": [ "!!!!! ДАЛЕЕ НУЖНО РАЗБИРАТЬСЯ\n", "https://mapscaping.com/shapefile-to-dxf/" ] }, { "cell_type": "code", "execution_count": 90, "id": "2a16cebd", "metadata": { "scrolled": true }, "outputs": [ { "ename": "DataSourceError", "evalue": "input.shp: No such file or directory", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mDataSourceError\u001b[0m Traceback (most recent call last)", "Cell \u001b[1;32mIn[90], line 5\u001b[0m\n\u001b[0;32m 2\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mezdxf\u001b[39;00m\n\u001b[0;32m 4\u001b[0m \u001b[38;5;66;03m# Load the Shapefile\u001b[39;00m\n\u001b[1;32m----> 5\u001b[0m gdf \u001b[38;5;241m=\u001b[39m \u001b[43mgpd\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mread_file\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43minput.shp\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[0;32m 7\u001b[0m \u001b[38;5;66;03m# Create a new DXF document\u001b[39;00m\n\u001b[0;32m 8\u001b[0m doc \u001b[38;5;241m=\u001b[39m ezdxf\u001b[38;5;241m.\u001b[39mnew(dxfversion\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mR2010\u001b[39m\u001b[38;5;124m'\u001b[39m)\n", "File \u001b[1;32m~\\AppData\\Local\\Programs\\Python\\Python310\\lib\\site-packages\\geopandas\\io\\file.py:299\u001b[0m, in \u001b[0;36m_read_file\u001b[1;34m(filename, bbox, mask, columns, rows, engine, **kwargs)\u001b[0m\n\u001b[0;32m 296\u001b[0m from_bytes \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mTrue\u001b[39;00m\n\u001b[0;32m 298\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m engine \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mpyogrio\u001b[39m\u001b[38;5;124m\"\u001b[39m:\n\u001b[1;32m--> 299\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m _read_file_pyogrio(\n\u001b[0;32m 300\u001b[0m filename, bbox\u001b[38;5;241m=\u001b[39mbbox, mask\u001b[38;5;241m=\u001b[39mmask, columns\u001b[38;5;241m=\u001b[39mcolumns, rows\u001b[38;5;241m=\u001b[39mrows, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs\n\u001b[0;32m 301\u001b[0m )\n\u001b[0;32m 303\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m engine \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mfiona\u001b[39m\u001b[38;5;124m\"\u001b[39m:\n\u001b[0;32m 304\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m pd\u001b[38;5;241m.\u001b[39mapi\u001b[38;5;241m.\u001b[39mtypes\u001b[38;5;241m.\u001b[39mis_file_like(filename):\n", "File \u001b[1;32m~\\AppData\\Local\\Programs\\Python\\Python310\\lib\\site-packages\\geopandas\\io\\file.py:549\u001b[0m, in \u001b[0;36m_read_file_pyogrio\u001b[1;34m(path_or_bytes, bbox, mask, rows, **kwargs)\u001b[0m\n\u001b[0;32m 540\u001b[0m warnings\u001b[38;5;241m.\u001b[39mwarn(\n\u001b[0;32m 541\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mThe \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124minclude_fields\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m and \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mignore_fields\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m keywords are deprecated, and \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m 542\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mwill be removed in a future release. You can use the \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mcolumns\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m keyword \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 545\u001b[0m stacklevel\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m3\u001b[39m,\n\u001b[0;32m 546\u001b[0m )\n\u001b[0;32m 547\u001b[0m kwargs[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcolumns\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m kwargs\u001b[38;5;241m.\u001b[39mpop(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124minclude_fields\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m--> 549\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m pyogrio\u001b[38;5;241m.\u001b[39mread_dataframe(path_or_bytes, bbox\u001b[38;5;241m=\u001b[39mbbox, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n", "File \u001b[1;32m~\\AppData\\Local\\Programs\\Python\\Python310\\lib\\site-packages\\pyogrio\\geopandas.py:265\u001b[0m, in \u001b[0;36mread_dataframe\u001b[1;34m(path_or_buffer, layer, encoding, columns, read_geometry, force_2d, skip_features, max_features, where, bbox, mask, fids, sql, sql_dialect, fid_as_index, use_arrow, on_invalid, arrow_to_pandas_kwargs, **kwargs)\u001b[0m\n\u001b[0;32m 260\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m use_arrow:\n\u001b[0;32m 261\u001b[0m \u001b[38;5;66;03m# For arrow, datetimes are read as is.\u001b[39;00m\n\u001b[0;32m 262\u001b[0m \u001b[38;5;66;03m# For numpy IO, datetimes are read as string values to preserve timezone info\u001b[39;00m\n\u001b[0;32m 263\u001b[0m \u001b[38;5;66;03m# as numpy does not directly support timezones.\u001b[39;00m\n\u001b[0;32m 264\u001b[0m kwargs[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdatetime_as_string\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mTrue\u001b[39;00m\n\u001b[1;32m--> 265\u001b[0m result \u001b[38;5;241m=\u001b[39m read_func(\n\u001b[0;32m 266\u001b[0m path_or_buffer,\n\u001b[0;32m 267\u001b[0m layer\u001b[38;5;241m=\u001b[39mlayer,\n\u001b[0;32m 268\u001b[0m encoding\u001b[38;5;241m=\u001b[39mencoding,\n\u001b[0;32m 269\u001b[0m columns\u001b[38;5;241m=\u001b[39mcolumns,\n\u001b[0;32m 270\u001b[0m read_geometry\u001b[38;5;241m=\u001b[39mread_geometry,\n\u001b[0;32m 271\u001b[0m force_2d\u001b[38;5;241m=\u001b[39mgdal_force_2d,\n\u001b[0;32m 272\u001b[0m skip_features\u001b[38;5;241m=\u001b[39mskip_features,\n\u001b[0;32m 273\u001b[0m max_features\u001b[38;5;241m=\u001b[39mmax_features,\n\u001b[0;32m 274\u001b[0m where\u001b[38;5;241m=\u001b[39mwhere,\n\u001b[0;32m 275\u001b[0m bbox\u001b[38;5;241m=\u001b[39mbbox,\n\u001b[0;32m 276\u001b[0m mask\u001b[38;5;241m=\u001b[39mmask,\n\u001b[0;32m 277\u001b[0m fids\u001b[38;5;241m=\u001b[39mfids,\n\u001b[0;32m 278\u001b[0m sql\u001b[38;5;241m=\u001b[39msql,\n\u001b[0;32m 279\u001b[0m sql_dialect\u001b[38;5;241m=\u001b[39msql_dialect,\n\u001b[0;32m 280\u001b[0m return_fids\u001b[38;5;241m=\u001b[39mfid_as_index,\n\u001b[0;32m 281\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs,\n\u001b[0;32m 282\u001b[0m )\n\u001b[0;32m 284\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m use_arrow:\n\u001b[0;32m 285\u001b[0m meta, table \u001b[38;5;241m=\u001b[39m result\n", "File \u001b[1;32m~\\AppData\\Local\\Programs\\Python\\Python310\\lib\\site-packages\\pyogrio\\raw.py:198\u001b[0m, in \u001b[0;36mread\u001b[1;34m(path_or_buffer, layer, encoding, columns, read_geometry, force_2d, skip_features, max_features, where, bbox, mask, fids, sql, sql_dialect, return_fids, datetime_as_string, **kwargs)\u001b[0m\n\u001b[0;32m 59\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"Read OGR data source into numpy arrays.\u001b[39;00m\n\u001b[0;32m 60\u001b[0m \n\u001b[0;32m 61\u001b[0m \u001b[38;5;124;03mIMPORTANT: non-linear geometry types (e.g., MultiSurface) are converted\u001b[39;00m\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 194\u001b[0m \n\u001b[0;32m 195\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[0;32m 196\u001b[0m dataset_kwargs \u001b[38;5;241m=\u001b[39m _preprocess_options_key_value(kwargs) \u001b[38;5;28;01mif\u001b[39;00m kwargs \u001b[38;5;28;01melse\u001b[39;00m {}\n\u001b[1;32m--> 198\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mogr_read\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 199\u001b[0m \u001b[43m \u001b[49m\u001b[43mget_vsi_path_or_buffer\u001b[49m\u001b[43m(\u001b[49m\u001b[43mpath_or_buffer\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 200\u001b[0m \u001b[43m \u001b[49m\u001b[43mlayer\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mlayer\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 201\u001b[0m \u001b[43m \u001b[49m\u001b[43mencoding\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mencoding\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 202\u001b[0m \u001b[43m \u001b[49m\u001b[43mcolumns\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcolumns\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 203\u001b[0m \u001b[43m \u001b[49m\u001b[43mread_geometry\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mread_geometry\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 204\u001b[0m \u001b[43m \u001b[49m\u001b[43mforce_2d\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mforce_2d\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 205\u001b[0m \u001b[43m \u001b[49m\u001b[43mskip_features\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mskip_features\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 206\u001b[0m \u001b[43m \u001b[49m\u001b[43mmax_features\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmax_features\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01mor\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[0;32m 207\u001b[0m \u001b[43m \u001b[49m\u001b[43mwhere\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mwhere\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 208\u001b[0m \u001b[43m \u001b[49m\u001b[43mbbox\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mbbox\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 209\u001b[0m \u001b[43m \u001b[49m\u001b[43mmask\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m_mask_to_wkb\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmask\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 210\u001b[0m \u001b[43m \u001b[49m\u001b[43mfids\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mfids\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 211\u001b[0m \u001b[43m \u001b[49m\u001b[43msql\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43msql\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 212\u001b[0m \u001b[43m \u001b[49m\u001b[43msql_dialect\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43msql_dialect\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 213\u001b[0m \u001b[43m \u001b[49m\u001b[43mreturn_fids\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mreturn_fids\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 214\u001b[0m \u001b[43m \u001b[49m\u001b[43mdataset_kwargs\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdataset_kwargs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 215\u001b[0m \u001b[43m \u001b[49m\u001b[43mdatetime_as_string\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdatetime_as_string\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 216\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", "File \u001b[1;32mpyogrio\\\\_io.pyx:1240\u001b[0m, in \u001b[0;36mpyogrio._io.ogr_read\u001b[1;34m()\u001b[0m\n", "File \u001b[1;32mpyogrio\\\\_io.pyx:220\u001b[0m, in \u001b[0;36mpyogrio._io.ogr_open\u001b[1;34m()\u001b[0m\n", "\u001b[1;31mDataSourceError\u001b[0m: input.shp: No such file or directory" ] } ], "source": [ "import geopandas as gpd\n", "import ezdxf\n", "\n", "# Load the Shapefile\n", "gdf = gpd.read_file('input.shp')\n", "\n", "# Create a new DXF document\n", "doc = ezdxf.new(dxfversion='R2010')\n", "\n", "# Add a new layer to the DXF document\n", "msp = doc.modelspace()\n", "\n", "# Iterate through the GeoDataFrame and add geometries to the DXF\n", "for _, row in gdf.iterrows():\n", " if row.geometry.type == 'Point':\n", " msp.add_point((row.geometry.x, row.geometry.y))\n", " elif row.geometry.type in ['LineString', 'MultiLineString']:\n", " for line in row.geometry:\n", " msp.add_lwpolyline(line.coords)\n", " elif row.geometry.type in ['Polygon', 'MultiPolygon']:\n", " for poly in row.geometry:\n", " msp.add_lwpolyline(poly.exterior.coords, is_closed=True)\n", "\n", "# Save the DXF file\n", "doc.saveas('output.dxf')" ] }, { "cell_type": "code", "execution_count": null, "id": "3b2d17c5", "metadata": {}, "outputs": [], "source": [ "# Для проекции в МСК \n", "# В начале определяем зону по файлу с районами, далее преобразуем в эту зону\n", "# НЕ ДОДЕЛАН!!!!\n", "\n", "for shp in shp_lst[:3]:\n", " gdf = gpd.read_file(shp).union_all\n", " centroid = gdf.centroid\n", " centroid_gdf = gpd.GeoDataFrame(geometry=gpd.points_from_xy(centroid.x, centroid.y)).set_crs(3857)\n", " gdf_joined = gpd.sjoin(\n", " \n", " \n", " gdf = gdf.to_crs(msk23_1)\n", " \n", " filepath = os.path.join(outfolder, os.path.basename(shp))\n", " gdf.to_file(filepath)\n", "\n", " \n", "# Преобразуем данные в формат DWG-DXF\n", "import osgeo import ogr\n", "driver = ogr.GetDriverByName('DXF')\n", "ds = driver.CreateCopy('output.dxf', gdf)\n", "ds = None\n", "\n", "import pydxf\n", "dxf = pydxf.DxfFile('input.dxf')\n", "# Преобразуем DXF в DWG\n", "dwg = pydxf.DwfFile('output.dwg')\n", "dwg.write(dxf)\n" ] }, { "cell_type": "code", "execution_count": null, "id": "84e4e74e", "metadata": {}, "outputs": [], "source": [ "import pyproj\n", "x, y = gdf.centroid.x, gdf.centroid.y\n", "lon, lat = pyproj.transform(pyproj.Proj('epsg:3857'), pyproj.Proj('epsg:4326'), x, y)" ] }, { "cell_type": "code", "execution_count": null, "id": "d696791f", "metadata": {}, "outputs": [], "source": [ "# Определите зону MSK\n", "if central_meridian >= 45 and central_meridian < 48:\n", " print(\"Проекция: MSK-23.1\")\n", "elif central_meridian >= 48 and central_meridian <= 51:\n", " print(\"Проекция: MSK-23.2\")\n", "else:\n", " print(\"Проекция: MSK, но зона не определена\")" ] }, { "cell_type": "code", "execution_count": null, "id": "aedd1949", "metadata": {}, "outputs": [], "source": [ "centroid = gdf.centroid\n", "gdf_joined = gpd.sjoin(centroid, gdf, how='inner', op='within').explore()" ] }, { "cell_type": "code", "execution_count": 1, "id": "7efffd0c", "metadata": {}, "outputs": [ { "ename": "NameError", "evalue": "name 'gpd' is not defined", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", "Cell \u001b[1;32mIn[1], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m centroid_gdf \u001b[38;5;241m=\u001b[39m \u001b[43mgpd\u001b[49m\u001b[38;5;241m.\u001b[39mGeoDataFrame(geometry\u001b[38;5;241m=\u001b[39mgpd\u001b[38;5;241m.\u001b[39mpoints_from_xy(centroid\u001b[38;5;241m.\u001b[39mx, centroid\u001b[38;5;241m.\u001b[39my))\u001b[38;5;241m.\u001b[39mset_crs(msk23_1)\n", "\u001b[1;31mNameError\u001b[0m: name 'gpd' is not defined" ] } ], "source": [ "centroid_gdf = gpd.GeoDataFrame(geometry=gpd.points_from_xy(centroid.x, centroid.y)).set_crs(msk23_1)" ] }, { "cell_type": "markdown", "id": "3b530859", "metadata": {}, "source": [ "## 2. Создание таблицы с координатами (поворотные точки) ТОЛЬКО МСК23" ] }, { "cell_type": "code", "execution_count": 9, "id": "70de8c1d", "metadata": { "scrolled": true }, "outputs": [ { "ename": "DataSourceError", "evalue": "11111\\sch-aibga-grushevn_pp_orz-new_MSK23_2.shp: No such file or directory", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mDataSourceError\u001b[0m Traceback (most recent call last)", "Cell \u001b[1;32mIn[9], line 4\u001b[0m\n\u001b[0;32m 2\u001b[0m \u001b[38;5;66;03m# Извлекаем имя файла\u001b[39;00m\n\u001b[0;32m 3\u001b[0m shp_name \u001b[38;5;241m=\u001b[39m os\u001b[38;5;241m.\u001b[39mpath\u001b[38;5;241m.\u001b[39msplitext(os\u001b[38;5;241m.\u001b[39mpath\u001b[38;5;241m.\u001b[39mbasename(shp))[\u001b[38;5;241m0\u001b[39m]\n\u001b[1;32m----> 4\u001b[0m gdf \u001b[38;5;241m=\u001b[39m \u001b[43mgpd\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mread_file\u001b[49m\u001b[43m(\u001b[49m\u001b[43mshp\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 6\u001b[0m \u001b[38;5;66;03m# Извлекаем координаты вертексов полигона (формат X, Y в текущей координатной системе)\u001b[39;00m\n\u001b[0;32m 7\u001b[0m df \u001b[38;5;241m=\u001b[39m gdf\u001b[38;5;241m.\u001b[39mget_coordinates()\n", "File \u001b[1;32m~\\AppData\\Local\\Programs\\Python\\Python310\\lib\\site-packages\\geopandas\\io\\file.py:299\u001b[0m, in \u001b[0;36m_read_file\u001b[1;34m(filename, bbox, mask, columns, rows, engine, **kwargs)\u001b[0m\n\u001b[0;32m 296\u001b[0m from_bytes \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mTrue\u001b[39;00m\n\u001b[0;32m 298\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m engine \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mpyogrio\u001b[39m\u001b[38;5;124m\"\u001b[39m:\n\u001b[1;32m--> 299\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m _read_file_pyogrio(\n\u001b[0;32m 300\u001b[0m filename, bbox\u001b[38;5;241m=\u001b[39mbbox, mask\u001b[38;5;241m=\u001b[39mmask, columns\u001b[38;5;241m=\u001b[39mcolumns, rows\u001b[38;5;241m=\u001b[39mrows, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs\n\u001b[0;32m 301\u001b[0m )\n\u001b[0;32m 303\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m engine \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mfiona\u001b[39m\u001b[38;5;124m\"\u001b[39m:\n\u001b[0;32m 304\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m pd\u001b[38;5;241m.\u001b[39mapi\u001b[38;5;241m.\u001b[39mtypes\u001b[38;5;241m.\u001b[39mis_file_like(filename):\n", "File \u001b[1;32m~\\AppData\\Local\\Programs\\Python\\Python310\\lib\\site-packages\\geopandas\\io\\file.py:549\u001b[0m, in \u001b[0;36m_read_file_pyogrio\u001b[1;34m(path_or_bytes, bbox, mask, rows, **kwargs)\u001b[0m\n\u001b[0;32m 540\u001b[0m warnings\u001b[38;5;241m.\u001b[39mwarn(\n\u001b[0;32m 541\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mThe \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124minclude_fields\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m and \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mignore_fields\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m keywords are deprecated, and \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m 542\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mwill be removed in a future release. You can use the \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mcolumns\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m keyword \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 545\u001b[0m stacklevel\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m3\u001b[39m,\n\u001b[0;32m 546\u001b[0m )\n\u001b[0;32m 547\u001b[0m kwargs[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcolumns\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m kwargs\u001b[38;5;241m.\u001b[39mpop(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124minclude_fields\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m--> 549\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m pyogrio\u001b[38;5;241m.\u001b[39mread_dataframe(path_or_bytes, bbox\u001b[38;5;241m=\u001b[39mbbox, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n", "File \u001b[1;32m~\\AppData\\Local\\Programs\\Python\\Python310\\lib\\site-packages\\pyogrio\\geopandas.py:265\u001b[0m, in \u001b[0;36mread_dataframe\u001b[1;34m(path_or_buffer, layer, encoding, columns, read_geometry, force_2d, skip_features, max_features, where, bbox, mask, fids, sql, sql_dialect, fid_as_index, use_arrow, on_invalid, arrow_to_pandas_kwargs, **kwargs)\u001b[0m\n\u001b[0;32m 260\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m use_arrow:\n\u001b[0;32m 261\u001b[0m \u001b[38;5;66;03m# For arrow, datetimes are read as is.\u001b[39;00m\n\u001b[0;32m 262\u001b[0m \u001b[38;5;66;03m# For numpy IO, datetimes are read as string values to preserve timezone info\u001b[39;00m\n\u001b[0;32m 263\u001b[0m \u001b[38;5;66;03m# as numpy does not directly support timezones.\u001b[39;00m\n\u001b[0;32m 264\u001b[0m kwargs[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdatetime_as_string\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mTrue\u001b[39;00m\n\u001b[1;32m--> 265\u001b[0m result \u001b[38;5;241m=\u001b[39m read_func(\n\u001b[0;32m 266\u001b[0m path_or_buffer,\n\u001b[0;32m 267\u001b[0m layer\u001b[38;5;241m=\u001b[39mlayer,\n\u001b[0;32m 268\u001b[0m encoding\u001b[38;5;241m=\u001b[39mencoding,\n\u001b[0;32m 269\u001b[0m columns\u001b[38;5;241m=\u001b[39mcolumns,\n\u001b[0;32m 270\u001b[0m read_geometry\u001b[38;5;241m=\u001b[39mread_geometry,\n\u001b[0;32m 271\u001b[0m force_2d\u001b[38;5;241m=\u001b[39mgdal_force_2d,\n\u001b[0;32m 272\u001b[0m skip_features\u001b[38;5;241m=\u001b[39mskip_features,\n\u001b[0;32m 273\u001b[0m max_features\u001b[38;5;241m=\u001b[39mmax_features,\n\u001b[0;32m 274\u001b[0m where\u001b[38;5;241m=\u001b[39mwhere,\n\u001b[0;32m 275\u001b[0m bbox\u001b[38;5;241m=\u001b[39mbbox,\n\u001b[0;32m 276\u001b[0m mask\u001b[38;5;241m=\u001b[39mmask,\n\u001b[0;32m 277\u001b[0m fids\u001b[38;5;241m=\u001b[39mfids,\n\u001b[0;32m 278\u001b[0m sql\u001b[38;5;241m=\u001b[39msql,\n\u001b[0;32m 279\u001b[0m sql_dialect\u001b[38;5;241m=\u001b[39msql_dialect,\n\u001b[0;32m 280\u001b[0m return_fids\u001b[38;5;241m=\u001b[39mfid_as_index,\n\u001b[0;32m 281\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs,\n\u001b[0;32m 282\u001b[0m )\n\u001b[0;32m 284\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m use_arrow:\n\u001b[0;32m 285\u001b[0m meta, table \u001b[38;5;241m=\u001b[39m result\n", "File \u001b[1;32m~\\AppData\\Local\\Programs\\Python\\Python310\\lib\\site-packages\\pyogrio\\raw.py:198\u001b[0m, in \u001b[0;36mread\u001b[1;34m(path_or_buffer, layer, encoding, columns, read_geometry, force_2d, skip_features, max_features, where, bbox, mask, fids, sql, sql_dialect, return_fids, datetime_as_string, **kwargs)\u001b[0m\n\u001b[0;32m 59\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"Read OGR data source into numpy arrays.\u001b[39;00m\n\u001b[0;32m 60\u001b[0m \n\u001b[0;32m 61\u001b[0m \u001b[38;5;124;03mIMPORTANT: non-linear geometry types (e.g., MultiSurface) are converted\u001b[39;00m\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 194\u001b[0m \n\u001b[0;32m 195\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[0;32m 196\u001b[0m dataset_kwargs \u001b[38;5;241m=\u001b[39m _preprocess_options_key_value(kwargs) \u001b[38;5;28;01mif\u001b[39;00m kwargs \u001b[38;5;28;01melse\u001b[39;00m {}\n\u001b[1;32m--> 198\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mogr_read\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 199\u001b[0m \u001b[43m \u001b[49m\u001b[43mget_vsi_path_or_buffer\u001b[49m\u001b[43m(\u001b[49m\u001b[43mpath_or_buffer\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 200\u001b[0m \u001b[43m \u001b[49m\u001b[43mlayer\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mlayer\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 201\u001b[0m \u001b[43m \u001b[49m\u001b[43mencoding\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mencoding\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 202\u001b[0m \u001b[43m \u001b[49m\u001b[43mcolumns\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcolumns\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 203\u001b[0m \u001b[43m \u001b[49m\u001b[43mread_geometry\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mread_geometry\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 204\u001b[0m \u001b[43m \u001b[49m\u001b[43mforce_2d\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mforce_2d\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 205\u001b[0m \u001b[43m \u001b[49m\u001b[43mskip_features\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mskip_features\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 206\u001b[0m \u001b[43m \u001b[49m\u001b[43mmax_features\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmax_features\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01mor\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[0;32m 207\u001b[0m \u001b[43m \u001b[49m\u001b[43mwhere\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mwhere\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 208\u001b[0m \u001b[43m \u001b[49m\u001b[43mbbox\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mbbox\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 209\u001b[0m \u001b[43m \u001b[49m\u001b[43mmask\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m_mask_to_wkb\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmask\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 210\u001b[0m \u001b[43m \u001b[49m\u001b[43mfids\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mfids\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 211\u001b[0m \u001b[43m \u001b[49m\u001b[43msql\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43msql\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 212\u001b[0m \u001b[43m \u001b[49m\u001b[43msql_dialect\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43msql_dialect\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 213\u001b[0m \u001b[43m \u001b[49m\u001b[43mreturn_fids\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mreturn_fids\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 214\u001b[0m \u001b[43m \u001b[49m\u001b[43mdataset_kwargs\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdataset_kwargs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 215\u001b[0m \u001b[43m \u001b[49m\u001b[43mdatetime_as_string\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdatetime_as_string\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 216\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", "File \u001b[1;32mpyogrio\\\\_io.pyx:1240\u001b[0m, in \u001b[0;36mpyogrio._io.ogr_read\u001b[1;34m()\u001b[0m\n", "File \u001b[1;32mpyogrio\\\\_io.pyx:220\u001b[0m, in \u001b[0;36mpyogrio._io.ogr_open\u001b[1;34m()\u001b[0m\n", "\u001b[1;31mDataSourceError\u001b[0m: 11111\\sch-aibga-grushevn_pp_orz-new_MSK23_2.shp: No such file or directory" ] } ], "source": [ "shp = '11111\\\\sch-aibga-grushevn_pp_orz-new_MSK23_2.shp'\n", "# Извлекаем имя файла\n", "shp_name = os.path.splitext(os.path.basename(shp))[0]\n", "gdf = gpd.read_file(shp)\n", "\n", "# Извлекаем координаты вертексов полигона (формат X, Y в текущей координатной системе)\n", "df = gdf.get_coordinates()\n", "# Добавляем индекс к таблице\n", "df.reset_index(inplace = True, drop = True)\n", "# Первая строка с 1\n", "df.index += 1\n", "df = df.reset_index()\n", "# Округляем\n", "df = round(df)\n", "# Переименовываем столбцы\n", "df.columns = ['N', 'X_MSK23', 'Y_MSK23']\n", "# Добавляет первую строку в конец таблицы\n", "df = df.take(list(range(len(df) - 1)) + [0])\n", "df.to_excel(shp_name + '.xlsx', index=False)" ] }, { "cell_type": "markdown", "id": "7c473b4b", "metadata": {}, "source": [ "## 3. Поворотные точки градусы, минуты, секунды в ГСК 2011 (для проверки по ГЕОЛОГИИ)" ] }, { "cell_type": "code", "execution_count": 1, "id": "1e5a4710", "metadata": { "scrolled": true }, "outputs": [], "source": [ "import geopandas as gpd\n", "import pandas as pd\n", "from os.path import splitext\n", "import os" ] }, { "cell_type": "markdown", "id": "198e699a", "metadata": {}, "source": [ "#### Функции" ] }, { "cell_type": "code", "execution_count": 2, "id": "2e3cf25c", "metadata": {}, "outputs": [], "source": [ "# Функция создания списка шейпфайлов для обработки\n", "def shp_lst(folder):\n", " lst = []\n", " for file in os.listdir(folder):\n", " if file.endswith(\".shp\"):\n", " lst.append(os.path.join(folder, file))\n", " print(lst[:2], '\\n', f'Всего: {len(lst)} файл(-а, -ов)')\n", " return lst" ] }, { "cell_type": "code", "execution_count": 3, "id": "52edaf9c", "metadata": {}, "outputs": [], "source": [ "# Создает таблицу с координатами градусы-минуты-секунды для полигона в GeoDataFrame (должен быть один объект)\n", "def coordinates(gdf):\n", " df = gdf.get_coordinates()\n", " # Добавляем индекс к таблице\n", " df.reset_index(inplace = True, drop = True)\n", " # Первая строка с 1\n", " df.index += 1\n", " df = df.reset_index()\n", " \n", " df['latitude_deg'] = df['y'].astype(int)\n", " df['latitude_min_full'] = ((df['y'] - df['latitude_deg']) * 60).abs()\n", " df['latitude_min'] = df['latitude_min_full'].astype(int)\n", " df['latitude_sec'] = round((df['latitude_min_full'] - df['latitude_min']) * 60, 3)\n", "\n", " df['longitude_deg'] = df['x'].astype(int)\n", " df['longitude_min_full'] = ((df['x'] - df['longitude_deg']) * 60).abs()\n", " df['longitude_min'] = df['longitude_min_full'].astype(int)\n", " df['longitude_sec'] = round((df['longitude_min_full'] - df['longitude_min']) * 60, 3)\n", "\n", " df.drop(['x', 'y', 'latitude_min_full', 'longitude_min_full'], axis=1, inplace=True)\n", " df = df.rename(columns={'index': 'N'})\n", "\n", " # Добавляем в конец дубликат первой строки\n", " df = df.take(list(range(len(df) - 1)) + [0])\n", " return df" ] }, { "cell_type": "code", "execution_count": 4, "id": "23bd2b42", "metadata": {}, "outputs": [], "source": [ "##### Функция шаблона Excel c шапкой для координат ГСК-2011\n", "\n", "from openpyxl import Workbook\n", "from openpyxl.styles import Alignment, Font, Border, Side\n", "\n", "def template_gc(output_file):\n", " wb = Workbook()\n", " ws = wb.active\n", "\n", " # --- Первая строка: заголовок \"ГСК-2011\", объединённый над всеми столбцами ---\n", " max_col = 7 # например, у вас 7 столбцов в шапке ниже\n", "\n", " ws.merge_cells(start_row=1, start_column=1, end_row=1, end_column=max_col)\n", " header_cell = ws.cell(row=1, column=1, value='ГСК-2011')\n", " header_cell.font = Font(bold=False) # простой шрифт (без жирности)\n", " header_cell.alignment = Alignment(horizontal='center', vertical='center')\n", " \n", " # --- Вторая и третья строки: многоуровневая шапка ---\n", " # Вторая строка — первый уровень шапки\n", " ws['A3'] = \"№ точки\"\n", " ws['B3'] = \"Широта [-90:90]\\n(С.Ш. - положительные\\nЮ.Ш. - отрицательные)\"\n", " ws['E3'] = \"Долгота [-180:180]\\n(В.Д. - положительные\\nЗ.Д. - отрицательные)\"\n", "\n", " # Объединение ячеек для первого уровня заголовков\n", " ws.merge_cells('A3:A4') # \"№ точки\" занимает две строки вертикально\n", " ws.merge_cells('B3:D3') # \"Широта ...\" над 3 колонками\n", " ws.merge_cells('E3:G3') # \"Долгота ...\" над 3 колонками\n", "\n", " # Третья строка — второй уровень (подзаголовки) с обычным шрифтом\n", " sub_headers = [\n", " 'Градусы, \\nцелое',\n", " 'Минуты, \\nцелое',\n", " 'Секунды,\\nдробь до \\n3 знаков'\n", " ]\n", "\n", " cols_lat = ['B', 'C', 'D']\n", " cols_lon = ['E', 'F', 'G']\n", "\n", " for col, text in zip(cols_lat, sub_headers):\n", " c = ws[f\"{col}4\"]\n", " c.value = text\n", " c.font = Font(bold=False) # простой шрифт\n", " c.alignment = Alignment(horizontal='center', vertical='center', wrap_text=True)\n", "\n", " for col, text in zip(cols_lon, sub_headers):\n", " c = ws[f\"{col}4\"]\n", " c.value = text\n", " c.font = Font(bold=False)\n", " c.alignment = Alignment(horizontal='center', vertical='center', wrap_text=True)\n", "\n", " # Выравнивание и жирность для второго уровня заголовка (строка 2)\n", " for cell in ['A3', 'B3', 'E3']:\n", " c = ws[cell]\n", " c.font = Font(bold=True)\n", " c.alignment = Alignment(horizontal='center', vertical='center', wrap_text=True)\n", "\n", " # Установим высоту строк для переносов текста\n", " ws.row_dimensions[1].height = 20\n", " ws.row_dimensions[2].height = 8\n", " ws.row_dimensions[3].height = 48\n", " ws.row_dimensions[4].height = 40\n", "\n", " # Подгонка ширины столбцов\n", " col_widths = [10, 15, 15, 20, 15, 15, 20]\n", " for i, width in enumerate(col_widths, 1):\n", " ws.column_dimensions[chr(64 + i)].width = width\n", "\n", " # Добавление рамки по всей области шапки (с 1 по 3 строку, с A по G)\n", " thin_side = Side(border_style=\"thin\", color=\"000000\")\n", " border = Border(left=thin_side, right=thin_side, top=thin_side, bottom=thin_side)\n", " for row in ws.iter_rows(min_row=3, max_row=4, min_col=1, max_col=max_col):\n", " for cell in row:\n", " # Центрируем все ячейки по горизонтали и вертикали, если текст в ячейке есть\n", " if cell.value is not None:\n", " cell.alignment = Alignment(horizontal='center', vertical='center', wrap_text=True)\n", " # Устанавливаем рамку\n", " cell.border = border\n", "\n", " # Сохраняем файл\n", " wb.save(output_file)" ] }, { "cell_type": "code", "execution_count": 5, "id": "4188dffe", "metadata": {}, "outputs": [], "source": [ "# Функция форматирования файла Excel, выравнивание всех ячеек по центру и добавления первой строки с номером участка\n", "from openpyxl import load_workbook\n", "from openpyxl.styles import Alignment, Font, Border, Side\n", "\n", "def format_xlsx(xlsx, counter): # counter - текущий номер участка\n", " # Открываем существующий файл\n", " wb = load_workbook(xlsx)\n", " ws = wb.active # или wb['SheetName']\n", "\n", " # Определяем размер текущей таблицы\n", " min_row, max_row = ws.min_row, ws.max_row\n", " min_col, max_col = ws.min_column, ws.max_column\n", "\n", "# УБРАЛ БЛОК ДОБАВЛЕНИЯ ПЕРВОЙ СТРОКИ С НОМЕРОМ УЧАСТКА, ТАК КАК В СИСТЕМУ МОЖНО ЗАГРУЖАТЬ ТОЛЬКО ПО ОДНОМУ УЧАСТКУ\n", "# # Вставляем пустую первую строку\n", "# ws.insert_rows(1)\n", "# max_row += 1 # сдвигаем нижнюю границу таблицы вниз на 1, т.к. вставили строку\n", "\n", "# # Объединяем все ячейки первой строки в одну ячейку\n", "# merge_range = f\"{ws.cell(row=1, column=min_col).coordinate}:\" \\\n", "# f\"{ws.cell(row=1, column=max_col).coordinate}\"\n", "# ws.merge_cells(merge_range)\n", "\n", "# header_cell = ws.cell(row=1, column=min_col)\n", "# header_cell.value = \"Участок \" + str(counter)\n", "# header_cell.font = Font(bold=True, size=11)\n", "# header_cell.alignment = Alignment(horizontal='center', vertical='center')\n", "\n", "# # Устанавливаем высоту первой строки для читаемости\n", "# ws.row_dimensions[1].height = 20\n", "\n", " # Создаем стиль тонкой рамки\n", " thin_side = Side(border_style=\"thin\", color=\"000000\")\n", " thin_border = Border(left=thin_side, right=thin_side, top=thin_side, bottom=thin_side)\n", "\n", " # Проходим по всем ячейкам таблицы (включая новую первую строку)\n", " for row in ws.iter_rows(min_row=0, max_row=max_row, min_col=min_col, max_col=max_col):\n", " for cell in row:\n", " # Центрируем содержимое ячеек\n", " if cell.value is not None:\n", " cell.alignment = Alignment(horizontal='center', vertical='center', wrap_text=True)\n", " # Устанавливаем тонкую рамку в каждую ячейку\n", " cell.border = thin_border\n", "\n", " # Сохраняем в тот же файл\n", " wb.save(xlsx)" ] }, { "cell_type": "code", "execution_count": 6, "id": "7c5eb821", "metadata": {}, "outputs": [], "source": [ "# Функция объединения 2+ файлов-участков от одного ООПТ \n", "from openpyxl import load_workbook, Workbook\n", "from openpyxl.styles import Font, PatternFill, Border, Alignment, Protection\n", "\n", "def copy_cell_style(src_cell, tgt_cell):\n", " if src_cell.has_style:\n", " tgt_cell.font = src_cell.font.copy()\n", " tgt_cell.border = src_cell.border.copy()\n", " tgt_cell.fill = src_cell.fill.copy()\n", " tgt_cell.number_format = src_cell.number_format\n", " tgt_cell.protection = src_cell.protection.copy()\n", " tgt_cell.alignment = src_cell.alignment.copy()\n", "\n", "def concat_xlsx_with_style(files, output_file):\n", " wb_new = Workbook()\n", " ws_new = wb_new.active\n", " ws_new.title = \"Угловые точки DD⁰MM'SS.SS\"\n", " \n", " current_row = 1\n", " for idx, file in enumerate(files):\n", " wb_src = load_workbook(file)\n", " ws_src = wb_src.active\n", " \n", " min_row = 1 # Можно поменять на 2 для пропуска заголовков во 2-м и последующих файлах\n", " \n", " # Копируем значения и стили по строкам\n", " for r in range(min_row, ws_src.max_row + 1):\n", " for c in range(1, ws_src.max_column + 1):\n", " src_cell = ws_src.cell(row=r, column=c)\n", " tgt_cell = ws_new.cell(row=current_row, column=c)\n", " tgt_cell.value = src_cell.value\n", " copy_cell_style(src_cell, tgt_cell)\n", " current_row += 1\n", "\n", " # Копируем объединённые ячейки (merged cells) с учётом сдвига строк\n", " row_offset = current_row - (ws_src.max_row + 1)\n", " for merged_range in ws_src.merged_cells.ranges:\n", " start_row = merged_range.min_row + row_offset\n", " end_row = merged_range.max_row + row_offset\n", " start_col = merged_range.min_col\n", " end_col = merged_range.max_col\n", " \n", " new_range = f\"{ws_src.cell(row=start_row, column=start_col).coordinate}:\" \\\n", " f\"{ws_src.cell(row=end_row, column=end_col).coordinate}\"\n", " try:\n", " ws_new.merge_cells(new_range)\n", " except Exception as e:\n", " print(f\"Ошибка объединения: {new_range} - {e}\")\n", "\n", " # Копирование высоты строк с учётом сдвига\n", " for r in range(min_row, ws_src.max_row + 1):\n", " height = ws_src.row_dimensions[r].height\n", " if height is not None:\n", " ws_new.row_dimensions[r + row_offset].height = height\n", "\n", " wb_new.save(output_file)" ] }, { "cell_type": "code", "execution_count": 7, "id": "41cb9036", "metadata": {}, "outputs": [], "source": [ "# Функция добавления листа с координатной системой СК-2011 для добавления на сайт с геологической информацией https://efgi.ru/\n", "from openpyxl import load_workbook\n", "from openpyxl.utils import get_column_letter\n", "\n", "def add_cs(excel_path):\n", " # Данные для записи\n", " headers = [\"СК\", \"EPSG\", \"Код в Proj4\"]\n", " values = [\n", " \"ГСК-2011\",\n", " 7683,\n", " \"+proj=longlat +a=6378136.5 +rf=298.2564151 \"\n", " \"+towgs84=0.013,-0.092,-0.03,-0.001738,0.003559,-0.004263,0.0074 +no_defs\"\n", " ]\n", "\n", " # Загружаем книгу\n", " wb = load_workbook(excel_path)\n", " \n", " # Если лист с именем \"СК\" существует - удаляем его (чтобы заменить)\n", " if \"СК\" in wb.sheetnames:\n", " del wb[\"СК\"]\n", "\n", " # Создаём новый лист \"СК\"\n", " ws = wb.create_sheet(\"СК\")\n", "\n", " # Записываем заголовки в первую строку\n", " for col_num, header in enumerate(headers, start=1):\n", " cell = ws.cell(row=1, column=col_num, value=header)\n", "\n", " # Записываем данные во вторую строку\n", " for col_num, value in enumerate(values, start=1):\n", " ws.cell(row=2, column=col_num, value=value)\n", " \n", " # Сохраняем файл\n", " wb.save(excel_path)" ] }, { "cell_type": "code", "execution_count": 8, "id": "8d0cdc89", "metadata": {}, "outputs": [], "source": [ "# Словарь с названиями районов и ООПТ\n", "dic_oopt = {\n", "'anp-anap-soch-skal_pp_orz-new_WGS84': 'Анапа_Анапские сочащиеся скалы',\n", "'anp-stepi-balki-zozulina_pp_orz-new_WGS84': 'Анапа_Степи балки Зозулина',\n", "'anp-bujor-kodzor-les_orz-new_WGS84': 'Анапа_ПП Бужоро-Кодзорский лес',\n", "'anp-krasnogor-les_pp_orz-new_WGS84': 'Анапа_ПП Красногорский лес',\n", "'anp-kumatyr-hrebet_zak_orz_WGS84': 'Анапа_ПП Куматырский лес',\n", "'anp-shkurat-les_orz-new_WGS84': 'Анапа_ПП Шкуратский лес',\n", "'anp-yug-gostag-les_orz-new_WGS84': 'Анапа_ПП Южно-Гостагаевскй лес',\n", "'anp-kurb-bugor_pp_orz-new_WGS84': 'Анапа_ПП Курбацкие бугры',\n", "'anp-chekon-redkoles_orz-new_WGS84': 'Анапа_ПП Чеконское редколесье',\n", "'brh-vys-bereg-beysug_pp_orz-new_WGS84': 'Брюховецкий_район_ПП_Высокий берег реки Бейсуг',\n", "'glj-gebeus-gorn-mass_zak_orz-new_WGS84': 'Геленджик_ПП_Гебеусский горный массив',\n", "'glj-mojj-redkles-gor-neksis_pp_orz-new_WGS84': 'Геленджик_ПП_Можжевеловые редколесья хребта Нексис',\n", "'esk-voronts-step_pp_orz-new_WGS84': 'Ейский район_Воронцовская степь',\n", "'esk-kruglaya-pad_pp_orz-new_WGS84': 'Ейский район_Круглая падь',\n", "'esk-hans-yasen_zak_orz-new_WGS84': 'Ейский район_Ханско-Ясенский заказник',\n", "'esk-yasnopol-step_pp_orz-new_WGS84': 'Ейский район_Яснопольская_степь',\n", "'kvk-obrivistiy-bereg-reki-kuban_pp_orz-new_WGS84': 'Кавказский и Тбилисск район_Обрывистый берег реки Кубань',\n", "'kvk-temijbek-vysok-bereg_pp_orz-new_WGS84': 'Кавказский_район_ПП_Темижбекский высокий берег',\n", "'knv-bolot-albashi_lpk_orz-new_WGS84': 'Каневской_район_ ЛПК Болото Албаши',\n", "'knv-chelbas-plavn_lpk_orz-new_WGS84': 'Каневской_район_ЛПК Челбасские плавни',\n", "'knv-nijn-beisug-plavn_lpk_orz-new_WGS84': 'Каневской_район_ЛПК Нижнебейсугские плавни',\n", "'kln-ponur-les_pp-orz-new_WGS84': 'Калининский_район_ПП Понурский лес',\n", "'kln-ponura-liman_lpk_orz-new_WGS84': 'Калининский_район_ЛПК Понурский лиман',\n", "'krl-balk-irinovka+_pp_orz-new_WGS84': 'Крыловский_район_ПП_Балка Ириновка',\n", "'krl-balk-krutaya_pp_orz-new_WGS84': 'Крыловский район_Балка Крутая в долине реки Ея',\n", "'krl-gryadin-plavn-rek-eya_pp_orz-new_WGS84': 'Крыловский_район_ПП_Грядинские плавни реки Ея',\n", "'krl-balk-irinovka+_pp_orz-new_WGS84': 'Крыловский_район_ПП_Балка Ириновка',\n", "'krm-uroch_kovalenkova_baga_pp_orz-new_WGS84': 'Крымский район_Коваленкова бага',\n", "'ksh-poltavskiy-ostanec_pp_orz-new_WGS84': 'Кущевский район_Полтавский останец степи в долине реки Эльбузд',\n", "'ksh-uroch-alekseevskoe_pp_orz-new_WGS84': 'Кущевский район_Урочище Алексеевское',\n", "'ksh-shalfey-step-rek-elbuzd_pp_orz-new_WGS84': 'Кущевский_район_ПП_Шалфеевая_степь',\n", "'mst-besleneev-pesheri_pp_orz-new_WGS84': 'Мостовской_р-н_ПП_Пещера Бесленеевская',\n", "'nvk-kutanskaya-step_pp_orz-new_WGS84': 'Успенск_Новокуб_Армавир_р-н_ПП_Кутанская степь',\n", "'nvp-fedorenk-bugr_pp_orz-new_WGS84': 'Новопокровский_район_ПП_Федоренковы бугры',\n", "'nvk-fortshtadt-nagorn-step_pp_orz-new_WGS84': 'Армавир_Новокубанск_р-н_ПП_Фортштадская степь',\n", "'nvr-abrau_zak+_orz-new_WGS84': 'Новороссийск_Абраусский заказник',\n", "'nvr-abrau_zak_orz-IZMENENIE_WGS84': 'Новороссийск_Абраусский заказник_расширение Щурова',\n", "'nvr-atakay-markoth_zak_orz-new_WGS84': 'Новороссийск_Атакайско-Маркотхский',\n", "'nvr-kovilskaya-step_pp_orz-new_WGS84': 'Новороссийск_Ковыльская_степь_хребта_Сенетх',\n", "'nvr-petrof-step-hr-seneth_pp_orz-new_WGS84': 'Новороссийск_Петрофитные_степи_Гора Самбурова',\n", "'otr-dzheltmesskie-vysoty_zak_orz-new_WGS84': 'Отрадненский район_Джельтмесские Высоты',\n", "'otr-chehrak+_zak_orz-new_WGS84': 'Отрадненский район_заказник Чехрак',\n", "'otr-chehrak+_zak_orz-IZMENENIE_WGS84': 'Отрадненский район_заказник Чехрак_изменения ООПТ',\n", "'pvl-urch-mugan_pp_orz-new_WGS84': 'Павловский_район_ПП_Урочище Муган',\n", "'svr-hrebet-dlinn-gor_prz_orz-new_WGS84': 'Cеверский_район_ПРЗ Хребет Длинная гора',\n", "'sch-aibga-grushevn_pp_orz-new_WGS84': 'Сочи_ПП_Аибгинский грушевник',\n", "'sch-mamay-lesopark_zak_orz-new_WGS84': 'Сочи_Мамайский лесопарк',\n", "'sch-urch-dzhegosh_pp_orz-new_WGS84': 'Сочи_ПП_Урочище Джегош',\n", "'tmr-urochische-strelka-yuzhnaya_pp_orz-new_WGS84': 'Темрюкский район_Урочище Стрелка Южная',\n", "'tbl-tbiliss_visokiy_bereg_pp_orz-new_WGS84': 'Тбилисский_р-н_ПП_Тбилисский высокий берег',\n", "'tbl-savk-kruch_pp_orz-new_WGS84': 'Тбилисский_р-н_ПП_Савкины кручи',\n", "'tps-gebeus-gorn-mass_zak_orz-new_WGS84': 'Туапсинский район_ПП_Гебеусский горный массив',\n", "'usp-stepnoy_zak++_orz-new_WGS84': 'Успенский_р-н_заказник Степной',\n", "'usp-uspen-poim-les_zak_orz-new_WGS84': 'Успенский_Отрадн_р-н_ПП_Успенские пойменные леса',\n", "'ulb-uch-lesostep-rek-2-zelench_pp_orz-new_WGS84': 'Усть-Лаб_р-н_ПП_Участки лесостепи на р. Зеленчук',\n", "'ulb-urochische-ladozhskoe_pp_orz-new_WGS84': 'Усть-Лабинский район_Урочище Ладожское',\n", "'ulb-urochische-pyatihatskoe_pp_orz-new_WGS84': 'Усть-Лабинский район_Урочище Пятихатское',\n", "'shr-eisk-plavn_lpk_orz-new_WGS84': 'Щербиновский район_ЛПК Ейские плавни',\n", "'shr-uroch-tureckaya-krepost_ppk_orz-new_WGS84': 'Щербиновский район_ППК Турецкая крепость',\n", "}" ] }, { "cell_type": "markdown", "id": "39a10e18", "metadata": {}, "source": [ "#### Начало обработки" ] }, { "cell_type": "code", "execution_count": 9, "id": "9730503b", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['Input_processing\\\\tbl-tbiliss_visokiy_bereg_pp_orz-new_WGS84.shp', 'Input_processing\\\\Орнитологический Границы тропы.shp'] \n", " Всего: 2 файл(-а, -ов)\n" ] } ], "source": [ "## Список файлов\n", "folder = 'Input_processing' # папка для обработки\n", "\n", "lst = shp_lst(folder)" ] }, { "cell_type": "code", "execution_count": 10, "id": "cfbad0f3", "metadata": { "scrolled": true }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "C:\\Users\\Evgenii\\AppData\\Local\\Temp\\ipykernel_43168\\1470149036.py:7: DeprecationWarning: Call to deprecated function copy (Use copy(obj) or cell.obj = cell.obj + other).\n", " tgt_cell.font = src_cell.font.copy()\n", "C:\\Users\\Evgenii\\AppData\\Local\\Temp\\ipykernel_43168\\1470149036.py:8: DeprecationWarning: Call to deprecated function copy (Use copy(obj) or cell.obj = cell.obj + other).\n", " tgt_cell.border = src_cell.border.copy()\n", "C:\\Users\\Evgenii\\AppData\\Local\\Temp\\ipykernel_43168\\1470149036.py:9: DeprecationWarning: Call to deprecated function copy (Use copy(obj) or cell.obj = cell.obj + other).\n", " tgt_cell.fill = src_cell.fill.copy()\n", "C:\\Users\\Evgenii\\AppData\\Local\\Temp\\ipykernel_43168\\1470149036.py:11: DeprecationWarning: Call to deprecated function copy (Use copy(obj) or cell.obj = cell.obj + other).\n", " tgt_cell.protection = src_cell.protection.copy()\n", "C:\\Users\\Evgenii\\AppData\\Local\\Temp\\ipykernel_43168\\1470149036.py:12: DeprecationWarning: Call to deprecated function copy (Use copy(obj) or cell.obj = cell.obj + other).\n", " tgt_cell.alignment = src_cell.alignment.copy()\n", "C:\\Users\\Evgenii\\AppData\\Local\\Temp\\ipykernel_43168\\1470149036.py:7: DeprecationWarning: Call to deprecated function copy (Use copy(obj) or cell.obj = cell.obj + other).\n", " tgt_cell.font = src_cell.font.copy()\n", "C:\\Users\\Evgenii\\AppData\\Local\\Temp\\ipykernel_43168\\1470149036.py:8: DeprecationWarning: Call to deprecated function copy (Use copy(obj) or cell.obj = cell.obj + other).\n", " tgt_cell.border = src_cell.border.copy()\n", "C:\\Users\\Evgenii\\AppData\\Local\\Temp\\ipykernel_43168\\1470149036.py:9: DeprecationWarning: Call to deprecated function copy (Use copy(obj) or cell.obj = cell.obj + other).\n", " tgt_cell.fill = src_cell.fill.copy()\n", "C:\\Users\\Evgenii\\AppData\\Local\\Temp\\ipykernel_43168\\1470149036.py:11: DeprecationWarning: Call to deprecated function copy (Use copy(obj) or cell.obj = cell.obj + other).\n", " tgt_cell.protection = src_cell.protection.copy()\n", "C:\\Users\\Evgenii\\AppData\\Local\\Temp\\ipykernel_43168\\1470149036.py:12: DeprecationWarning: Call to deprecated function copy (Use copy(obj) or cell.obj = cell.obj + other).\n", " tgt_cell.alignment = src_cell.alignment.copy()\n" ] }, { "ename": "KeyError", "evalue": "'Орнитологический Границы тропы'", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mKeyError\u001b[0m Traceback (most recent call last)", "Cell \u001b[1;32mIn[10], line 40\u001b[0m\n\u001b[0;32m 37\u001b[0m merge_lst\u001b[38;5;241m.\u001b[39minsert(\u001b[38;5;241m0\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtemplate_gc.xlsx\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[0;32m 39\u001b[0m \u001b[38;5;66;03m# Имя из словаря со списком район+ООПТ по имени shape-файла\u001b[39;00m\n\u001b[1;32m---> 40\u001b[0m final_name \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mstr\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mКоординаты_\u001b[39m\u001b[38;5;124m'\u001b[39m) \u001b[38;5;241m+\u001b[39m \u001b[43mdic_oopt\u001b[49m\u001b[43m[\u001b[49m\u001b[43mshp_name\u001b[49m\u001b[43m]\u001b[49m \u001b[38;5;241m+\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m_Участок_\u001b[39m\u001b[38;5;124m\"\u001b[39m \u001b[38;5;241m+\u001b[39m \u001b[38;5;28mstr\u001b[39m(counter) \u001b[38;5;241m+\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m.xlsx\u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[0;32m 42\u001b[0m \u001b[38;5;66;03m# Объединяем все файлы из списка с сохранением исходного форматирования (функция)\u001b[39;00m\n\u001b[0;32m 43\u001b[0m concat_xlsx_with_style(merge_lst, final_name)\n", "\u001b[1;31mKeyError\u001b[0m: 'Орнитологический Границы тропы'" ] } ], "source": [ "# Пакетная обработка\n", "for shp in lst:\n", " # Считываем файл\n", " gdf = gpd.read_file(shp) \n", " gdf = gdf.to_crs(7683) # Переводим в ГСК-2011\n", " # Извлекаем имя файла\n", " shp_name = os.path.basename(shp).split('.')[0]\n", " # Счетчик для сохранения разных участков одной ООПТ\n", " counter = 0\n", " \n", " # Превращаем возможных мултисоставной объект (multipart) в односоставной (singlepart)\n", " gdf = gdf.explode(index_parts=False).reset_index(drop=True)\n", " \n", " # Создает список фреймов из каждой объекта (если многосоставной) \n", " list_of_single_row_gdfs = [gdf.iloc[[i]] for i in range(len(gdf))]\n", "\n", " \n", " for el in list_of_single_row_gdfs:\n", " # Счетчик для номера участка внутри одного шейпа\n", " counter += 1\n", " merge_lst = []\n", " # Вызов функции для расчета и форматирования координат\n", " df = coordinates(el)\n", " \n", " name_xlsx = shp_name + '.xlsx'\n", " df.to_excel(name_xlsx, header=False, index=False)\n", " \n", " # Форматируем файл через функцию\n", " format_xlsx(name_xlsx, counter) \n", " merge_lst.append(name_xlsx)\n", " \n", " # Создаем шапку для таблицы (функция), если файл не существует\n", " if not os.path.exists('template_gc.xlsx'):\n", " template_gc('template_gc.xlsx') \n", " \n", " # Добавлеем шапку таблицы в список файлов для обработки под номером 0\n", " merge_lst.insert(0, 'template_gc.xlsx')\n", " \n", " # Имя из словаря со списком район+ООПТ по имени shape-файла\n", " final_name = str('Координаты_') + dic_oopt[shp_name] + \"_Участок_\" + str(counter) + '.xlsx'\n", " \n", " # Объединяем все файлы из списка с сохранением исходного форматирования (функция)\n", " concat_xlsx_with_style(merge_lst, final_name)\n", " \n", " # Добавляем второй лист с параметрами преобразования координат для геологического сервиса\n", " add_cs(final_name)" ] }, { "cell_type": "markdown", "id": "41efeb91", "metadata": {}, "source": [ "## 4. Поворотные точки с 3 координатными системами (WGS84, МСК23, ГСК2011) - АНАПСКАЯ ПЕРЕСЫПЬ" ] }, { "cell_type": "code", "execution_count": 56, "id": "1393e5ee", "metadata": {}, "outputs": [], "source": [ "import geopandas as gpd\n", "import pandas as pd\n", "from os.path import splitext\n", "import os" ] }, { "cell_type": "code", "execution_count": 57, "id": "c264ba85", "metadata": {}, "outputs": [], "source": [ "# Функция создания списка шейпфайлов для обработки\n", "def shp_lst(folder):\n", " lst = []\n", " for file in os.listdir(folder):\n", " if file.endswith(\".shp\"):\n", " lst.append(os.path.join(folder, file))\n", " print(lst[:2], '\\n', f'Всего: {len(lst)} файл(-а, -ов)')\n", " return lst\n", "\n", "### Функция создания таблицы с коодинатными системами\n", "# Извлекаем имя файла\n", "def coord_crs(shp):\n", " shp_name = os.path.splitext(os.path.basename(shp))[0]\n", " gdf = gpd.read_file(shp)\n", " \n", " # WGS84\n", " gdf1 = gdf.to_crs(4326)\n", " # Извлекаем координаты вертексов полигона (формат X, Y в текущей координатной системе)\n", " df1 = gdf1.get_coordinates()\n", " # Добавляем индекс к таблице\n", " df1.reset_index(inplace = True, drop = True)\n", " # Первая строка с 1\n", " df1.index += 1\n", " df1 = df1.reset_index()\n", " df1 = round(df1,6)\n", " df1.columns = ['N', 'Dolgota_X_WGS84', 'Shirota_Y_WGS84', ]\n", " df1 = df1[['N', 'Shirota_Y_WGS84', 'Dolgota_X_WGS84']]\n", "\n", " #MSK23\n", " gdf2 = gdf.to_crs(msk23_1)\n", " df2 = gdf2.get_coordinates()\n", " # Добавляем индекс к таблице\n", " df2.reset_index(inplace = True, drop = True)\n", " # Первая строка с 1\n", " df2.index += 1\n", " df2 = df2.reset_index()\n", " # Округляем\n", " df2 = round(df2)\n", " df2.columns = ['N', 'Dolgota_X_MSK23', 'Shirota_Y_MSK23', ]\n", " df2 = df2[['N', 'Shirota_Y_MSK23', 'Dolgota_X_MSK23']]\n", "\n", " #GSK2011\n", " gdf3 = gdf.to_crs(7683)\n", " df3 = gdf3.get_coordinates()\n", " # Добавляем индекс к таблице\n", " df3.reset_index(inplace = True, drop = True)\n", " # Первая строка с 1\n", " df3.index += 1\n", " df3 = df3.reset_index()\n", " df3 = round(df3,6)\n", " df3.columns = ['N', 'Dolgota_X_GSK2011', 'Shirota_Y_GSK2011',]\n", " df3 = df3[['N', 'Shirota_Y_GSK2011','Dolgota_X_GSK2011']]\n", "\n", " # Объединение таблиц с координатами (df1 и df2)\n", " df1 = df1.merge(df2,left_on='N', right_on='N')\n", " df1 = df1.merge(df3,left_on='N', right_on='N')\n", " # Добавляем в конец дубликат первой строки\n", " df1 = df1.take(list(range(len(df1) - 1)) + [0])\n", " # Файлы Excel помещаются в папку скрипта с именем исходном файла\n", " df1.to_excel(shp_name + '.xlsx', index=False)" ] }, { "cell_type": "code", "execution_count": 58, "id": "5ba0c820", "metadata": {}, "outputs": [], "source": [ "# Считываем проекцию в формате WKT и сохраняем ее в переменной\n", "from pyproj import CRS\n", "with open(r'F:\\PROJECT-Colormap\\Преобразования географических проекций (СК, ГСК-2011, МСК)\\МСК23 проекции Краснодар\\MCK-23_Zone_1N.prj', 'r') as f:\n", " #wkt = f.read()\n", " msk23_1 = f.read()\n", "# crs = CRS.from_wkt(wkt)\n", "\n", "with open(r'F:\\PROJECT-Colormap\\Преобразования географических проекций (СК, ГСК-2011, МСК)\\МСК23 проекции Краснодар\\MCK-23_Zone_2N.prj', 'r') as f:\n", " msk23_2 = f.read()" ] }, { "cell_type": "code", "execution_count": 59, "id": "b2077b77", "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['Input_processing\\\\Орнитологический Границы тропы.shp'] \n", " Всего: 1 файл(-а, -ов)\n" ] } ], "source": [ "## Список файлов\n", "folder = 'Input_processing' # папка для обработки\n", "\n", "lst = shp_lst(folder)" ] }, { "cell_type": "code", "execution_count": 60, "id": "f97e8123", "metadata": {}, "outputs": [], "source": [ "# Обработка \n", "for shp in lst:\n", " coord_crs(shp)" ] }, { "cell_type": "markdown", "id": "e5e45902", "metadata": {}, "source": [ "### Тоже, что и выше, но создают для каждого элемента в шейпе отдельный файл Excel и название файла по номеру кад. участка (делал через Perplexity)" ] }, { "cell_type": "code", "execution_count": 55, "id": "1627e21e", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['Input_processing\\\\selected_cad_numbers.shp'] \n", " Всего: 1 файл(-а, -ов)\n", "Готово: selected_cad_numbers -> Output_excel\n" ] } ], "source": [ "\n", "\n", "import geopandas as gpd\n", "import pandas as pd\n", "from os.path import splitext, basename, join\n", "import os\n", "from pyproj import CRS\n", "\n", "# ---------- Настройки ----------\n", "INPUT_FOLDER = 'Input_processing' # папка для обработки\n", "OUTPUT_FOLDER = 'Output_excel' # куда сохранять Excel\n", "CAD_FIELD = 'cad_number' # имя столбца с кадастровым номером\n", "MSK23_WKT_FILE = r'F:\\PROJECT-Colormap\\Преобразования географических проекций (СК, ГСК-2011, МСК)\\МСК23 проекции Краснодар\\MCK-23_Zone_1N.prj'\n", "\n", "# ---------- Вспомогательные ----------\n", "def ensure_dir(path):\n", " os.makedirs(path, exist_ok=True)\n", "\n", "def shp_lst(folder):\n", " lst = [os.path.join(folder, f) for f in os.listdir(folder) if f.lower().endswith(\".shp\")]\n", " print(lst[:2], '\\n', f'Всего: {len(lst)} файл(-а, -ов)')\n", " return lst\n", "\n", "def load_wkt(path):\n", " with open(path, 'r', encoding='utf-8') as f:\n", " return f.read()\n", "\n", "# ---------- Основная функция ----------\n", "def export_features_to_excels(shp, msk23_wkt, output_dir=OUTPUT_FOLDER, cad_field=CAD_FIELD):\n", " ensure_dir(output_dir)\n", " shp_name = os.path.splitext(os.path.basename(shp))[0]\n", " gdf = gpd.read_file(shp)\n", "\n", " if cad_field not in gdf.columns:\n", " print(f'WARNING: {cad_field} не найден в {shp_name}. Будут использованы имена по индексу.')\n", "\n", " # Преобразования систем координат заранее\n", " gdf_wgs = gdf.to_crs(4326) # WGS84\n", " gdf_msk = gdf.to_crs(msk23_wkt) # MSK23 WKT\n", " gdf_gsk = gdf.to_crs(7683) # GSK2011 / EPSG:7683\n", "\n", " # Проходим по каждому объекту\n", " for i, (wgs_geom, msk_geom, gsk_geom, row) in enumerate(zip(gdf_wgs.geometry, gdf_msk.geometry, gdf_gsk.geometry, gdf.itertuples(index=False))):\n", " # Имя файла\n", " base_name = getattr(row, cad_field) if cad_field in gdf.columns else f'{shp_name}_feat_{i+1}'\n", " base_name = str(base_name).replace(':', '_')\n", "\n", " # Собираем координаты вершин полигона/мультиполигона\n", " def coords_as_df(geom, x_name, y_name, round_ndigits=None, round0=False):\n", " # Разворачиваем в список колец\n", " def extract_rings(g):\n", " if g is None or g.is_empty:\n", " return []\n", " if g.geom_type == 'Polygon':\n", " return [g.exterior] + list(g.interiors)\n", " if g.geom_type == 'MultiPolygon':\n", " rings = []\n", " for p in g.geoms:\n", " rings.append(p.exterior)\n", " rings.extend(list(p.interiors))\n", " return rings\n", " # Для LineString/Point fallback\n", " return [g]\n", " pts = []\n", " for ring in extract_rings(geom):\n", " for x, y in ring.coords:\n", " pts.append((y, x)) # хотим сначала Y, потом X\n", " df = pd.DataFrame(pts, columns=[y_name, x_name]).reset_index(drop=True)\n", " df.index += 1\n", " df.insert(0, 'N', df.index)\n", " if round0:\n", " df[[y_name, x_name]] = df[[y_name, x_name]].round(0)\n", " elif round_ndigits is not None:\n", " df[[y_name, x_name]] = df[[y_name, x_name]].round(round_ndigits)\n", " # Добавляем дубликат первой строки в конец\n", " if len(df) > 0:\n", " first_row = df.iloc[[0]].copy()\n", " df = pd.concat([df.iloc[:-1], first_row], ignore_index=True)\n", " df.index += 1\n", " df['N'] = df.index\n", " return df\n", "\n", " df_wgs = coords_as_df(wgs_geom, 'Dolgota_X_WGS84', 'Shirota_Y_WGS84', round_ndigits=6)\n", " df_msk = coords_as_df(msk_geom, 'Dolgota_X_MSK23', 'Shirota_Y_MSK23', round0=True)\n", " df_gsk = coords_as_df(gsk_geom, 'Dolgota_X_GSK2011', 'Shirota_Y_GSK2011', round_ndigits=6)\n", "\n", " # Объединяем по N\n", " df = df_wgs.merge(df_msk, on='N', how='outer').merge(df_gsk, on='N', how='outer')\n", "\n", " # Сохраняем в Excel\n", " out_path = os.path.join(output_dir, f'{base_name}.xlsx')\n", " df.to_excel(out_path, index=False)\n", "\n", " print(f'Готово: {shp_name} -> {output_dir}')\n", "\n", "# ---------- Инициализация ----------\n", "msk23_wkt = load_wkt(MSK23_WKT_FILE)\n", "\n", "# ---------- Запуск ----------\n", "for shp in shp_lst(INPUT_FOLDER):\n", " export_features_to_excels(shp, msk23_wkt)\n" ] }, { "cell_type": "markdown", "id": "90e191f7", "metadata": {}, "source": [ "## 5. Преобразование в MapInfo" ] }, { "cell_type": "code", "execution_count": null, "id": "afff19d6", "metadata": {}, "outputs": [], "source": [ "import geopandas as gpd\n", "import pandas as pd\n", "from os.path import splitext\n", "import os\n", "\n", "# Функция создания списка шейпфайлов для обработки\n", "def shp_lst(folder):\n", " lst = []\n", " for file in os.listdir(folder):\n", " if file.endswith(\".shp\"):\n", " lst.append(os.path.join(folder, file))\n", " print(lst[:2], '\\n', f'Всего: {len(lst)} файл(-а, -ов)')\n", " return lst\n" ] }, { "cell_type": "code", "execution_count": 48, "id": "76cbf432", "metadata": {}, "outputs": [], "source": [ "### Перевод в MapInfo\n", "folder = 'Output'\n", "for shp in lst:\n", " shp_name = os.path.splitext(os.path.basename(shp))[0]\n", " gdf = gpd.read_file(shp)\n", " gdf.to_file(folder + '\\\\' + shp_name, driver='MapInfo File')" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.14.3" } }, "nbformat": 4, "nbformat_minor": 5 }