Layer Subaccessor#
In geotech-pandas, a layer reperesents a soil or rock layer of a point. These layers are usually
implied as the elements or rows inside a DataFrame.
In this guide, the basics of the layer subaccessor methods are
presented. The layer subaccessor is a collection of depth-related
calculations for each point in the DataFrame.
First, we import the necessary libraries,
In [1]: import pandas as pd
In [2]: import geotech_pandas
Next, we create a simple DataFrame with point_id and bottom
columns present. An additional soil_type column is also added to show how this column is
transformed when Splitting layers.
In [3]: df = pd.DataFrame(
...: {
...: "point_id": ["BH-1", "BH-1", "BH-1"],
...: "bottom": [1.0, 2.0, 3.0],
...: "soil_type": ["sand", "clay", "sand"],
...: }
...: )
...:
In [4]: df
Out[4]:
point_id bottom soil_type
0 BH-1 1.0 sand
1 BH-1 2.0 clay
2 BH-1 3.0 sand
Getting layer top depth data#
One of the methods under layer is the ability to get the top
depths of each layer based on their bottom depths. The
get_top() method returns a Series
that represents the top depths based on the bottom depths of each layer.
In [5]: df.geotech.layer.get_top()
Out[5]:
0 0.0
1 1.0
2 2.0
Name: top, dtype: float64
Assign the results of get_top() to a column in the
DataFrame to store the results. It is recommended to assign the results in
a column with the same name as the Series name returned by the
get_top() method.
In [6]: df["top"] = df.geotech.layer.get_top()
In [7]: df
Out[7]:
point_id bottom soil_type top
0 BH-1 1.0 sand 0.0
1 BH-1 2.0 clay 1.0
2 BH-1 3.0 sand 2.0
To avoid manually setting the column name, we can utilize the concat() method
since this method sets the Series name as the column name when
concatenating a DataFrame with a Series.
To demonstrate this, we must delete the column we created earlier first,
In [8]: del df["top"]
In [9]: df
Out[9]:
point_id bottom soil_type
0 BH-1 1.0 sand
1 BH-1 2.0 clay
2 BH-1 3.0 sand
Then proceed with the following command to concatenate df with the results of
get_top(),
In [10]: df = pd.concat((df, df.geotech.layer.get_top()), axis=1)
In [11]: df
Out[11]:
point_id bottom soil_type top
0 BH-1 1.0 sand 0.0
1 BH-1 2.0 clay 1.0
2 BH-1 3.0 sand 2.0
As you can see, it results to the same DataFrame as before.
It is recommended to use the concat() method since geotech-pandas relies
heavily in consistent column names. For more information, see General Columns.
If you want the output to be much cleaner, you can always override the arrangement of columns like so,
In [12]: df = df[["point_id", "top", "bottom", "soil_type"]]
In [13]: df
Out[13]:
point_id top bottom soil_type
0 BH-1 0.0 1.0 sand
1 BH-1 1.0 2.0 clay
2 BH-1 2.0 3.0 sand
Getting layer center data#
The get_center() method returns the center depth of each layer
based on the average of the top and bottom columns.
In [14]: df.geotech.layer.get_center()
Out[14]:
0 0.5
1 1.5
2 2.5
Name: center, dtype: float64
Similar to before, we can store the results using concat(),
In [15]: df = pd.concat((df, df.geotech.layer.get_center()), axis=1)
In [16]: df
Out[16]:
point_id top bottom soil_type center
0 BH-1 0.0 1.0 sand 0.5
1 BH-1 1.0 2.0 clay 1.5
2 BH-1 2.0 3.0 sand 2.5
Moving soil_type to the end,
In [17]: col = df.pop("soil_type")
In [18]: df.insert(len(df.columns), col.name, col)
In [19]: df
Out[19]:
point_id top bottom center soil_type
0 BH-1 0.0 1.0 0.5 sand
1 BH-1 1.0 2.0 1.5 clay
2 BH-1 2.0 3.0 2.5 sand
Getting layer thickness data#
The get_thickness() method returns the thickness of each layer
in terms of depth of each layer by getting the absolute difference between the top and
bottom columns.
In [20]: df.geotech.layer.get_thickness()
Out[20]:
0 1.0
1 1.0
2 1.0
Name: thickness, dtype: float64
Similar to before, we can store the results using concat(),
In [21]: df = pd.concat((df, df.geotech.layer.get_thickness()), axis=1)
In [22]: df
Out[22]:
point_id top bottom center soil_type thickness
0 BH-1 0.0 1.0 0.5 sand 1.0
1 BH-1 1.0 2.0 1.5 clay 1.0
2 BH-1 2.0 3.0 2.5 sand 1.0
Since we already stored soil_type in col earlier and no changes occurred to soil_type
since then, we can simply delete soil_type from df and re-insert col at the end of
df like so,
In [23]: del df[col.name]
In [24]: df.insert(len(df.columns), col.name, col)
In [25]: df
Out[25]:
point_id top bottom center thickness soil_type
0 BH-1 0.0 1.0 0.5 1.0 sand
1 BH-1 1.0 2.0 1.5 1.0 clay
2 BH-1 2.0 3.0 2.5 1.0 sand
Splitting layers#
The split_at() method returns a
DataFrame where each layer is split into two if the provided depth is
found within its top and bottom depths.
For example, if wish to split BH-1 at 1.5 m, we call
split_at() with the depth argument as 1.5 like so,
In [26]: df = df.geotech.layer.split_at(depth=1.5)
In [27]: df
Out[27]:
point_id top bottom center thickness soil_type
0 BH-1 0.0 1.0 0.5 1.0 sand
1 BH-1 1.0 1.5 1.5 1.0 clay
2 BH-1 1.5 2.0 1.5 1.0 clay
3 BH-1 2.0 3.0 2.5 1.0 sand
As you can see, the DataFrame has been split and the top and
bottom columns have been updated correctly. However, the other depth-related data remain the
same when they should also be different. At the moment, this is the limitation of
split_at() as it only updates the top and bottom
columns. There are workarounds to this issue though. You can either reassign the other depth-related
columns or split the DataFrame first before performing depth-related
calculations.
Fortunately, pandas offers the update() method for
DataFrame objects. As such, we can update and correct the
DataFrame using the following commands,
In [28]: df.update(df.geotech.layer.get_center())
In [29]: df.update(df.geotech.layer.get_thickness())
In [30]: df
Out[30]:
point_id top bottom center thickness soil_type
0 BH-1 0.0 1.0 0.50 1.0 sand
1 BH-1 1.0 1.5 1.25 0.5 clay
2 BH-1 1.5 2.0 1.75 0.5 clay
3 BH-1 2.0 3.0 2.50 1.0 sand