Beispiel #1
0
def calculate_orientation(gdf: gpd.geodataframe.GeoDataFrame) -> gpd.geodataframe.GeoDataFrame:
    """
    Calculating the orientations from linestrings
    Args:
        gdf: GeoDataFrame containing the orientation LineStrings
    Return:
        gdf: GeoDataFrame containing the orientation values
    """
    gdf = calculate_orientations_new(gdf)
    gdf['length'] = gdf.geometry.length
    gdf['dip'] = np.rad2deg(np.arctan(gdf['dZ'] / gdf['length']))
    gdf = vector.extract_xy(gdf, reset_index=False)

    x = []
    y = []

    formation = []

    dip = []
    azimuth = []
    for i in range(0, len(gdf), 2):
        x.append(np.abs(gdf.iloc[i + 1]['X'] + gdf.iloc[i]['X']) / 2)
        y.append(np.abs(gdf.iloc[i + 1]['Y'] + gdf.iloc[i]['Y']) / 2)
        formation.append(gdf.iloc[i]['formation'])
        dip.append(gdf.iloc[i]['dip'])
        azimuth.append(gdf.iloc[i]['azimuth'])

    df = pd.DataFrame(data=[x, y, formation, dip, azimuth]).transpose()
    df.columns = ['X', 'Y', 'formation', 'dip', 'azimuth']

    gdf = gpd.GeoDataFrame(df, geometry=gpd.points_from_xy(df.X, df.Y), crs='EPSG:4647')
    gdf['polarity'] = 1

    return gdf
Beispiel #2
0
def test_sample_from_rasterio2(gdf, dem):
    from gemgis.raster import sample_from_rasterio
    from gemgis.vector import extract_xy

    extent = [0, 972.0, 0, 1069.0]

    gdf = extract_xy(gdf)
Beispiel #3
0
def test_sample_from_rasterio2(gdf, dem):
    from gemgis.raster import sample_from_rasterio
    from gemgis.vector import extract_xy

    gdf = extract_xy(gdf)
    point_x = gdf['X'].tolist()[0]
    point_y = gdf['Y'].tolist()[0]

    samples = sample_from_rasterio(dem, point_x, point_y)

    assert isinstance(samples, float)
    assert samples == 364.994873046875
Beispiel #4
0
def to_section_dict(gdf: gpd.geodataframe.GeoDataFrame, section_column: str = 'section_name',
                    resolution=None) -> dict:
    """
    Converting custom sections stored in shape files to GemPy section_dicts
    Args:
        gdf - gpd.geodataframe.GeoDataFrame containing the points or lines of custom sections
        section_column - string containing the name of the column containing the section names
        resolution - list containing the x,y resolution of the custom section
    Return:
         section_dict containing the section names, coordinates and resolution
    """

    if resolution is None:
        resolution = [100, 80]

    # Checking if gdf is of type GeoDataFrame
    if not isinstance(gdf, gpd.geodataframe.GeoDataFrame):
        raise TypeError('gdf must be of type GeoDataFrame')

    # Checking if the section_column is of type string
    if not isinstance(section_column, str):
        raise TypeError('Name for section_column must be of type string')

    # Checking if resolution is of type list
    if not isinstance(resolution, list):
        raise TypeError('resolution must be of type list')

    # Checking if X and Y values are in column
    if not {'X', 'Y'}.issubset(gdf.columns):
        gdf = vector.extract_xy(gdf)

    if len(resolution) != 2:
        raise ValueError('resolution list must be of length two')

    # Extracting Section names
    section_names = gdf[section_column].unique()

    # Create section dicts for Point Shape Files
    if all(gdf.geom_type == "Point"):
        section_dict = {i: ([gdf[gdf[section_column] == i].X.iloc[0], gdf[gdf[section_column] == i].Y.iloc[0]],
                            [gdf[gdf[section_column] == i].X.iloc[1], gdf[gdf[section_column] == i].Y.iloc[1]],
                            resolution) for i in section_names}

    # Create section dicts for Line Shape Files
    else:
        section_dict = {i: ([gdf[gdf[section_column] == i].X.iloc[0], gdf[gdf[section_column] == i].Y.iloc[0]],
                            [gdf[gdf[section_column] == i].X.iloc[1], gdf[gdf[section_column] == i].Y.iloc[1]],
                            resolution) for i in section_names}

    return section_dict
