3. Cross-over errors#
[1]:
%load_ext autoreload
%autoreload 2
import logging
import geopandas as gpd
import pandas as pd
import plotly.io as pio
import airbornegeo
logging.getLogger("airbornegeo").setLevel("INFO")
logging.basicConfig()
pio.renderers.default = "notebook"
3.1. Load data#
This is a subset of the BAS AGAP survey over Antarctica’s Gamburtsev Subglacial Mountains. The file is download and subset in the notebook AGAP_magnetic_survey, and the BAS processing steps are repeated in the notebook processing_AGAP_magnetic_survey.
[2]:
data_df = pd.read_csv("data/AGAP_magnetic_survey_processed_blocked.csv")
data_df = data_df[
[
"easting",
"northing",
"height",
"line",
"unixtime",
"distance_along_line",
"mag",
]
]
# for testing limit number of lines
data_df = data_df[~data_df.line.between(133, 142)]
data_df = data_df[~data_df.line.between(168, 176)]
data_df = data_df[
(data_df.line.isin(data_df.line.unique()[::2])) | (data_df.line >= 143)
]
# define flight lines vs tie lines with column 'tie' which is True or False
data_df["tie"] = False
data_df.loc[data_df.line >= 142, "tie"] = True
data_df.head()
[2]:
| easting | northing | height | line | unixtime | distance_along_line | mag | tie | |
|---|---|---|---|---|---|---|---|---|
| 0 | 621099.093988 | 159056.748193 | 4110.45 | 1 | 1.229500e+09 | 27.181565 | -33.385 | False |
| 1 | 621206.517953 | 159071.301512 | 4114.50 | 1 | 1.229500e+09 | 135.587530 | -35.120 | False |
| 2 | 621313.794221 | 159085.113599 | 4117.90 | 1 | 1.229500e+09 | 243.749367 | -36.875 | False |
| 3 | 621420.722903 | 159099.184618 | 4120.80 | 1 | 1.229500e+09 | 351.600337 | -38.585 | False |
| 4 | 621527.158177 | 159114.303863 | 4123.15 | 1 | 1.229500e+09 | 459.104857 | -40.205 | False |
[3]:
data_df[data_df.tie].line.sort_values().unique()
[3]:
array([143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155,
156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 177,
178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190,
191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203,
204, 205, 206])
[4]:
data_df[~data_df.tie].line.sort_values().unique()
[4]:
array([ 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25,
27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51,
53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77,
79, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99, 101, 103,
105, 107, 109, 111, 113, 115, 117, 119, 121, 123, 125, 127, 129,
131])
[5]:
airbornegeo.plotly_points(
data_df[data_df.tie],
color_col="line",
hover_cols=["distance_along_line"],
)
[6]:
airbornegeo.plotly_points(
data_df[~data_df.tie],
color_col="line",
hover_cols=["distance_along_line"],
)
3.2. Find intersections#
[7]:
# convert dataframe into geodataframe
data_df = gpd.GeoDataFrame(
data_df,
geometry=gpd.points_from_xy(data_df.easting, data_df.northing),
crs="EPSG:3031",
)
[8]:
# calculate theoretical intersection points
inters = airbornegeo.create_intersection_table(data_df)
inters
INFO:airbornegeo:found 662 intersections
[8]:
| line | tie | geometry | max_dist | easting | northing | |
|---|---|---|---|---|---|---|
| 0 | 1 | 143 | POINT (1158153 254083) | 16.441255 | 1158153.0 | 254083.0 |
| 1 | 1 | 144 | POINT (1190820 259865) | 24.124887 | 1190820.0 | 259865.0 |
| 2 | 1 | 145 | POINT (1223524 265689) | 17.269650 | 1223524.0 | 265689.0 |
| 3 | 1 | 146 | POINT (1256193 271497) | 31.608179 | 1256193.0 | 271497.0 |
| 4 | 1 | 147 | POINT (1288901 277249) | 50.174377 | 1288901.0 | 277249.0 |
| ... | ... | ... | ... | ... | ... | ... |
| 657 | 125 | 199 | POINT (1318165 302398) | 33.689493 | 1318165.0 | 302398.0 |
| 658 | 125 | 200 | POINT (1350929 308239) | 36.343660 | 1350929.0 | 308239.0 |
| 659 | 127 | 148 | POINT (1319894 292699) | 22.093103 | 1319894.0 | 292699.0 |
| 660 | 127 | 199 | POINT (1319922 292702) | 23.297236 | 1319922.0 | 292702.0 |
| 661 | 127 | 200 | POINT (1352642 298507) | 36.743873 | 1352642.0 | 298507.0 |
662 rows × 6 columns
3.3. Add intersections as rows to the dataframe#
We can now add a row to each line of the dataframe which represents the intersection point. We don’t know the data values for the intersection point, so we will also need to interpolate the data from the line data on either side of the intersection. We can specify the interpolation type (‘linear’, ‘nearest’, ‘quadratic’, ‘cubic’ etc.) and a window width of data to use for the interpolation in meters. We also specify which columns we want to be interpolated.
If the window width is not wide enough to capture data on either side, it will be doubled twice to try and capture enough data. If it still too narrow to capture data on either side, the intersection point will either be dropped, or if extrapolate is set to true, the values will be filled with extrapolation, instead of interpolation. This extrapolation is also necessary if the intersections lie beyond the end of a line, which occurs if you used the buffer_dist argument for
create_intersection_table.
- : data
x : intersection
[ ]: windows
- - - - - - - x - - - - - -
[ ] # first window
[ ] # doubled once
[ ] # doubled twice
[9]:
data_df, inters = airbornegeo.interpolate_intersections(
data_df,
inters,
to_interp=["mag", "height"],
window_width=500,
method="cubic",
extrapolate=False,
)
[10]:
inters.head()
[10]:
| line | tie | geometry | max_dist | easting | northing | dist_along_flight_line | dist_along_flight_tie | flight_interpolation_type | tie_interpolation_type | flight_height | tie_height | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 143 | POINT (1158153 254083) | 16.441255 | 1158153.0 | 254083.0 | 545768.072695 | 138071.419338 | interpolated | interpolated | 4168.038983 | 4008.397691 |
| 1 | 1 | 144 | POINT (1190820 259865) | 24.124887 | 1190820.0 | 259865.0 | 578952.394781 | 131585.125284 | interpolated | interpolated | 4174.500813 | 4010.840823 |
| 2 | 1 | 145 | POINT (1223524 265689) | 17.269650 | 1223524.0 | 265689.0 | 612181.972720 | 147253.496664 | interpolated | interpolated | 3544.149925 | 3995.961216 |
| 3 | 1 | 146 | POINT (1256193 271497) | 31.608179 | 1256193.0 | 271497.0 | 645372.035087 | 136211.666619 | interpolated | interpolated | 3564.579994 | 3578.174277 |
| 4 | 1 | 147 | POINT (1288901 277249) | 50.174377 | 1288901.0 | 277249.0 | 678598.170740 | 155115.224990 | interpolated | interpolated | 3536.160719 | 3545.947314 |
[11]:
data_df[data_df.is_intersection].head()
[11]:
| easting | northing | height | line | unixtime | distance_along_line | mag | tie | geometry | is_intersection | intersecting_line | interpolation_type | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 7455 | 637640.0 | 161826.0 | 4122.332685 | 1 | NaN | 16811.103180 | -53.846042 | NaN | POINT (637640 161826) | True | 150.0 | interpolated |
| 7456 | 670007.0 | 167673.0 | 4132.634362 | 1 | NaN | 49821.820318 | -80.387990 | NaN | POINT (670007 167673) | True | 151.0 | interpolated |
| 7457 | 702402.0 | 173414.0 | 4156.031337 | 1 | NaN | 82726.336899 | -44.550155 | NaN | POINT (702402 173414) | True | 152.0 | interpolated |
| 7458 | 702430.0 | 173419.0 | 4156.517464 | 1 | NaN | 82767.019948 | -44.908585 | NaN | POINT (702430 173419) | True | 153.0 | interpolated |
| 7459 | 734809.0 | 179103.0 | 4121.060700 | 1 | NaN | 115638.011785 | -120.195968 | NaN | POINT (734809 179103) | True | 154.0 | interpolated |
[12]:
# see which lines dont have intersections
airbornegeo.lines_without_intersections(data_df, inters)
[12]:
[np.int64(107),
np.int64(109),
np.int64(129),
np.int64(131),
np.int64(188),
np.int64(189),
np.int64(190),
np.int64(192),
np.int64(193),
np.int64(194),
np.int64(203)]
3.4. Inspect the intersections#
The below two cells allow you to look at a line in profile view and see it’s intersections. We pass the column ‘mag’ to be plotted on the y axis, and distance along line on the x axis. The small dots, which form lines since they are close together, show the magnetic data of the line. The diamonds show the intersection points. The diamonds are plotted with the y axis values of the intersecting line. If the diamond if vertically offset from the points, that means the intersecting line’s magnetic value at the intersection is quite different. This shows the cross-over errors. For example, in the below plot, the lines 85 and 77 have quite large cross-over erros with the plotted line, 161.
[13]:
# # if you want to individually inspect each line and its intersections
# airbornegeo.inspect_intersections(
# data_df,
# plot_variable=["mag"],
# # plot_all=True,
# )
[14]:
# if you want to just look at 1 line
airbornegeo.plot_line_and_crosses(
data_df,
line=161,
x="distance_along_line",
y=["mag"],
y_axes=[1],
plot_inters=True,
)
3.5. Calculate intersection cross-over errors#
Now we have interpolated magnetic values for each intersecting line at the intersection points, we can calculate the cross-over errors for each intersection
[15]:
inters = airbornegeo.calculate_crossover_errors(
data_df,
inters,
data_col="mag",
plot_map=True,
)
[16]:
inters.head()
[16]:
| line | tie | geometry | max_dist | easting | northing | dist_along_flight_line | dist_along_flight_tie | flight_interpolation_type | tie_interpolation_type | flight_height | tie_height | mistie_0 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 143 | POINT (1158153 254083) | 16.441255 | 1158153.0 | 254083.0 | 545768.072695 | 138071.419338 | interpolated | interpolated | 4168.038983 | 4008.397691 | 100.458661 |
| 1 | 1 | 144 | POINT (1190820 259865) | 24.124887 | 1190820.0 | 259865.0 | 578952.394781 | 131585.125284 | interpolated | interpolated | 4174.500813 | 4010.840823 | 32.151483 |
| 2 | 1 | 145 | POINT (1223524 265689) | 17.269650 | 1223524.0 | 265689.0 | 612181.972720 | 147253.496664 | interpolated | interpolated | 3544.149925 | 3995.961216 | 72.936553 |
| 3 | 1 | 146 | POINT (1256193 271497) | 31.608179 | 1256193.0 | 271497.0 | 645372.035087 | 136211.666619 | interpolated | interpolated | 3564.579994 | 3578.174277 | 84.125118 |
| 4 | 1 | 147 | POINT (1288901 277249) | 50.174377 | 1288901.0 | 277249.0 | 678598.170740 | 155115.224990 | interpolated | interpolated | 3536.160719 | 3545.947314 | -7.731396 |