{"id":1029,"date":"2026-10-14T11:32:03","date_gmt":"2026-10-14T11:32:03","guid":{"rendered":"https:\/\/helpwithmygisassignment.com\/blog\/?p=1029"},"modified":"2026-10-20T06:32:59","modified_gmt":"2026-10-20T06:32:59","slug":"converting-excel-csv-coordinates-into-shapefiles-programmatically-with-python","status":"publish","type":"post","link":"https:\/\/helpwithmygisassignment.com\/blog\/converting-excel-csv-coordinates-into-shapefiles-programmatically-with-python\/","title":{"rendered":"Converting Excel CSV Coordinates into Shapefiles Programmatically with Python"},"content":{"rendered":"<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_89 counter-hierarchy ez-toc-counter ez-toc-grey ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">Table of Contents<\/p>\n<span class=\"ez-toc-title-toggle\"><a href=\"#\" class=\"ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle\" aria-label=\"Toggle Table of Content\"><span class=\"ez-toc-js-icon-con\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/span><\/a><\/span><\/div>\n<nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-1'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/helpwithmygisassignment.com\/blog\/converting-excel-csv-coordinates-into-shapefiles-programmatically-with-python\/#Converting_Excel_CSV_Coordinates_into_Shapefiles_Programmatically_with_Python\" >Converting Excel CSV Coordinates into Shapefiles Programmatically with Python<\/a><ul class='ez-toc-list-level-2' ><li class='ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/helpwithmygisassignment.com\/blog\/converting-excel-csv-coordinates-into-shapefiles-programmatically-with-python\/#1_Introduction_Converting_Excel_CSV_Coordinates_into_Shapefiles_Programmatically_with_Python\" >1. Introduction: Converting Excel CSV Coordinates into Shapefiles Programmatically with Python<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-1'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/helpwithmygisassignment.com\/blog\/converting-excel-csv-coordinates-into-shapefiles-programmatically-with-python\/#2_Prerequisites\" >2. Prerequisites<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-1'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/helpwithmygisassignment.com\/blog\/converting-excel-csv-coordinates-into-shapefiles-programmatically-with-python\/#3_Example_CSV_Structure\" >3. Example CSV Structure<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-1'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/helpwithmygisassignment.com\/blog\/converting-excel-csv-coordinates-into-shapefiles-programmatically-with-python\/#4_Step_1_%E2%80%94_Read_the_CSV_with_Pandas\" >4. Step 1 \u2014 Read the CSV with Pandas<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-1'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/helpwithmygisassignment.com\/blog\/converting-excel-csv-coordinates-into-shapefiles-programmatically-with-python\/#5_Step_2_%E2%80%94_Clean_the_Coordinate_Columns\" >5. Step 2 \u2014 Clean the Coordinate Columns<\/a><ul class='ez-toc-list-level-2' ><li class='ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/helpwithmygisassignment.com\/blog\/converting-excel-csv-coordinates-into-shapefiles-programmatically-with-python\/#Remove_unnecessary_spaces\" >Remove unnecessary spaces<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/helpwithmygisassignment.com\/blog\/converting-excel-csv-coordinates-into-shapefiles-programmatically-with-python\/#Remove_missing_coordinates\" >Remove missing coordinates<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/helpwithmygisassignment.com\/blog\/converting-excel-csv-coordinates-into-shapefiles-programmatically-with-python\/#Validate_the_coordinate_ranges\" >Validate the coordinate ranges<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-1'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/helpwithmygisassignment.com\/blog\/converting-excel-csv-coordinates-into-shapefiles-programmatically-with-python\/#6_Step_3_%E2%80%94_Convert_the_DataFrame_into_a_GeoDataFrame\" >6. Step 3 \u2014 Convert the DataFrame into a GeoDataFrame<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-1'><a class=\"ez-toc-link ez-toc-heading-11\" href=\"https:\/\/helpwithmygisassignment.com\/blog\/converting-excel-csv-coordinates-into-shapefiles-programmatically-with-python\/#7_Step_4_%E2%80%94_Set_the_Coordinate_Reference_System\" >7. Step 4 \u2014 Set the Coordinate Reference System<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-12\" href=\"https:\/\/helpwithmygisassignment.com\/blog\/converting-excel-csv-coordinates-into-shapefiles-programmatically-with-python\/#Why_explicitly_define_the_CRS\" >Why explicitly define the CRS?<\/a><\/li><\/ul><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-1'><a class=\"ez-toc-link ez-toc-heading-13\" href=\"https:\/\/helpwithmygisassignment.com\/blog\/converting-excel-csv-coordinates-into-shapefiles-programmatically-with-python\/#8_Step_5_%E2%80%94_Export_to_an_ESRI_Shapefile\" >8. Step 5 \u2014 Export to an ESRI Shapefile<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-1'><a class=\"ez-toc-link ez-toc-heading-14\" href=\"https:\/\/helpwithmygisassignment.com\/blog\/converting-excel-csv-coordinates-into-shapefiles-programmatically-with-python\/#9_Export_to_GeoPackage\" >9. Export to GeoPackage<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-1'><a class=\"ez-toc-link ez-toc-heading-15\" href=\"https:\/\/helpwithmygisassignment.com\/blog\/converting-excel-csv-coordinates-into-shapefiles-programmatically-with-python\/#10_Complete_Script\" >10. Complete Script<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-1'><a class=\"ez-toc-link ez-toc-heading-16\" href=\"https:\/\/helpwithmygisassignment.com\/blog\/converting-excel-csv-coordinates-into-shapefiles-programmatically-with-python\/#11_Saving_GeoJSON_with_Python\" >11. Saving GeoJSON with Python<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-1'><a class=\"ez-toc-link ez-toc-heading-17\" href=\"https:\/\/helpwithmygisassignment.com\/blog\/converting-excel-csv-coordinates-into-shapefiles-programmatically-with-python\/#12_Common_Pitfall_Inverted_Latitude_and_Longitude\" >12. Common Pitfall: Inverted Latitude and Longitude<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-18\" href=\"https:\/\/helpwithmygisassignment.com\/blog\/converting-excel-csv-coordinates-into-shapefiles-programmatically-with-python\/#Quick_diagnostic\" >Quick diagnostic<\/a><\/li><\/ul><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-1'><a class=\"ez-toc-link ez-toc-heading-19\" href=\"https:\/\/helpwithmygisassignment.com\/blog\/converting-excel-csv-coordinates-into-shapefiles-programmatically-with-python\/#13_Common_Pitfall_Numbers_Stored_as_Strings\" >13. Common Pitfall: Numbers Stored as Strings<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-1'><a class=\"ez-toc-link ez-toc-heading-20\" href=\"https:\/\/helpwithmygisassignment.com\/blog\/converting-excel-csv-coordinates-into-shapefiles-programmatically-with-python\/#14_Common_Pitfall_Spaces_in_Column_Names\" >14. Common Pitfall: Spaces in Column Names<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-1'><a class=\"ez-toc-link ez-toc-heading-21\" href=\"https:\/\/helpwithmygisassignment.com\/blog\/converting-excel-csv-coordinates-into-shapefiles-programmatically-with-python\/#15_Common_Pandas_and_GeoPandas_Errors\" >15. Common Pandas and GeoPandas Errors<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-22\" href=\"https:\/\/helpwithmygisassignment.com\/blog\/converting-excel-csv-coordinates-into-shapefiles-programmatically-with-python\/#KeyError_Latitude\" >KeyError: 'Latitude'<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-23\" href=\"https:\/\/helpwithmygisassignment.com\/blog\/converting-excel-csv-coordinates-into-shapefiles-programmatically-with-python\/#ValueError_could_not_convert_string_to_float\" >ValueError: could not convert string to float<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-24\" href=\"https:\/\/helpwithmygisassignment.com\/blog\/converting-excel-csv-coordinates-into-shapefiles-programmatically-with-python\/#Geometry_is_empty_or_invalid\" >Geometry is empty or invalid<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-25\" href=\"https:\/\/helpwithmygisassignment.com\/blog\/converting-excel-csv-coordinates-into-shapefiles-programmatically-with-python\/#Points_appear_in_the_wrong_location\" >Points appear in the wrong location<\/a><\/li><\/ul><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-1'><a class=\"ez-toc-link ez-toc-heading-26\" href=\"https:\/\/helpwithmygisassignment.com\/blog\/converting-excel-csv-coordinates-into-shapefiles-programmatically-with-python\/#16_A_More_Robust_Automated_Workflow\" >16. A More Robust Automated Workflow<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-1'><a class=\"ez-toc-link ez-toc-heading-27\" href=\"https:\/\/helpwithmygisassignment.com\/blog\/converting-excel-csv-coordinates-into-shapefiles-programmatically-with-python\/#17_Practical_GIS_Automation_Tips\" >17. Practical GIS Automation Tips<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-1'><a class=\"ez-toc-link ez-toc-heading-28\" href=\"https:\/\/helpwithmygisassignment.com\/blog\/converting-excel-csv-coordinates-into-shapefiles-programmatically-with-python\/#18_Summary\" >18. Summary<\/a><\/li><\/ul><\/nav><\/div>\n<h1><span class=\"ez-toc-section\" id=\"Converting_Excel_CSV_Coordinates_into_Shapefiles_Programmatically_with_Python\"><\/span>Converting Excel CSV Coordinates into Shapefiles Programmatically with Python<span class=\"ez-toc-section-end\"><\/span><\/h1>\n<p><b data-path-to-node=\"15,0\" data-index-in-node=\"1\">Converting Excel CSV Coordinates into Shapefiles Programmatically with Python<\/b> saves time when you regularly receive tabular GIS data as spreadsheets containing latitude and longitude values.<\/p>\n<p>With <strong>Python, pandas, <a href=\"https:\/\/helpwithmygisassignment.com\/blog\/arcpy-for-beginners-arcgis-pro-complete-automation-guide\/\">GeoPandas<\/a>, and <a href=\"https:\/\/shapely.readthedocs.io\/\" target=\"_blank\" rel=\"noopener\">Shapely<\/a><\/strong>, you can automate the entire workflow: read the table, clean the coordinates, create point geometries, assign a CRS, and export the result as a Shapefile or GeoPackage.<\/p>\n<p>This is especially useful for <strong>automated GIS data cleaning<\/strong> and repeatable GIS workflows.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"1_Introduction_Converting_Excel_CSV_Coordinates_into_Shapefiles_Programmatically_with_Python\"><\/span>1. Introduction: Converting Excel CSV Coordinates into Shapefiles Programmatically with Python<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-1170 size-large\" src=\"https:\/\/helpwithmygisassignment.com\/blog\/wp-content\/uploads\/2026\/10\/Gemini_Generated_Image_tkdzmntkdzmntkdz-1024x559.jpg\" alt=\"Converting Excel CSV Coordinates into Shapefiles Programmatically with Python script output displaying geospatial point layers in QGIS.\" width=\"1024\" height=\"559\" srcset=\"https:\/\/helpwithmygisassignment.com\/blog\/wp-content\/uploads\/2026\/10\/Gemini_Generated_Image_tkdzmntkdzmntkdz-1024x559.jpg 1024w, https:\/\/helpwithmygisassignment.com\/blog\/wp-content\/uploads\/2026\/10\/Gemini_Generated_Image_tkdzmntkdzmntkdz-300x164.jpg 300w, https:\/\/helpwithmygisassignment.com\/blog\/wp-content\/uploads\/2026\/10\/Gemini_Generated_Image_tkdzmntkdzmntkdz-768x419.jpg 768w, https:\/\/helpwithmygisassignment.com\/blog\/wp-content\/uploads\/2026\/10\/Gemini_Generated_Image_tkdzmntkdzmntkdz.jpg 1408w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/p>\n<p>Imagine receiving a CSV file every week containing:<\/p>\n<div>\n<div>\n<div>\n<table>\n<thead>\n<tr>\n<th>Site_ID<\/th>\n<th>Name<\/th>\n<th>Latitude<\/th>\n<th>Longitude<\/th>\n<th>Population<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>001<\/td>\n<td>Site A<\/td>\n<td>-1.286389<\/td>\n<td>36.817223<\/td>\n<td>1200<\/td>\n<\/tr>\n<tr>\n<td>002<\/td>\n<td>Site B<\/td>\n<td>-1.292066<\/td>\n<td>36.821945<\/td>\n<td>850<\/td>\n<\/tr>\n<tr>\n<td>003<\/td>\n<td>Site C<\/td>\n<td>-1.300000<\/td>\n<td>36.810000<\/td>\n<td>640<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<\/div>\n<p>You could:<\/p>\n<ol start=\"1\">\n<li>Open QGIS or ArcGIS Pro.<\/li>\n<li>Import the CSV.<\/li>\n<li>Tell the software which columns contain X and Y.<\/li>\n<li>Set the CRS.<\/li>\n<li>Export the layer.<\/li>\n<li>Repeat the process next week.<\/li>\n<\/ol>\n<p>That works, but it is not very efficient when the workflow is repeated frequently.<\/p>\n<p>A Python script can perform the same process automatically:<\/p>\n<div>\n<pre dir=\"ltr\"><code>CSV\r\n \u2193\r\nRead with pandas\r\n \u2193\r\nClean coordinates\r\n \u2193\r\nCreate Point geometries\r\n \u2193\r\nAssign CRS\r\n \u2193\r\nExport Shapefile \/ GeoPackage<\/code><\/pre>\n<\/div>\n<p>This approach is particularly useful when processing dozens or hundreds of files.<\/p>\n<hr \/>\n<h1><span class=\"ez-toc-section\" id=\"2_Prerequisites\"><\/span>2. Prerequisites<span class=\"ez-toc-section-end\"><\/span><\/h1>\n<p>You need Python and three main libraries:<\/p>\n<ul>\n<li><strong>pandas<\/strong> \u2014 reads and manipulates tabular data.<\/li>\n<li><strong>GeoPandas<\/strong> \u2014 adds geospatial capabilities to pandas.<\/li>\n<li><strong>Shapely<\/strong> \u2014 creates and works with geometric objects such as points.<\/li>\n<\/ul>\n<p>Install them with:<\/p>\n<div>\n<pre dir=\"ltr\"><code>pip install pandas geopandas shapely<\/code><\/pre>\n<\/div>\n<p>You can verify the installation with:<\/p>\n<div>\n<pre dir=\"ltr\"><code>import pandas as pdimport geopandas as gpdimport shapelyprint(\"pandas:\", pd.__version__)print(\"geopandas:\", gpd.__version__)print(\"shapely:\", shapely.__version__)<\/code><\/pre>\n<\/div>\n<div><\/div>\n<blockquote><p><strong>Tip:<\/strong> If you are using Conda, installing GeoPandas through <code dir=\"ltr\">conda-forge<\/code> can sometimes be easier because GeoPandas depends on several geospatial packages.<\/p><\/blockquote>\n<hr \/>\n<h1><span class=\"ez-toc-section\" id=\"3_Example_CSV_Structure\"><\/span>3. Example CSV Structure<span class=\"ez-toc-section-end\"><\/span><\/h1>\n<p>For this tutorial, assume your file is called:<\/p>\n<div>\n<pre dir=\"ltr\"><code>sites.csv<\/code><\/pre>\n<\/div>\n<p>And contains:<\/p>\n<div>\n<pre dir=\"ltr\"><code>Site_ID,Name,Latitude,Longitude,Population\r\n001,Site A,-1.286389,36.817223,1200\r\n002,Site B,-1.292066,36.821945,850\r\n003,Site C,-1.300000,36.810000,640<\/code><\/pre>\n<\/div>\n<p>The important columns are:<\/p>\n<ul>\n<li><code dir=\"ltr\">Latitude<\/code><\/li>\n<li><code dir=\"ltr\">Longitude<\/code><\/li>\n<\/ul>\n<p>The other columns become attributes in the resulting GIS layer.<\/p>\n<hr \/>\n<h1><span class=\"ez-toc-section\" id=\"4_Step_1_%E2%80%94_Read_the_CSV_with_Pandas\"><\/span>4. Step 1 \u2014 Read the CSV with Pandas<span class=\"ez-toc-section-end\"><\/span><\/h1>\n<p>The first step is to load the CSV into a pandas DataFrame.<\/p>\n<div>\n<pre dir=\"ltr\"><code>import pandas as pd# Read the CSV filedf = pd.read_csv(\"sites.csv\")# Display the first five recordsprint(df.head())<\/code><\/pre>\n<\/div>\n<div><\/div>\n<p>You can also inspect the column names:<\/p>\n<div>\n<pre dir=\"ltr\"><code>print(df.columns)<\/code><\/pre>\n<\/div>\n<div><\/div>\n<p>And check the data types:<\/p>\n<div>\n<pre dir=\"ltr\"><code>print(df.dtypes)<\/code><\/pre>\n<\/div>\n<div><\/div>\n<p>You might see something like:<\/p>\n<div>\n<pre dir=\"ltr\"><code>Site_ID        int64\r\nName          object\r\nLatitude     float64\r\nLongitude    float64\r\nPopulation     int64\r\ndtype: object<\/code><\/pre>\n<\/div>\n<p>At this point, the data is still an ordinary table. It does not contain GIS geometry yet.<\/p>\n<hr \/>\n<h1><span class=\"ez-toc-section\" id=\"5_Step_2_%E2%80%94_Clean_the_Coordinate_Columns\"><\/span>5. Step 2 \u2014 Clean the Coordinate Columns<span class=\"ez-toc-section-end\"><\/span><\/h1>\n<p>This is one of the most important parts of the workflow.<\/p>\n<p>Real-world spreadsheets are rarely perfectly clean. Coordinates may contain:<\/p>\n<ul>\n<li>Empty cells<\/li>\n<li>Leading or trailing spaces<\/li>\n<li>Numbers stored as text<\/li>\n<li>Commas or other formatting characters<\/li>\n<li>Invalid values<\/li>\n<\/ul>\n<p>For example:<\/p>\n<div>\n<pre dir=\"ltr\"><code>\" -1.286389 \"\r\n\"36.817223 \"<\/code><\/pre>\n<\/div>\n<p>Although these look like numbers, they may actually be strings.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Remove_unnecessary_spaces\"><\/span>Remove unnecessary spaces<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<div>\n<pre dir=\"ltr\"><code>df[\"Latitude\"] = df[\"Latitude\"].astype(str).str.strip()df[\"Longitude\"] = df[\"Longitude\"].astype(str).str.strip()<\/code><\/pre>\n<\/div>\n<div><\/div>\n<p>Then convert them to numeric values:<\/p>\n<div>\n<pre dir=\"ltr\"><code>df[\"Latitude\"] = pd.to_numeric(df[\"Latitude\"], errors=\"coerce\")df[\"Longitude\"] = pd.to_numeric(df[\"Longitude\"], errors=\"coerce\")<\/code><\/pre>\n<\/div>\n<div><\/div>\n<p>The <code dir=\"ltr\">errors=\"coerce\"<\/code> option converts values that cannot be interpreted as numbers into <code dir=\"ltr\">NaN<\/code>.<\/p>\n<p>For example:<\/p>\n<div>\n<pre dir=\"ltr\"><code>\"-1.286389\" \u2192 -1.286389\r\n\"36.817223\" \u2192 36.817223\r\n\"unknown\"   \u2192 NaN<\/code><\/pre>\n<\/div>\n<h3><span class=\"ez-toc-section\" id=\"Remove_missing_coordinates\"><\/span>Remove missing coordinates<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<div>\n<pre dir=\"ltr\"><code>df = df.dropna(subset=[\"Latitude\", \"Longitude\"])<\/code><\/pre>\n<\/div>\n<div><\/div>\n<p>This prevents rows without usable coordinates from creating invalid geometries.<\/p>\n<hr \/>\n<h2><span class=\"ez-toc-section\" id=\"Validate_the_coordinate_ranges\"><\/span>Validate the coordinate ranges<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>For latitude and longitude in the WGS 84 coordinate system:<\/p>\n<ul>\n<li>Latitude must be between <strong>-90 and 90<\/strong><\/li>\n<li>Longitude must be between <strong>-180 and 180<\/strong><\/li>\n<\/ul>\n<p>You can filter invalid records:<\/p>\n<div>\n<pre dir=\"ltr\"><code>df = df[    df[\"Latitude\"].between(-90, 90) &amp;    df[\"Longitude\"].between(-180, 180)]<\/code><\/pre>\n<\/div>\n<div><\/div>\n<p>This is a useful step in an <strong>automated GIS data cleaning<\/strong> pipeline.<\/p>\n<hr \/>\n<h1><span class=\"ez-toc-section\" id=\"6_Step_3_%E2%80%94_Convert_the_DataFrame_into_a_GeoDataFrame\"><\/span>6. Step 3 \u2014 Convert the DataFrame into a GeoDataFrame<span class=\"ez-toc-section-end\"><\/span><\/h1>\n<p>Now we can turn the coordinate columns into actual GIS point geometries.<\/p>\n<p>Import the required GeoPandas and Shapely functionality:<\/p>\n<div>\n<pre dir=\"ltr\"><code>import geopandas as gpd\r\nfrom shapely.geometry import Point<\/code><\/pre>\n<\/div>\n<p>Create the geometry:<\/p>\n<div>\n<pre dir=\"ltr\"><code>geometry = [\r\n    Point(lon, lat)\r\n    for lon, lat in zip(df[\"Longitude\"], df[\"Latitude\"])\r\n]<\/code><\/pre>\n<\/div>\n<p>Notice the order:<\/p>\n<div>\n<pre dir=\"ltr\"><code>Point(longitude, latitude)<\/code><\/pre>\n<\/div>\n<p><strong>Longitude comes first. Latitude comes second.<\/strong><\/p>\n<p>Now create a GeoDataFrame:<\/p>\n<div>\n<pre dir=\"ltr\"><code>gdf = gpd.GeoDataFrame(\r\n    df,\r\n    geometry=geometry\r\n)<\/code><\/pre>\n<\/div>\n<p>You can inspect it:<\/p>\n<div>\n<pre dir=\"ltr\"><code>print(gdf.head())<\/code><\/pre>\n<\/div>\n<p>You now have a spatial dataset.<\/p>\n<hr \/>\n<h1><span class=\"ez-toc-section\" id=\"7_Step_4_%E2%80%94_Set_the_Coordinate_Reference_System\"><\/span>7. Step 4 \u2014 Set the Coordinate Reference System<span class=\"ez-toc-section-end\"><\/span><\/h1>\n<p>The coordinates in our example are latitude\/longitude coordinates using <strong>WGS 84<\/strong>.<\/p>\n<p>Its EPSG code is:<\/p>\n<div>\n<pre dir=\"ltr\"><code>EPSG:4326<\/code><\/pre>\n<\/div>\n<p>Assign it to the GeoDataFrame:<\/p>\n<div>\n<pre dir=\"ltr\"><code>gdf = gdf.set_crs(\"EPSG:4326\")<\/code><\/pre>\n<\/div>\n<p>You can verify it:<\/p>\n<div>\n<pre dir=\"ltr\"><code>print(gdf.crs)<\/code><\/pre>\n<\/div>\n<p>Output:<\/p>\n<div>\n<pre dir=\"ltr\"><code>EPSG:4326<\/code><\/pre>\n<\/div>\n<h3><span class=\"ez-toc-section\" id=\"Why_explicitly_define_the_CRS\"><\/span>Why explicitly define the CRS?<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>A coordinate such as:<\/p>\n<div>\n<pre dir=\"ltr\"><code>36.817223, -1.286389<\/code><\/pre>\n<\/div>\n<p>has little meaning to GIS software without knowing the coordinate reference system.<\/p>\n<p>The CRS tells GIS software how those coordinates relate to the Earth&#8217;s surface.<\/p>\n<blockquote><p><strong>Important:<\/strong> <code dir=\"ltr\">set_crs()<\/code> assigns the existing coordinate system. It does <strong>not<\/strong> transform the coordinates.<\/p><\/blockquote>\n<p>If you need to convert the data to another CRS, use:<\/p>\n<div>\n<pre dir=\"ltr\"><code>gdf = gdf.to_crs(\"EPSG:XXXX\")<\/code><\/pre>\n<\/div>\n<div><\/div>\n<p>For example:<\/p>\n<div>\n<pre dir=\"ltr\"><code>gdf_projected = gdf.to_crs(\"EPSG:3857\")<\/code><\/pre>\n<\/div>\n<hr \/>\n<h1><span class=\"ez-toc-section\" id=\"8_Step_5_%E2%80%94_Export_to_an_ESRI_Shapefile\"><\/span>8. Step 5 \u2014 Export to an ESRI Shapefile<span class=\"ez-toc-section-end\"><\/span><\/h1>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-1171 size-large\" src=\"https:\/\/helpwithmygisassignment.com\/blog\/wp-content\/uploads\/2026\/10\/Gemini_Generated_Image_pngngypngngypngn-1024x559.jpg\" alt=\"Converting Excel CSV Coordinates into Shapefiles Programmatically with Python script output displaying geospatial point layers in QGIS.\" width=\"1024\" height=\"559\" srcset=\"https:\/\/helpwithmygisassignment.com\/blog\/wp-content\/uploads\/2026\/10\/Gemini_Generated_Image_pngngypngngypngn-1024x559.jpg 1024w, https:\/\/helpwithmygisassignment.com\/blog\/wp-content\/uploads\/2026\/10\/Gemini_Generated_Image_pngngypngngypngn-300x164.jpg 300w, https:\/\/helpwithmygisassignment.com\/blog\/wp-content\/uploads\/2026\/10\/Gemini_Generated_Image_pngngypngngypngn-768x419.jpg 768w, https:\/\/helpwithmygisassignment.com\/blog\/wp-content\/uploads\/2026\/10\/Gemini_Generated_Image_pngngypngngypngn.jpg 1408w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/p>\n<p>Once the GeoDataFrame is ready, exporting it is straightforward.<\/p>\n<div>\n<pre dir=\"ltr\"><code>gdf.to_file(\r\n    \"sites.shp\",\r\n    driver=\"ESRI Shapefile\"\r\n)<\/code><\/pre>\n<\/div>\n<p>This creates a Shapefile dataset.<\/p>\n<p>However, remember that a Shapefile is actually a collection of files, typically including:<\/p>\n<div>\n<pre dir=\"ltr\"><code>sites.shp\r\nsites.shx\r\nsites.dbf\r\nsites.prj<\/code><\/pre>\n<\/div>\n<p>Keep these files together.<\/p>\n<p>The <code dir=\"ltr\">.shp<\/code> file alone is not the complete dataset.<\/p>\n<hr \/>\n<h1><span class=\"ez-toc-section\" id=\"9_Export_to_GeoPackage\"><\/span>9. Export to GeoPackage<span class=\"ez-toc-section-end\"><\/span><\/h1>\n<p>GeoPackage is often a better modern alternative to Shapefile.<\/p>\n<p>You can export the same GeoDataFrame using:<\/p>\n<div>\n<pre dir=\"ltr\"><code>gdf.to_file(\r\n    \"sites.gpkg\",\r\n    layer=\"sites\",\r\n    driver=\"GPKG\"\r\n)<\/code><\/pre>\n<\/div>\n<p>This produces:<\/p>\n<div>\n<pre dir=\"ltr\"><code>sites.gpkg<\/code><\/pre>\n<\/div>\n<p>Unlike a Shapefile, the main dataset is contained in a single file.<\/p>\n<p>GeoPackage also avoids several traditional Shapefile limitations, making it useful for modern GIS workflows.<\/p>\n<hr \/>\n<h1><span class=\"ez-toc-section\" id=\"10_Complete_Script\"><\/span>10. Complete Script<span class=\"ez-toc-section-end\"><\/span><\/h1>\n<p>Once you understand the individual steps, they can be combined into one reusable script.<\/p>\n<div>\n<pre dir=\"ltr\"><code>import pandas as pdimport geopandas as gpdfrom shapely.geometry import Point# --------------------------------------------------# 1. Read CSV# --------------------------------------------------df = pd.read_csv(\"sites.csv\")# --------------------------------------------------# 2. Clean coordinate columns# --------------------------------------------------# Remove leading\/trailing spacesdf[\"Latitude\"] = df[\"Latitude\"].astype(str).str.strip()df[\"Longitude\"] = df[\"Longitude\"].astype(str).str.strip()# Convert coordinates to numeric valuesdf[\"Latitude\"] = pd.to_numeric(    df[\"Latitude\"],    errors=\"coerce\")df[\"Longitude\"] = pd.to_numeric(    df[\"Longitude\"],    errors=\"coerce\")# Remove rows with missing coordinatesdf = df.dropna(    subset=[\"Latitude\", \"Longitude\"])# --------------------------------------------------# 3. Remove invalid coordinates<\/code><\/pre>\n<\/div>\n<div><\/div>\n<p>This script now performs the entire <strong>Convert CSV to Shapefile Python GeoPandas<\/strong> workflow automatically.<\/p>\n<hr \/>\n<h1><span class=\"ez-toc-section\" id=\"11_Saving_GeoJSON_with_Python\"><\/span>11. Saving GeoJSON with Python<span class=\"ez-toc-section-end\"><\/span><\/h1>\n<p>You can also export the same data to GeoJSON.<\/p>\n<div>\n<pre dir=\"ltr\"><code>gdf.to_file(\r\n    \"sites.geojson\",\r\n    driver=\"GeoJSON\"\r\n)<\/code><\/pre>\n<\/div>\n<p>This can be particularly useful when working with web GIS applications.<\/p>\n<p>A complete export section might therefore look like:<\/p>\n<div>\n<pre dir=\"ltr\"><code># Shapefile\r\ngdf.to_file(\r\n    \"sites.shp\",\r\n    driver=\"ESRI Shapefile\"\r\n)\r\n\r\n# GeoPackage\r\ngdf.to_file(\r\n    \"sites.gpkg\",\r\n    layer=\"sites\",\r\n    driver=\"GPKG\"\r\n)\r\n\r\n# GeoJSON\r\ngdf.to_file(\r\n    \"sites.geojson\",\r\n    driver=\"GeoJSON\"\r\n)<\/code><\/pre>\n<\/div>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-large wp-image-1337\" src=\"https:\/\/helpwithmygisassignment.com\/blog\/wp-content\/uploads\/2026\/10\/Gemini_Generated_Image_kx3ir9kx3ir9kx3i-1024x572.jpg\" alt=\"Python GeoPandas software interface showing tabular coordinate data converting into spatial map layers\" width=\"1024\" height=\"572\" srcset=\"https:\/\/helpwithmygisassignment.com\/blog\/wp-content\/uploads\/2026\/10\/Gemini_Generated_Image_kx3ir9kx3ir9kx3i-1024x572.jpg 1024w, https:\/\/helpwithmygisassignment.com\/blog\/wp-content\/uploads\/2026\/10\/Gemini_Generated_Image_kx3ir9kx3ir9kx3i-300x167.jpg 300w, https:\/\/helpwithmygisassignment.com\/blog\/wp-content\/uploads\/2026\/10\/Gemini_Generated_Image_kx3ir9kx3ir9kx3i-768x429.jpg 768w, https:\/\/helpwithmygisassignment.com\/blog\/wp-content\/uploads\/2026\/10\/Gemini_Generated_Image_kx3ir9kx3ir9kx3i.jpg 1376w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/p>\n<p>This gives you three common GIS formats from the same source table.<\/p>\n<hr \/>\n<h1><span class=\"ez-toc-section\" id=\"12_Common_Pitfall_Inverted_Latitude_and_Longitude\"><\/span>12. Common Pitfall: Inverted Latitude and Longitude<span class=\"ez-toc-section-end\"><\/span><\/h1>\n<p>One of the most common mistakes when converting coordinates programmatically is reversing the coordinate order.<\/p>\n<p>Correct:<\/p>\n<div>\n<pre dir=\"ltr\"><code>Point(longitude, latitude)<\/code><\/pre>\n<\/div>\n<p>Incorrect:<\/p>\n<div>\n<pre dir=\"ltr\"><code>Point(latitude, longitude)<\/code><\/pre>\n<\/div>\n<p>For example, consider:<\/p>\n<div>\n<pre dir=\"ltr\"><code>Latitude:  -1.286389\r\nLongitude: 36.817223<\/code><\/pre>\n<\/div>\n<p>The correct Shapely point is:<\/p>\n<div>\n<pre dir=\"ltr\"><code>Point(36.817223, -1.286389)<\/code><\/pre>\n<\/div>\n<p>not:<\/p>\n<div>\n<pre dir=\"ltr\"><code>Point(-1.286389, 36.817223)<\/code><\/pre>\n<\/div>\n<p>The second version can place your points thousands of kilometres away from their intended location.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Quick_diagnostic\"><\/span>Quick diagnostic<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Before creating the geometry, inspect a few coordinates:<\/p>\n<div>\n<pre dir=\"ltr\"><code>print(df[[\"Latitude\", \"Longitude\"]].head())<\/code><\/pre>\n<\/div>\n<p>Then check your resulting layer in QGIS or ArcGIS Pro.<\/p>\n<hr \/>\n<h1><span class=\"ez-toc-section\" id=\"13_Common_Pitfall_Numbers_Stored_as_Strings\"><\/span>13. Common Pitfall: Numbers Stored as Strings<span class=\"ez-toc-section-end\"><\/span><\/h1>\n<p>A CSV might contain:<\/p>\n<div>\n<pre dir=\"ltr\"><code>Latitude\r\n-1.286389\r\n-1.292066\r\n-1.300000<\/code><\/pre>\n<\/div>\n<p>but pandas could interpret the values as strings if the column contains inconsistent formatting.<\/p>\n<p>Check the data type:<\/p>\n<div>\n<pre dir=\"ltr\"><code>print(df[\"Latitude\"].dtype)<\/code><\/pre>\n<\/div>\n<p>If necessary, convert it:<\/p>\n<div>\n<pre dir=\"ltr\"><code>df[\"Latitude\"] = pd.to_numeric(\r\n    df[\"Latitude\"],\r\n    errors=\"coerce\"\r\n)<\/code><\/pre>\n<\/div>\n<p>Do the same for longitude:<\/p>\n<div>\n<pre dir=\"ltr\"><code>df[\"Longitude\"] = pd.to_numeric(\r\n    df[\"Longitude\"],\r\n    errors=\"coerce\"\r\n)<\/code><\/pre>\n<\/div>\n<hr \/>\n<h1><span class=\"ez-toc-section\" id=\"14_Common_Pitfall_Spaces_in_Column_Names\"><\/span>14. Common Pitfall: Spaces in Column Names<span class=\"ez-toc-section-end\"><\/span><\/h1>\n<p>Sometimes Excel exports produce column names such as:<\/p>\n<div>\n<pre dir=\"ltr\"><code>\" Latitude\"\r\n\"Longitude \"<\/code><\/pre>\n<\/div>\n<p>This can cause:<\/p>\n<div>\n<pre dir=\"ltr\"><code>df[\"Latitude\"]<\/code><\/pre>\n<\/div>\n<p>to fail.<\/p>\n<p>A useful cleaning step is:<\/p>\n<div>\n<pre dir=\"ltr\"><code>df.columns = df.columns.str.strip()<\/code><\/pre>\n<\/div>\n<p>You can also make column names lowercase:<\/p>\n<div>\n<pre dir=\"ltr\"><code>df.columns = df.columns.str.strip().str.lower()<\/code><\/pre>\n<\/div>\n<p>Then your columns become:<\/p>\n<div>\n<pre dir=\"ltr\"><code>site_id\r\nname\r\nlatitude\r\nlongitude\r\npopulation<\/code><\/pre>\n<\/div>\n<p>Your code would then use:<\/p>\n<div>\n<pre dir=\"ltr\"><code>df[\"latitude\"]\r\ndf[\"longitude\"]<\/code><\/pre>\n<\/div>\n<p>This is particularly useful when building scripts that process files from different sources.<\/p>\n<hr \/>\n<h1><span class=\"ez-toc-section\" id=\"15_Common_Pandas_and_GeoPandas_Errors\"><\/span>15. Common Pandas and GeoPandas Errors<span class=\"ez-toc-section-end\"><\/span><\/h1>\n<h3><span class=\"ez-toc-section\" id=\"KeyError_Latitude\"><\/span><code dir=\"ltr\">KeyError: 'Latitude'<\/code><span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>This usually means pandas cannot find a column with exactly that name.<\/p>\n<p>Check:<\/p>\n<div>\n<pre dir=\"ltr\"><code>print(df.columns.tolist())<\/code><\/pre>\n<\/div>\n<p>Look for differences such as:<\/p>\n<div>\n<pre dir=\"ltr\"><code>\"Latitude \"\r\n\" latitude\"\r\n\"LATITUDE\"<\/code><\/pre>\n<\/div>\n<p>Then clean the column names:<\/p>\n<div>\n<pre dir=\"ltr\"><code>df.columns = df.columns.str.strip()<\/code><\/pre>\n<\/div>\n<hr \/>\n<h3><span class=\"ez-toc-section\" id=\"ValueError_could_not_convert_string_to_float\"><\/span><code dir=\"ltr\">ValueError: could not convert string to float<\/code><span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Your coordinate column probably contains invalid text.<\/p>\n<p>Use:<\/p>\n<div>\n<pre dir=\"ltr\"><code>df[\"Latitude\"] = pd.to_numeric(\r\n    df[\"Latitude\"],\r\n    errors=\"coerce\"\r\n)<\/code><\/pre>\n<\/div>\n<p>Then find missing values:<\/p>\n<div>\n<pre dir=\"ltr\"><code>print(df[df[\"Latitude\"].isna()])<\/code><\/pre>\n<\/div>\n<hr \/>\n<h3><span class=\"ez-toc-section\" id=\"Geometry_is_empty_or_invalid\"><\/span>Geometry is empty or invalid<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Check for missing coordinates:<\/p>\n<div>\n<pre dir=\"ltr\"><code>print(df[[\"Latitude\", \"Longitude\"]].isna().sum())<\/code><\/pre>\n<\/div>\n<p>Then remove them:<\/p>\n<div>\n<pre dir=\"ltr\"><code>df = df.dropna(\r\n    subset=[\"Latitude\", \"Longitude\"]\r\n)<\/code><\/pre>\n<\/div>\n<hr \/>\n<h3><span class=\"ez-toc-section\" id=\"Points_appear_in_the_wrong_location\"><\/span>Points appear in the wrong location<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>First check the axis order:<\/p>\n<div>\n<pre dir=\"ltr\"><code>Point(longitude, latitude)<\/code><\/pre>\n<\/div>\n<p>Then check the CRS:<\/p>\n<div>\n<pre dir=\"ltr\"><code>print(gdf.crs)<\/code><\/pre>\n<\/div>\n<p>For latitude\/longitude coordinates, it should normally be:<\/p>\n<div>\n<pre dir=\"ltr\"><code>EPSG:4326<\/code><\/pre>\n<\/div>\n<hr \/>\n<h1><span class=\"ez-toc-section\" id=\"16_A_More_Robust_Automated_Workflow\"><\/span>16. A More Robust Automated Workflow<span class=\"ez-toc-section-end\"><\/span><\/h1>\n<p>Once the basic script works, you can turn it into a reusable function.<\/p>\n<div>\n<pre dir=\"ltr\"><code>import pandas as pd\r\nimport geopandas as gpd\r\nfrom shapely.geometry import Point\r\n\r\n\r\ndef csv_to_geodata(\r\n    input_file,\r\n    output_file,\r\n    latitude_col=\"Latitude\",\r\n    longitude_col=\"Longitude\"\r\n):\r\n\r\n    # Read CSV\r\n    df = pd.read_csv(input_file)\r\n\r\n    # Clean column names\r\n    df.columns = df.columns.str.strip()\r\n\r\n    # Clean coordinates\r\n    df[latitude_col] = pd.to_numeric(\r\n        df[latitude_col].astype(str).str.strip(),\r\n        errors=\"coerce\"\r\n    )\r\n\r\n    df[longitude_col] = pd.to_numeric(\r\n        df[longitude_col].astype(str).str.strip(),\r\n        errors=\"coerce\"\r\n    )\r\n\r\n    # Remove missing coordinates\r\n    df = df.dropna(\r\n        subset=[latitude_col, longitude_col]\r\n    )\r\n\r\n    # Validate coordinate ranges\r\n    df = df[\r\n        df[latitude_col].between(-90, 90) &amp;\r\n        df[longitude_col].between(-180, 180)\r\n    ]\r\n\r\n    # Create geometry\r\n    geometry = [\r\n        Point(lon, lat)\r\n        for lon, lat in zip(\r\n            df[longitude_col],\r\n            df[latitude_col]\r\n        )\r\n    ]\r\n\r\n    # Create GeoDataFrame\r\n    gdf = gpd.GeoDataFrame(\r\n        df,\r\n        geometry=geometry,\r\n        crs=\"EPSG:4326\"\r\n    )\r\n\r\n    # Export\r\n    gdf.to_file(\r\n        output_file,\r\n        driver=\"ESRI Shapefile\"\r\n    )\r\n\r\n    return gdf\r\n\r\n\r\n# Run the conversion\r\nresult = csv_to_geodata(\r\n    \"sites.csv\",\r\n    \"sites.shp\"\r\n)\r\n\r\nprint(result)<\/code><\/pre>\n<\/div>\n<p>Now you can reuse the same function for different datasets without rewriting the entire workflow.<\/p>\n<hr \/>\n<h1><span class=\"ez-toc-section\" id=\"17_Practical_GIS_Automation_Tips\"><\/span>17. Practical GIS Automation Tips<span class=\"ez-toc-section-end\"><\/span><\/h1>\n<p>Once you are comfortable with this workflow, you can expand it considerably.<\/p>\n<p>For example, a Python script can:<\/p>\n<ul>\n<li>Process hundreds of CSV files.<\/li>\n<li>Standardize column names.<\/li>\n<li>Remove invalid coordinates.<\/li>\n<li>Detect missing values.<\/li>\n<li>Create point geometries.<\/li>\n<li>Reproject layers.<\/li>\n<li>Export multiple GIS formats.<\/li>\n<li>Merge datasets.<\/li>\n<li>Calculate spatial attributes.<\/li>\n<li>Generate summary reports.<\/li>\n<\/ul>\n<p>Instead of manually cleaning and importing each file, you can create a repeatable pipeline:<\/p>\n<div>\n<pre dir=\"ltr\"><code>Raw Excel\/CSV\r\n      \u2193\r\nColumn cleaning\r\n      \u2193\r\nCoordinate validation\r\n      \u2193\r\nMissing-value handling\r\n      \u2193\r\nPoint creation\r\n      \u2193\r\nCRS assignment\r\n      \u2193\r\nGIS export\r\n      \u2193\r\nReady-to-use spatial data<\/code><\/pre>\n<\/div>\n<p>That is where <strong>GeoPandas<\/strong> becomes particularly powerful: it allows familiar pandas-style data processing to be combined with spatial operations.<\/p>\n<hr \/>\n<h1><span class=\"ez-toc-section\" id=\"18_Summary\"><\/span>18. Summary<span class=\"ez-toc-section-end\"><\/span><\/h1>\n<p>The basic workflow for <strong>Convert CSV to Shapefile Python GeoPandas<\/strong> is:<\/p>\n<ol start=\"1\">\n<li>Read the CSV using <code dir=\"ltr\">pandas<\/code>.<\/li>\n<li>Clean the coordinate columns.<\/li>\n<li>Convert latitude and longitude to numeric values.<\/li>\n<li>Remove missing or invalid coordinates.<\/li>\n<li>Create Shapely <code dir=\"ltr\">Point<\/code> geometries.<\/li>\n<li>Convert the DataFrame into a GeoDataFrame.<\/li>\n<li>Assign the correct CRS, such as <code dir=\"ltr\">EPSG:4326<\/code>.<\/li>\n<li>Export the result as Shapefile, GeoPackage, or GeoJSON.<\/li>\n<\/ol>\n<p>The most important code pattern to remember is:<\/p>\n<div>\n<pre dir=\"ltr\"><code>df = pd.read_csv(\"sites.csv\")df[\"Latitude\"] = pd.to_numeric(    df[\"Latitude\"],    errors=\"coerce\")df[\"Longitude\"] = pd.to_numeric(    df[\"Longitude\"],    errors=\"coerce\")gdf = gpd.GeoDataFrame(    df,    geometry=[        Point(lon, lat)        for lon, lat in zip(            df[\"Longitude\"],            df[\"Latitude\"]        )    ],    crs=\"EPSG:4326\")gdf.to_file(    \"sites.shp\",    driver=\"ESRI Shapefile\")<\/code><\/pre>\n<\/div>\n<div><\/div>\n<p>Once this pattern becomes familiar, you can move beyond one-off conversions toward <strong>automated GIS data cleaning<\/strong> pipelines that process large numbers of tabular datasets consistently and reproducibly.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Converting Excel CSV Coordinates into Shapefiles Programmatically with Python Converting Excel CSV Coordinates into Shapefiles Programmatically with Python saves time when you regularly receive tabular GIS data as spreadsheets containing latitude and longitude values. With Python, pandas, GeoPandas, and Shapely, you can automate the entire workflow: read the table, clean the coordinates, create point geometries, &#8230; <a title=\"Converting Excel CSV Coordinates into Shapefiles Programmatically with Python\" class=\"read-more\" href=\"https:\/\/helpwithmygisassignment.com\/blog\/converting-excel-csv-coordinates-into-shapefiles-programmatically-with-python\/\" aria-label=\"Read more about Converting Excel CSV Coordinates into Shapefiles Programmatically with Python\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":1170,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[17,4],"tags":[],"class_list":["post-1029","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-civil-engineering","category-gis-articles"],"_links":{"self":[{"href":"https:\/\/helpwithmygisassignment.com\/blog\/wp-json\/wp\/v2\/posts\/1029","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/helpwithmygisassignment.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/helpwithmygisassignment.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/helpwithmygisassignment.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/helpwithmygisassignment.com\/blog\/wp-json\/wp\/v2\/comments?post=1029"}],"version-history":[{"count":7,"href":"https:\/\/helpwithmygisassignment.com\/blog\/wp-json\/wp\/v2\/posts\/1029\/revisions"}],"predecessor-version":[{"id":1338,"href":"https:\/\/helpwithmygisassignment.com\/blog\/wp-json\/wp\/v2\/posts\/1029\/revisions\/1338"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/helpwithmygisassignment.com\/blog\/wp-json\/wp\/v2\/media\/1170"}],"wp:attachment":[{"href":"https:\/\/helpwithmygisassignment.com\/blog\/wp-json\/wp\/v2\/media?parent=1029"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/helpwithmygisassignment.com\/blog\/wp-json\/wp\/v2\/categories?post=1029"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/helpwithmygisassignment.com\/blog\/wp-json\/wp\/v2\/tags?post=1029"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}