Beispiel #5
0
def plot_contours_3d(contours: gpd.geodataframe.GeoDataFrame,
                     plotter: pv.Plotter,
                     color: str = 'red',
                     add_to_z: Union[int, float] = 0):
    """
           Plotting the dem in 3D with pv
           Args:
               contours: GeoDataFrame containing the contour information
               plotter: name of the PyVista plotter
               color: string for the color of the contour lines
               add_to_z: int of float value to add to the height of points
       """
    if not isinstance(contours, gpd.geodataframe.GeoDataFrame):
        raise TypeError('Line Object must be of type GeoDataFrame')

    # Checking if the plotter is of type pv plotter
    if not isinstance(plotter, pv.Plotter):
        raise TypeError('Plotter must be of type pv.Plotter')

    # Checking if the color is of type string
    if not isinstance(color, str):
        raise TypeError('Color must be of type string')

    # Checking if additional Z value is of type int or float
    if not isinstance(add_to_z, (int, float)):
        raise TypeError('Add_to_z must be of type int or float')

    # Checking if Z values are in gdf
    if not {'Z'}.issubset(contours.columns):
        raise ValueError('Z-values not defined')

    # If XY coordinates not in gdf, extract X,Y values
    if not {'X', 'Y'}.issubset(contours.columns):
        contours = extract_xy(contours, reset_index=False)

    # Create list of points and plot them
    try:
        for j in contours.index.unique():
            point_list = [[
                contours.loc[j].iloc[i].X, contours.loc[j].iloc[i].Y,
                contours.loc[j].iloc[i].Z + add_to_z
            ] for i in range(len(contours.loc[j]))]
            vertices = np.array(point_list)
            plotter.add_lines(vertices, color=color)
    except AttributeError:
        raise AttributeError('X and Y coordinates of countours are missing')
Beispiel #6
0
def test_sample_from_rasterio(gdf, dem):
    from gemgis.raster import sample_from_rasterio
    from gemgis.vector import extract_xy

    gdf = extract_xy(gdf)
    point_x = gdf['X'].tolist()[:5]
    point_y = gdf['Y'].tolist()[:5]

    samples = sample_from_rasterio(dem, point_x, point_y)

    assert isinstance(samples, list)
    assert len(samples) == 5
    assert isinstance(samples[0], float)
    assert samples[0] == 364.994873046875
    assert samples[1] == 400.3435974121094
    assert samples[2] == 459.54931640625
    assert samples[3] == 525.6910400390625
    assert samples[4] == 597.6325073242188
Beispiel #7
0
def test_sample_from_array(gdf, dem):
    from gemgis.raster import sample_from_array
    from gemgis.vector import extract_xy

    extent = [0, 972.0, 0, 1069.0]

    gdf = extract_xy(gdf)
    point_x = gdf['X'].tolist()[:5]
    point_y = gdf['Y'].tolist()[:5]

    samples = sample_from_array(dem.read(1), extent, point_x, point_y)

    assert isinstance(samples, np.ndarray)
    assert len(samples) == 5
    assert isinstance(samples[0], np.float32)
    assert samples[0] == np.float32(366.61255)
    assert samples[1] == np.float32(402.09912)
    assert samples[2] == np.float32(460.6181)
    assert samples[3] == np.float32(529.0156)
    assert samples[4] == np.float32(597.6325)
Beispiel #8
0
def interpolate_strike_lines(gdf, increment):
    """

    Args:
        gdf:
        increment:

    Returns:

    """
    gdf_out = gpd.GeoDataFrame()
    gdf = vector.extract_xy(gdf).sort_values(by='id')
    for i in range(len(gdf['id'].unique().tolist()) - 1):

        diff = gdf.loc[gdf.index.unique().values.tolist()[i]]['Z'].values.tolist()[0] - \
               gdf.loc[gdf.index.unique().values.tolist()[i + 1]]['Z'].values.tolist()[0]

        if np.abs(diff) > increment:
            gdf_strike = pd.concat([
                gdf.loc[gdf.index.unique().values.tolist()[i]],
                gdf.loc[gdf.index.unique().values.tolist()[i + 1]]
            ])
            lines = calculate_lines(gdf_strike, increment)

            gdf_new = pd.concat([
                gdf.loc[gdf.index.unique().values.tolist()[i]], lines,
                gdf.loc[gdf.index.unique().values.tolist()[i + 1]]
            ])
            gdf_out = gdf_out.append(gdf_new, ignore_index=True)
        else:
            gdf_new = pd.concat([
                gdf.loc[gdf.index.unique().values.tolist()[i]],
                gdf.loc[gdf.index.unique().values.tolist()[i + 1]]
            ])
            gdf_out = gdf_out.append(gdf_new, ignore_index=True)

    gdf_out = gdf_out.sort_values(by=['Y']).drop_duplicates('geometry')
    gdf_out['id'] = np.arange(1,
                              len(gdf_out['id'].values.tolist()) + 1).tolist()

    return gdf_out
