Convert CSV to GeoCSV (EMC)¶
This guide shows how to turn a plain CSV table into a valid GeoCSV file that EMC tools can ingest — using the sample header templates in samples/.
GeoCSV = header (lines starting with
#) + your CSV data.
You can usually make one by concatenating a prepared header file and your CSV body.
What is GeoCSV (in EMC)?¶
GeoCSV is a simple, text-based format:
- A header block of metadata lines beginning with # key: value
- Followed by a data table (comma-separated by default)
- For gridded Earth models, the header declares which columns are coordinates (x, y, optional z) and which columns are model variables (e.g., vp, vs, rho).
This repository provides three header templates:
samples/header_2D.csv– 2D models (y, x + variables)samples/header_3D.csv– 3D models (y, x, z + variables)samples/header_3D_projected.csv– 3D with a projected CRS (e.g., UTM) and geographic lat/lon variables
Each template already includes the required GeoCSV keys, for example:
# dataset: GeoCSV2.0
# delimiter: ,
# y_column: latitude
# x_column: longitude
# z_column: depth <-- only in 3D
# vp_column: vp <-- example model variable
# vp_units: km/s
...
latitude,longitude,depth,vp,vs,rho <-- FIRST non-# line is the CSV header row
Prerequisites¶
- Your CSV data file (no
#lines) — call itmy_data.csv - One of the header templates from
samples/ - UTF‑8 encoding, Unix line endings (
\n) recommended - Column names in the first row must match the header’s
*_column:values
Optional, for validation:
- GeoCSV_2_netCDF.py (in EMC_Tools) to convert GeoCSV → NetCDF for quick checks
- emc_inspector.py to verify NetCDF compliance
Quick recipe (concatenate header + data)¶
Pick the right header and concatenate with your data:
2D model¶
# Inspect the header template
sed -n '1,80p' samples/header_2D.csv
# Ensure your CSV header row matches the template’s *_column names
head -1 my_data.csv
# Build GeoCSV
cat samples/header_2D.csv my_data.csv > out_2D.geocsv.csv
3D model (geographic lat/lon/depth)¶
sed -n '1,80p' samples/header_3D.csv
head -1 my_data.csv
cat samples/header_3D.csv my_data.csv > out_3D.geocsv.csv
3D model (projected CRS + lat/lon)¶
sed -n '1,120p' samples/header_3D_projected.csv
head -1 my_data.csv
cat samples/header_3D_projected.csv my_data.csv > out_3D_proj.geocsv.csv
Tip: The output filename extension is arbitrary (
.csvis fine). EMC tools look at the header keys, not the file extension.
Mapping your CSV columns¶
Your CSV’s first row must contain column names. The header’s *_column: keys must point to those exact names. Examples:
2D¶
# y_column: latitude# x_column: longitude- Model variables:
# vp_column: vp# vp_units: km/s# vp_long_name: P-wave velocity
3D¶
# y_column: latitude# x_column: longitude# z_column: depth(positive down usually; make sure units are clear)- Variables as above
3D projected¶
- Projected axes:
# y_column: y(easting or northing depending on your convention)# x_column: x# z_column: depth- Geographic variables also present so the tools can convert/plot:
# latitude_column: latitude# longitude_column: longitude- CRS metadata (in the header):
# grid_ref: projected(and# utm_zone: 11N,# ellipsoid: WGS84, etc.)# geospatial_*_units: metersfor x/y if they are projected
Edit the template to match your column names, units, and descriptions.
Validate your GeoCSV¶
1) Convert to NetCDF (fast structural check)¶
# Show header only (no file written)
python GeoCSV_2_netCDF.py -i out_2D.geocsv.csv -H
# Write a NetCDF4 Classic file
python GeoCSV_2_netCDF.py -i out_2D.geocsv.csv
# → produces out_2D.geocsv.nc (or <input>.nc)
2) Inspect the resulting NetCDF (optional)¶
# Quick look using ncdump (if available)
ncdump -h out_2D.geocsv.nc
# EMC inspector (checks EMC/CF requirements)
python emc_inspector.py
# (You'll be prompted for the file name: enter: out_2D.geocsv.nc)
If emc_inspector.py flags issues (e.g., missing units), update the GeoCSV header and re-run the conversion.
Example end-to-end workflows¶
A) 2D model (lat/lon)¶
- Prepare
my_data.csvwith columns:latitude,longitude,vp,vs 34.5,-117.0,6.10,3.50 34.6,-117.1,6.05,3.48 ... - Edit
samples/header_2D.csvto ensure:# y_column: latitude # x_column: longitude # vp_column: vp # vs_column: vs # vp_units: km/s # vs_units: km/s # delimiter: , - Build and validate:
cat samples/header_2D.csv my_data.csv > my_model_2D.csv python GeoCSV_2_netCDF.py -i my_model_2D.csv python emc_inspector.py # then enter: my_model_2D.nc
B) 3D model (lat/lon/depth)¶
my_data.csv:latitude,longitude,depth,vp 34.5,-117.0,0.0,5.90 34.5,-117.0,5.0,6.05 ...- Edit
samples/header_3D.csv:# z_column: depth # depth_units: km # geospatial_vertical_positive: down - Concatenate and convert:
cat samples/header_3D.csv my_data.csv > my_model_3D.csv python GeoCSV_2_netCDF.py -i my_model_3D.csv python emc_inspector.py # enter: my_model_3D.nc
C) 3D projected (e.g., UTM 11N, meters)¶
my_data.csv:x,y,depth,latitude,longitude,vp 379000,3768000,0.0,34.50,-117.00,6.10 379000,3768000,5.0,34.50,-117.00,6.18 ...- Edit
samples/header_3D_projected.csv:# grid_ref: projected # utm_zone: 11N # ellipsoid: WGS84 # x_units: meters # y_units: meters # latitude_column: latitude # longitude_column: longitude - Concatenate and convert:
cat samples/header_3D_projected.csv my_data.csv > my_model_3D_proj.csv python GeoCSV_2_netCDF.py -i my_model_3D_proj.csv python emc_inspector.py # enter: my_model_3D_proj.nc
Common pitfalls & fixes¶
- Header/data delimiter mismatch: If your CSV uses
;or|, set# delimiter: ;(or|) in the header. - Column names don’t match: The header’s
*_columnvalues must match the CSV header row exactly. - Units missing: Provide
<var>_unitskey for every variable and coordinate. - Depth sign/origin: Clarify with
geospatial_vertical_positive: down(commonly for depth), and setdepth_units. - Projected models without lat/lon: For EMC tools, include both projected coordinates and latitude/longitude.
- Encoding/BOM: Save in UTF‑8 without BOM.
- Sorting: Not required for GeoCSV, but
GeoCSV_2_netCDF.pywill sort when building gridded arrays.
Next steps¶
- Convert GeoCSV → NetCDF:
python GeoCSV_2_netCDF.py -i my_model.csv - Validate the NetCDF:
python emc_inspector.py(enter the produced.ncfile) - Contribute the model following:
docs/how-to/model-contribution-guide.md