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