Beispiel #9
0
def calculate_lines(gdf, increment):
    """

    Args:
        gdf:
        increment:

    Returns:

    """
    num = calculate_number_of_isopoints(gdf, increment)

    gdf = gdf.sort_values(by=['Z', 'X'])
    minval = min(gdf.sort_values(by='Z')['Z'].unique().tolist())
    maxval = max(gdf.sort_values(by='Z')['Z'].unique().tolist())

    pointsx = []
    pointsy = []
    for i in range(len(gdf[gdf['Z'] == minval])):
        index = get_nearest_neighbor(
            np.array(gdf[gdf['Z'] == minval][['X', 'Y']].values.tolist()),
            np.array([
                gdf[gdf['Z'] == minval]['X'].values.tolist()[i],
                gdf[gdf['Z'] == minval]['Y'].values.tolist()[i]
            ]))

        x1 = gdf[gdf['Z'] == minval]['X'].tolist()[i]
        y1 = gdf[gdf['Z'] == minval]['Y'].tolist()[i]
        x2 = gdf[gdf['Z'] == maxval]['X'].tolist()[index]
        y2 = gdf[gdf['Z'] == maxval]['Y'].tolist()[index]

        for j in range(num):
            pointx = ((j + 1) / (num + 1) * x2 + (1 - (j + 1) /
                                                  (num + 1)) * x1)
            pointy = ((j + 1) / (num + 1) * y2 + (1 - (j + 1) /
                                                  (num + 1)) * y1)

            pointsx.append(pointx)
            pointsy.append(pointy)

    ls_list = []
    heights = []
    for i in range(0, int(len(pointsx) / 2)):
        ls = LineString([
            Point(pointsx[i], pointsy[i]),
            Point(pointsx[i + num], pointsy[i + num])
        ])
        ls_list.append(ls)
        heights.append(minval + i * increment + increment)
        heights.append(minval + i * increment + increment)

    lines = gpd.GeoDataFrame(gpd.GeoSeries(ls_list))

    lines['geometry'] = ls_list

    lines = vector.extract_xy(lines)
    del lines[0]

    lines['formation'] = gdf['formation'].unique().tolist()[0]
    lines['Z'] = heights
    lines['id'] = heights
    return lines
Beispiel #10
0
def calculate_orientations(gdf: gpd.geodataframe.GeoDataFrame) -> pd.DataFrame:
    """
    Calculating orientation values from strike lines based on eigenvector analysis
    Args:
        gdf: GeoDataFrame containing the intersections of layer boundaries with topographic contour lines
    Return:
        orientations: DataFrame containing the extracted orientation values and a midpoint location of the strike lines
    """

    # Checking if gdf is of type GeoDataFrame
    if not isinstance(gdf, gpd.geodataframe.GeoDataFrame):
        raise TypeError('gdf must be of type GeoDataFrame')

    # Checking if X and Y values are in column
    if np.logical_not(pd.Series(['formation', 'Z']).isin(gdf.columns).all()):
        raise ValueError('formation or Z column missing in GeoDataFrame')

    if any(gdf['id'].apply(lambda x: x == None)):
        raise ValueError('IDs must not be None')

    # Extract XY coordinates
    gdf_new = vector.extract_xy(gdf, inplace=False)

    # Create empty lists
    orientations = []
    xlist = []
    ylist = []
    zlist = []

    if len(gdf_new['id'].unique()) == 2:
        # Get values for height
        gdf_new_array = gdf_new[['X', 'Y', 'Z']].values.tolist()
        points = gdf_new_array

        # Calculates eigenvector of points
        C = np.cov(gdf_new_array, rowvar=False)
        normal_vector = np.linalg.eigh(C)[1][:, 0]
        x, y, z = normal_vector

        # Convert vector to dip and azimuth
        sign_z = 1 if z > 0 else -1
        dip = np.degrees(np.arctan2(np.sqrt(x * x + y * y), abs(z)))
        azimuth = (np.degrees(np.arctan2(sign_z * x, sign_z * y)) % 360)
        orient = [dip, azimuth]

        # Append values to list
        orientations.append(orient)
        xlist.append(
            sum([points[i][0] for i in range(len(points))]) / len(points))
        ylist.append(
            sum([points[i][1] for i in range(len(points))]) / len(points))
        zlist.append(
            sum([points[i][2] for i in range(len(points))]) / len(points))

    else:
        # Extract orientations
        for i in range(len(gdf_new['id'].unique()) - 1):
            # Get values for the first and second height
            gdf_new1 = gdf_new[gdf_new['id'] == i + 1 +
                               (gdf_new['id'].unique()[0] - 1)]
            gdf_new2 = gdf_new[gdf_new['id'] == i + 2 +
                               (gdf_new['id'].unique()[0] - 1)]

            # Convert coordinates to lists
            gdf_new1_array = gdf_new1[['X', 'Y', 'Z']].values.tolist()
            gdf_new2_array = gdf_new2[['X', 'Y', 'Z']].values.tolist()

            # Merge lists of points
            points = gdf_new1_array + gdf_new2_array

            # Calculates eigenvector of points
            C = np.cov(points, rowvar=False)
            normal_vector = np.linalg.eigh(C)[1][:, 0]
            x, y, z = normal_vector

            # Convert vector to dip and azimuth
            sign_z = 1 if z > 0 else -1
            dip = np.degrees(np.arctan2(np.sqrt(x * x + y * y), abs(z)))
            azimuth = (np.degrees(np.arctan2(sign_z * x, sign_z * y)) % 360)
            orient = [dip, azimuth]

            # Append values to list
            orientations.append(orient)
            xlist.append(
                sum([points[i][0] for i in range(len(points))]) / len(points))
            ylist.append(
                sum([points[i][1] for i in range(len(points))]) / len(points))
            zlist.append(
                sum([points[i][2] for i in range(len(points))]) / len(points))

    # Create DataFrame
    orientations = pd.DataFrame(data=[
        xlist, ylist, zlist, [i[0] for i in orientations],
        [i[1] for i in orientations]
    ]).transpose()
    # Rename columns
    orientations.columns = ['X', 'Y', 'Z', 'dip', 'azimuth']
    # Add polarity column
    orientations['polarity'] = 1
    # Add formation name
    orientations['formation'] = gdf['formation'].unique()[0]

    return orientations
