Source code for pyvibracore.results.impact_force_result

from __future__ import annotations

import json
from dataclasses import dataclass
from typing import Any, Sequence, Tuple

import geopandas as gpd
import matplotlib.pyplot as plt
import pandas as pd
from mpl_toolkits.axes_grid1.anchored_artists import AnchoredSizeBar


[docs]@dataclass(frozen=True) class MultiCalculationData: """ Dataclass that holds the information from `/impact-force/multi` Attributes ----------- gdf: gpd.GeoDataFrame """ gdf: gpd.GeoDataFrame
[docs] @classmethod def from_api_response(cls, response_dict: dict) -> "MultiCalculationData": """ Stores the response of the VibraCore endpoint Parameters ---------- response_dict: The resulting response of a call to `/impact-force/multi` """ return cls( gdf=gpd.read_file(json.dumps(response_dict), driver="GeoJSON"), )
[docs] def plot( self, figsize: Tuple[float, float] = (10.0, 12.0), settings: dict | None = None, **kwargs: Any, ) -> plt.Figure: """ Plots the CPT and soil table data. Parameters ---------- figsize: Size of the activate figure, as the `plt.figure()` argument. settings: Plot settings used in plot: default settings are: .. code-block:: python { "hue": "max", "title": "Maximale slagkracht [kN]", "xlabel": "X-coördinaat", "ylabel": "Y-coördinaat" } **kwargs: All additional keyword arguments are passed to the `pyplot.subplots()` call. Returns ------- fig: The matplotlib Figure """ kwargs_settings = { "hue": "max", "title": "Maximale slagkracht [kN]", "xlabel": "X-coördinaat", "ylabel": "Y-coördinaat", } if settings: kwargs_settings.update(settings) if kwargs_settings["hue"] not in ["max", "base", "Q90", "Q95"]: raise ValueError( f"The value {kwargs_settings['hue']} is not in [max, base, Q90, Q95]" ) kwargs_subplot = { "figsize": figsize, "tight_layout": True, } kwargs_subplot.update(kwargs) fig, axes = plt.subplots(**kwargs_subplot) # Create figure self.gdf.plot( kwargs_settings.get("hue", "max"), ax=axes, legend=True, figsize=(15, 10), legend_kwds={"orientation": "vertical"}, cmap="RdYlGn_r", # 'jet', markersize=150, marker="v", aspect=1, ) # add CPT name to plot for idx, row in self.gdf.iterrows(): axes.annotate( row["id"], xy=(row["x"], row["y"]), horizontalalignment="center", fontsize=20, xytext=(row["x"], row["y"] + 3), ) # Set label and title for figure axes.set_xlabel(xlabel=kwargs_settings.get("xlabel", ""), size=15) axes.set_ylabel(ylabel=kwargs_settings.get("ylabel", ""), size=15) axes.set_title(label=kwargs_settings.get("title", ""), size=25) # Add north arrow x, y, arrow_length = 0.95, 0.98, 0.1 axes.annotate( "N", xy=(x, y), xytext=(x, y - arrow_length), arrowprops=dict(facecolor="black", width=5, headwidth=15), ha="center", va="center", fontsize=20, xycoords=axes.transAxes, ) # scale bar scalebar = AnchoredSizeBar( axes.transData, 20, "20 m", "lower left", pad=1, color="black", frameon=True, size_vertical=2, ) axes.add_artist(scalebar) return fig
@dataclass(frozen=True) class ImpactForceTable: """ Object that contains the impact force related data-traces. Attributes: ------------ betaFrictionalResistance: Sequence[float] beta frictional resistance [kN] betaPointResistance: Sequence[float] beta point resistance [kN] correctedConeResistance: Sequence[float] corrected cone resistance [Mpa] depthOffset: Sequence[float] CPT depth [m w.r.t. Reference] frictionalResistance: Sequence[float] frictional resistance [kN] pointResistance: Sequence[float] point resistance [kN] sheetResistance: Sequence[float] sheet resistance [kN] slotResistance: Sequence[float] slot resistance [kN] totalResistance: Sequence[float] total resistance [kN] """ betaFrictionalResistance: Sequence[float] | None betaPointResistance: Sequence[float] | None correctedConeResistance: Sequence[float] | None depthOffset: Sequence[float] | None frictionalResistance: Sequence[float] | None pointResistance: Sequence[float] | None sheetResistance: Sequence[float] | None slotResistance: Sequence[float] | None totalResistance: Sequence[float] | None def __post_init__(self) -> None: raw_lengths = [] for values in self.__dict__.values(): if values: raw_lengths.append(len(values)) if len(list(set(raw_lengths))) > 1: raise ValueError("All values in this dataclass must have the same length.") @classmethod def from_api_response(cls, response_dict: dict) -> "ImpactForceTable": """ Stores the response of the VibraCore endpoint Parameters ---------- response_dict: The resulting response of a call to `impact-force/calculation/single` """ return cls( betaFrictionalResistance=response_dict.get("betaFrictionalResistance"), betaPointResistance=response_dict.get("betaPointResistance"), correctedConeResistance=response_dict.get("correctedConeResistance"), depthOffset=response_dict.get("depthOffset"), frictionalResistance=response_dict.get("frictionalResistance"), pointResistance=response_dict.get("pointResistance"), sheetResistance=response_dict.get("sheetResistance"), slotResistance=response_dict.get("slotResistance"), totalResistance=response_dict.get("totalResistance"), ) @property def dataframe(self) -> pd.DataFrame: """The pandas.DataFrame representation""" return pd.DataFrame(self.__dict__).dropna(axis="rows", how="any") # type: ignore
[docs]@dataclass(frozen=True) class SingleCalculationData: """ Object that contains the impact force related data. Attributes: ------------ table: ImpactForceTable table object installationLevel: float installation level [m w.r.t. Reference] maximumForce: float total resistance [kN] pointForce: float resistance at the base [kN] """ table: ImpactForceTable installationLevel: float maximumForce: float pointForce: float | None
[docs] @classmethod def from_api_response(cls, response_dict: dict) -> "SingleCalculationData": """ Stores the response of the VibraCore endpoint Parameters ---------- response_dict: The resulting response of a call to `impact-force/calculation/single` """ return cls( table=ImpactForceTable.from_api_response(response_dict["data"]), installationLevel=response_dict["installationLevel"], maximumForce=response_dict["maximumForce"], pointForce=response_dict.get("pointForce"), )
[docs] def plot( self, figsize: Tuple[float, float] = (10.0, 12.0), **kwargs: Any, ) -> plt.Figure: """ Plots the resistance data. Parameters ---------- figsize: Size of the activate figure, as the `plt.figure()` argument. **kwargs: All additional keyword arguments are passed to the `pyplot.subplots()` call. Returns ------- fig: The matplotlib Figure """ kwargs_subplot = { "figsize": figsize, "tight_layout": True, } kwargs_subplot.update(kwargs) fig, axes = plt.subplots(**kwargs_subplot) for item in [ "totalResistance", "frictionalResistance", "slotResistance", "pointResistance", ]: axes.plot( self.table.__getattribute__(item), self.table.depthOffset, label=item, ) axes.axvline( x=self.installationLevel, c="k", linestyle="dashed", label=f"max force ({self.maximumForce.__round__(2)})", ) axes.axhline( y=self.installationLevel, c="k", linestyle="dotted", label=f"installation level ({self.installationLevel})", ) axes.set_xlabel("Resistance [kN]") axes.grid() return fig