Beispiel #11
0
def interpolate_strike_lines(gdf: gpd.geodataframe.GeoDataFrame, increment: Union[float, int], **kwargs) \
        -> gpd.geodataframe.GeoDataFrame:
    """
    Interpolating strike lines to calculate orientations
    Args:
        gdf: GeoDataFrame containing existing strike lines
        increment: increment between the strike lines
    Kwargs:
        xcol: str/name of X column
        ycol: str/name of X column
        zcol: str/name of Z column
    Returns:
        gdf_out: GeoDataFrame containing the existing and interpolated strike lines
    """

    # Checking if gdf is of type GeoDataFrame
    if not isinstance(gdf, gpd.geodataframe.GeoDataFrame):
        raise TypeError('gdf must be of type GeoDataFrame')

    # Checking if the increment is of type float or int
    if not isinstance(increment, (float, int)):
        raise TypeError('The increment must be provided as float or int')

    # Getting the name of the Z column
    xcol = kwargs.get('xcol', 'X')

    # Getting the name of the Y column
    ycol = kwargs.get('zcol', 'Y')

    # Getting the name of the Z column
    zcol = kwargs.get('zcol', 'Z')

    # Create empty GeoDataFrame
    gdf_out = gpd.GeoDataFrame()

    # Extract vertices from gdf
    gdf = vector.extract_xy(gdf, drop_id=False, reset_index=False).sort_values(by='id')

    # Interpolate strike lines
    for i in range(len(gdf['id'].unique().tolist()) - 1):

        # Calculate distance between two strike lines in the original gdf
        diff = gdf.loc[gdf.index.unique().values.tolist()[i]][zcol].values.tolist()[0] - \
               gdf.loc[gdf.index.unique().values.tolist()[i + 1]][zcol].values.tolist()[0]

        # If the distance is larger than the increment, interpolate strike lines
        if np.abs(diff) > increment:
            gdf_strike = pd.concat(
                [gdf.loc[gdf.index.unique().values.tolist()[i]], gdf.loc[gdf.index.unique().values.tolist()[i + 1]]])

            # Calculate strike lines
            lines = calculate_lines(gdf_strike, increment)

            # Append interpolated lines to gdf that will be returned
            gdf_new = pd.concat(
                [gdf.loc[gdf.index.unique().values.tolist()[i]], lines,
                 gdf.loc[gdf.index.unique().values.tolist()[i + 1]]])
            gdf_out = gdf_out.append(gdf_new, ignore_index=True)

        # If the distance is equal to the increment, append line to the gdf that will be returned
        else:
            gdf_new = pd.concat(
                [gdf.loc[gdf.index.unique().values.tolist()[i]], gdf.loc[gdf.index.unique().values.tolist()[i + 1]]])
            gdf_out = gdf_out.append(gdf_new, ignore_index=True)

    # Drop duplicates
    gdf_out = gdf_out.sort_values(by=['Y']).drop_duplicates('geometry')

    # Redefine ID column with interpolated strike lines
    gdf_out['id'] = np.arange(1, len(gdf_out['id'].values.tolist()) + 1).tolist()

    return gdf_out
Beispiel #12
0
def calculate_lines(gdf: Union[gpd.geodataframe.GeoDataFrame, pd.DataFrame], increment: Union[float, int], **kwargs):
    """
    Function to interpolate strike lines
    Args:
        gdf: GeoDataFrame/DataFrame containing existing strike lines
        increment: increment between the strike lines
    Kwargs:
        xcol: str/name of X column
        ycol: str/name of X column
        zcol: str/name of Z column
    Returns:
        lines: GeoDataFrame with interpolated strike lines
    """

    # Checking if gdf is of type GeoDataFrame
    if not isinstance(gdf, (gpd.geodataframe.GeoDataFrame, pd.DataFrame)):
        raise TypeError('gdf must be of type GeoDataFrame')

    # Checking that all geometries are valid
    if not all(gdf.geometry.is_valid):
        raise ValueError('Not all Shapely Objects are valid objects')

    # Checking if the increment is of type float or int
    if not isinstance(increment, (float, int)):
        raise TypeError('The increment must be provided as float or int')

    # Getting the name of the Z column
    xcol = kwargs.get('xcol', 'X')

    # Getting the name of the Y column
    ycol = kwargs.get('zcol', 'Y')

    # Getting the name of the Z column
    zcol = kwargs.get('zcol', 'Z')

    # Checking that the Z column is in the GeoDataFrame
    if not pd.Series([xcol, zcol]).isin(gdf.columns).all():
        raise ValueError('Provide names of X,Z columns as kwarg as X,Z columns could not be recognized')

    # Calculating number of isopoints
    num = calculate_number_of_isopoints(gdf, increment, zcol=zcol)

    # Sorting values
    gdf = gdf.sort_values(by=[zcol, xcol])

    # Getting lists of min and max values
    minval = min(gdf.sort_values(by=zcol)[zcol].unique().tolist())
    maxval = max(gdf.sort_values(by=zcol)[zcol].unique().tolist())

    # Creating empty list for x and y values
    pointsx = []
    pointsy = []

    # Calculating vertices of lines
    for i in range(len(gdf[gdf[zcol] == minval])):
        # Getting index for nearest neighbor
        index = get_nearest_neighbor(np.array(gdf[gdf[zcol] == minval][[xcol, ycol]].values.tolist()),
                                     np.array([gdf[gdf[zcol] == minval][xcol].values.tolist()[i],
                                               gdf[gdf[zcol] == minval][ycol].values.tolist()[i]]))

        # Creating x and y points from existing gdf
        x1 = gdf[gdf['Z'] == minval][xcol].tolist()[i]
        y1 = gdf[gdf['Z'] == minval][ycol].tolist()[i]
        x2 = gdf[gdf['Z'] == maxval][xcol].tolist()[index]
        y2 = gdf[gdf['Z'] == maxval][ycol].tolist()[index]

        # Calculating vertices of lines
        for j in range(num):
            # Calculating vertices
            pointx = ((j + 1) / (num + 1) * x2 + (1 - (j + 1) / (num + 1)) * x1)
            pointy = ((j + 1) / (num + 1) * y2 + (1 - (j + 1) / (num + 1)) * y1)

            # Append vertices to list
            pointsx.append(pointx)
            pointsy.append(pointy)

    # Create empty lists
    ls_list = []
    heights = []

    # Create linestring from point lists
    for i in range(0, int(len(pointsx) / 2)):
        # Creating linestrings
        ls = LineString([Point(pointsx[i], pointsy[i]),
                         Point(pointsx[i + num], pointsy[i + num])])
        # Appending line strings
        ls_list.append(ls)
        heights.append(minval + i * increment + increment)
        heights.append(minval + i * increment + increment)

    # Creating GeoDataFrame
    lines = gpd.GeoDataFrame(gpd.GeoSeries(ls_list), crs=gdf.crs)

    # Setting geometry column of GeoDataFrame
    lines['geometry'] = ls_list

    # Extracting X and Y coordinate and deleting first entry
    lines = vector.extract_xy(lines)
    del lines[0]

    # Adding formation and height information to GeoDataFrame
    lines['formation'] = gdf['formation'].unique().tolist()[0]
    lines['Z'] = heights
    lines['id'] = heights

    return lines