{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# APSG tutorial - Part 1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**APSG** defines several new python classes to easily manage, analyze and visualize orientation structural geology data. There are several classes to work with orientation data, namely `Vector3` for vectorial data and `Lineation`, `Foliation` for axial data" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Basic usage" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**APSG** module could be imported either into its own namespace or into the active one for easier interactive work." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:54.966486Z", "iopub.status.busy": "2026-05-26T10:13:54.966404Z", "iopub.status.idle": "2026-05-26T10:13:56.454972Z", "shell.execute_reply": "2026-05-26T10:13:56.454518Z" }, "scrolled": true }, "outputs": [], "source": [ "from apsg import *" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Basic operations with vectors in 2D and 3D\n", "Instance of vector object `Vector3` could be created by passing three arguments corresponding to 3 components to function `vec`:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.456618Z", "iopub.status.busy": "2026-05-26T10:13:56.456470Z", "iopub.status.idle": "2026-05-26T10:13:56.457943Z", "shell.execute_reply": "2026-05-26T10:13:56.457709Z" } }, "outputs": [], "source": [ "u = vec(1, -2, 3)\n", "v = vec(-2, 1, 1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Alternative ways to create a vector are to pass a single iterable object as list, tuple or array, or to provide geological orientation according to **APSG** notation (default is *direction of dip* and *dip angle* for planar and *trend* and *plunge* for linear features)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.459357Z", "iopub.status.busy": "2026-05-26T10:13:56.459287Z", "iopub.status.idle": "2026-05-26T10:13:56.460868Z", "shell.execute_reply": "2026-05-26T10:13:56.460620Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Vector3(-2, 2, 3) Vector3(-0.25, 0.433, 0.866)\n" ] } ], "source": [ "coords = (-2, 2, 3)\n", "a = vec(coords)\n", "b = vec(120, 60)\n", "print(a, b)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The instance of a 2D vector `Vector2` could be created passing 2 arguments corresponding to 2 components or a single iterable of components to the function `vec2`:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.477038Z", "iopub.status.busy": "2026-05-26T10:13:56.476944Z", "iopub.status.idle": "2026-05-26T10:13:56.478881Z", "shell.execute_reply": "2026-05-26T10:13:56.478450Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Vector2(1, 1) Vector2(-1, 2)\n" ] } ], "source": [ "k = vec2(1, 1)\n", "coords = (-1, 2)\n", "l = vec2(coords)\n", "print(k, l)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Alternatively, single argument is interpreted as direction in degrees (0-top, 90-right, 180-down, 270-left)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.479950Z", "iopub.status.busy": "2026-05-26T10:13:56.479862Z", "iopub.status.idle": "2026-05-26T10:13:56.482308Z", "shell.execute_reply": "2026-05-26T10:13:56.482131Z" } }, "outputs": [ { "data": { "text/plain": [ "Vector2(-2.5, 4.33)" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m = 5 * vec2(120)\n", "m" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For common vector operations we can use standard mathematical operators or special methods using dot notation" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.483455Z", "iopub.status.busy": "2026-05-26T10:13:56.483372Z", "iopub.status.idle": "2026-05-26T10:13:56.485101Z", "shell.execute_reply": "2026-05-26T10:13:56.484906Z" } }, "outputs": [ { "data": { "text/plain": [ "Vector3(-1, -1, 4)" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "u + v" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.485999Z", "iopub.status.busy": "2026-05-26T10:13:56.485935Z", "iopub.status.idle": "2026-05-26T10:13:56.487412Z", "shell.execute_reply": "2026-05-26T10:13:56.487244Z" } }, "outputs": [ { "data": { "text/plain": [ "Vector3(3, -3, 2)" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "u - v" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.488335Z", "iopub.status.busy": "2026-05-26T10:13:56.488272Z", "iopub.status.idle": "2026-05-26T10:13:56.489795Z", "shell.execute_reply": "2026-05-26T10:13:56.489621Z" } }, "outputs": [ { "data": { "text/plain": [ "Vector3(7, -8, 7)" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "3*u - 2*v" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Its magnitude or length is most commonly defined as its Euclidean norm and could be calculated using `abs`" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.490719Z", "iopub.status.busy": "2026-05-26T10:13:56.490654Z", "iopub.status.idle": "2026-05-26T10:13:56.492151Z", "shell.execute_reply": "2026-05-26T10:13:56.491948Z" } }, "outputs": [ { "data": { "text/plain": [ "2.449489742783178" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "abs(v)" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.493010Z", "iopub.status.busy": "2026-05-26T10:13:56.492941Z", "iopub.status.idle": "2026-05-26T10:13:56.494418Z", "shell.execute_reply": "2026-05-26T10:13:56.494244Z" } }, "outputs": [ { "data": { "text/plain": [ "4.242640687119285" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "abs(u + v)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For *dot product* we can use the `dot` method or the `@` operator " ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.495310Z", "iopub.status.busy": "2026-05-26T10:13:56.495241Z", "iopub.status.idle": "2026-05-26T10:13:56.496733Z", "shell.execute_reply": "2026-05-26T10:13:56.496549Z" } }, "outputs": [ { "data": { "text/plain": [ "-1" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "u.dot(v)" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.497487Z", "iopub.status.busy": "2026-05-26T10:13:56.497422Z", "iopub.status.idle": "2026-05-26T10:13:56.499154Z", "shell.execute_reply": "2026-05-26T10:13:56.498733Z" } }, "outputs": [ { "data": { "text/plain": [ "-1.0" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "u @ v" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For *cross product* we can use the `cross` method" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.499994Z", "iopub.status.busy": "2026-05-26T10:13:56.499878Z", "iopub.status.idle": "2026-05-26T10:13:56.502228Z", "shell.execute_reply": "2026-05-26T10:13:56.501889Z" } }, "outputs": [ { "data": { "text/plain": [ "Vector3(-5, -7, -3)" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "u.cross(v)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To project vector ``u`` onto vector ``v`` we can use method ``proj``" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.502996Z", "iopub.status.busy": "2026-05-26T10:13:56.502888Z", "iopub.status.idle": "2026-05-26T10:13:56.505280Z", "shell.execute_reply": "2026-05-26T10:13:56.504914Z" } }, "outputs": [ { "data": { "text/plain": [ "Vector3(0.333, -0.167, -0.167)" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "u.proj(v)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To find angle (in degrees) between to vectors we use method ``angle``" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.506126Z", "iopub.status.busy": "2026-05-26T10:13:56.505965Z", "iopub.status.idle": "2026-05-26T10:13:56.508251Z", "shell.execute_reply": "2026-05-26T10:13:56.507904Z" } }, "outputs": [ { "data": { "text/plain": [ "96.26395271992722" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "u.angle(v)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The ``rotate`` method rotates a vector around another vector. For example, to rotate vector ``u`` around vector ``v`` for 45°" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.509017Z", "iopub.status.busy": "2026-05-26T10:13:56.508910Z", "iopub.status.idle": "2026-05-26T10:13:56.511341Z", "shell.execute_reply": "2026-05-26T10:13:56.510939Z" } }, "outputs": [ { "data": { "text/plain": [ "Vector3(2.248, 0.558, 2.939)" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "u.rotate(v, 45)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Classes Lineation and Foliation\n", "To work with orientation data in structural geology, **APSG** provides two classes: ``Foliation`` to represent planar features and ``Lineation`` to represent linear features. Both classes support all `Vector3` methods and operators, but it should be noted, that `dot` and `angle` respect their axial nature, i.e. angle between two lineations can't be bigger than 90 degrees." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To create instance of `Lineation` or `Foliation`, we can use functions `lin` and `fol`. Arguments have similar syntax to `vec`." ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.512171Z", "iopub.status.busy": "2026-05-26T10:13:56.512061Z", "iopub.status.idle": "2026-05-26T10:13:56.514489Z", "shell.execute_reply": "2026-05-26T10:13:56.514134Z" } }, "outputs": [ { "data": { "text/plain": [ "(L:120/60, S:216/62)" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "lin(120, 60), fol(216, 62)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also cast `Vector3` instance to `Foliation` or `Lineation`" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.515268Z", "iopub.status.busy": "2026-05-26T10:13:56.515160Z", "iopub.status.idle": "2026-05-26T10:13:56.517266Z", "shell.execute_reply": "2026-05-26T10:13:56.516987Z" } }, "outputs": [ { "data": { "text/plain": [ "(L:297/53, S:117/37)" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "lin(u), fol(u)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Vector methods for Lineation and Foliation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "To find angle between two linear or planar features we can use method `angle`" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.517941Z", "iopub.status.busy": "2026-05-26T10:13:56.517875Z", "iopub.status.idle": "2026-05-26T10:13:56.519830Z", "shell.execute_reply": "2026-05-26T10:13:56.519549Z" } }, "outputs": [ { "data": { "text/plain": [ "41.59741268003547" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l1 = lin(110, 40)\n", "l2 = lin(160, 30)\n", "l1.angle(l2)" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.520502Z", "iopub.status.busy": "2026-05-26T10:13:56.520408Z", "iopub.status.idle": "2026-05-26T10:13:56.522345Z", "shell.execute_reply": "2026-05-26T10:13:56.522059Z" } }, "outputs": [ { "data": { "text/plain": [ "54.696399321975335" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p1 = fol(330, 50)\n", "p2 = fol(250, 40)\n", "p1.angle(p2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can use *cross product* to construct a planar feature defined by two linear features" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.523078Z", "iopub.status.busy": "2026-05-26T10:13:56.523014Z", "iopub.status.idle": "2026-05-26T10:13:56.524813Z", "shell.execute_reply": "2026-05-26T10:13:56.524548Z" } }, "outputs": [ { "data": { "text/plain": [ "S:113/40" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l1.cross(l2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "or to construct linear feature defined by intersection of two planar features" ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.525850Z", "iopub.status.busy": "2026-05-26T10:13:56.525784Z", "iopub.status.idle": "2026-05-26T10:13:56.527609Z", "shell.execute_reply": "2026-05-26T10:13:56.527360Z" } }, "outputs": [ { "data": { "text/plain": [ "L:278/36" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p1.cross(p2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*Cross product* of planar and linear features could be used to construct a plane defined by a linear feature and the normal of a planar feature" ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.528342Z", "iopub.status.busy": "2026-05-26T10:13:56.528278Z", "iopub.status.idle": "2026-05-26T10:13:56.530089Z", "shell.execute_reply": "2026-05-26T10:13:56.529827Z" } }, "outputs": [ { "data": { "text/plain": [ "S:96/53" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l2.cross(p2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "or to find the perpendicular linear feature on a given plane" ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.530738Z", "iopub.status.busy": "2026-05-26T10:13:56.530666Z", "iopub.status.idle": "2026-05-26T10:13:56.532570Z", "shell.execute_reply": "2026-05-26T10:13:56.532297Z" } }, "outputs": [ { "data": { "text/plain": [ "L:276/37" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p2.cross(l2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To rotate structural features we can use method ``rotate``" ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.533410Z", "iopub.status.busy": "2026-05-26T10:13:56.533345Z", "iopub.status.idle": "2026-05-26T10:13:56.535224Z", "shell.execute_reply": "2026-05-26T10:13:56.534972Z" } }, "outputs": [ { "data": { "text/plain": [ "S:269/78" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p2.rotate(l2, 45)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Classes Pair and Fault\n", "To work with paired orientation data like foliations and lineations or fault data in structural geology, **APSG** provides the ``Pair`` base class and the derived ``Fault`` class. Both classes are instantiated providing dip direction and dip of planar and linear measurements, which are automatically orthogonalized. If misfit is too high, warning is raised. The `Fault` class expects one more argument providing sense of movement information, either 1 or -1 for normal/reverse movement." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To create instance of `Pair`, we have to pass two arguments for planar and two arguments for linear features following geological notation to function `pair`:" ] }, { "cell_type": "code", "execution_count": 26, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.535860Z", "iopub.status.busy": "2026-05-26T10:13:56.535797Z", "iopub.status.idle": "2026-05-26T10:13:56.537805Z", "shell.execute_reply": "2026-05-26T10:13:56.537534Z" } }, "outputs": [ { "data": { "text/plain": [ "P:118/39-163/30" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p = pair(120, 40, 162, 28)\n", "p" ] }, { "cell_type": "code", "execution_count": 27, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.538390Z", "iopub.status.busy": "2026-05-26T10:13:56.538324Z", "iopub.status.idle": "2026-05-26T10:13:56.540080Z", "shell.execute_reply": "2026-05-26T10:13:56.539827Z" } }, "outputs": [ { "data": { "text/plain": [ "3.5623168411508175" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p.misfit" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Planar and linear features are accessible using `fol` and `lin` properties" ] }, { "cell_type": "code", "execution_count": 28, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.540751Z", "iopub.status.busy": "2026-05-26T10:13:56.540684Z", "iopub.status.idle": "2026-05-26T10:13:56.542526Z", "shell.execute_reply": "2026-05-26T10:13:56.542238Z" } }, "outputs": [ { "data": { "text/plain": [ "(S:118/39, L:163/30)" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p.fol, p.lin" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To rotate a ``Pair`` instance we can use the ``rotate`` method" ] }, { "cell_type": "code", "execution_count": 29, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.543109Z", "iopub.status.busy": "2026-05-26T10:13:56.543046Z", "iopub.status.idle": "2026-05-26T10:13:56.545179Z", "shell.execute_reply": "2026-05-26T10:13:56.544902Z" } }, "outputs": [ { "data": { "text/plain": [ "P:314/83-237/61" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p.rotate(lin(45, 10), 60)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Instantiation of ``Fault`` class is similar, we just have to provide an argument to define the sense of movement" ] }, { "cell_type": "code", "execution_count": 30, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.545780Z", "iopub.status.busy": "2026-05-26T10:13:56.545717Z", "iopub.status.idle": "2026-05-26T10:13:56.548223Z", "shell.execute_reply": "2026-05-26T10:13:56.547928Z" } }, "outputs": [ { "data": { "text/plain": [ "F:120/59-110/59 N" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f = fault(120, 60, 110, 58, 1) # 1 for normal fault\n", "f" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note the change in sense of movement after ``Fault`` rotation" ] }, { "cell_type": "code", "execution_count": 31, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.548898Z", "iopub.status.busy": "2026-05-26T10:13:56.548834Z", "iopub.status.idle": "2026-05-26T10:13:56.551100Z", "shell.execute_reply": "2026-05-26T10:13:56.550823Z" } }, "outputs": [ { "data": { "text/plain": [ "F:312/62-340/59 N" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f.rotate(lin(45, 10), 60)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For simple fault analyses the ``Fault`` class also provides ``p``, ``t``, ``m``, and ``d`` properties to get PT-axes, kinematic plane and dihedra separation plane" ] }, { "cell_type": "code", "execution_count": 32, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.551691Z", "iopub.status.busy": "2026-05-26T10:13:56.551625Z", "iopub.status.idle": "2026-05-26T10:13:56.553619Z", "shell.execute_reply": "2026-05-26T10:13:56.553355Z" } }, "outputs": [ { "data": { "text/plain": [ "(L:315/75, L:116/14, S:27/85, S:290/31)" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f.p, f.t, f.m, f.d" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Class Cone\n", "General feature type to store small or great circles as a cone. It could be defined by `axis`, `secant` and `revolving angle` or by ``axis`` and ``apical angle``. The revolving angle is by default 360° defining full cone. For segments of small circles, the `revolving angle` could be different." ] }, { "cell_type": "code", "execution_count": 33, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.554263Z", "iopub.status.busy": "2026-05-26T10:13:56.554156Z", "iopub.status.idle": "2026-05-26T10:13:56.555878Z", "shell.execute_reply": "2026-05-26T10:13:56.555640Z" } }, "outputs": [ { "data": { "text/plain": [ "C:140/50 [25]" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c = cone(lin(140, 50), lin(140, 75))\n", "c" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To create small circle segment, you can provide `revolving angle`" ] }, { "cell_type": "code", "execution_count": 34, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.556476Z", "iopub.status.busy": "2026-05-26T10:13:56.556405Z", "iopub.status.idle": "2026-05-26T10:13:56.557782Z", "shell.execute_reply": "2026-05-26T10:13:56.557536Z" } }, "outputs": [], "source": [ "c = cone(lin(90, 70), lin(45,30), 115)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The tips of small circle segments could be obtained from the cone properties ``secant`` and ``rotated_secant``" ] }, { "cell_type": "code", "execution_count": 35, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.558361Z", "iopub.status.busy": "2026-05-26T10:13:56.558296Z", "iopub.status.idle": "2026-05-26T10:13:56.559982Z", "shell.execute_reply": "2026-05-26T10:13:56.559739Z" } }, "outputs": [ { "data": { "text/plain": [ "(L:45/30, L:137/30)" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "lin(c.secant), lin(c.rotated_secant)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To define cone using `apical angle`, use `axis` and number arguments. Note, that `revolving angle` is 360 by default" ] }, { "cell_type": "code", "execution_count": 36, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.560599Z", "iopub.status.busy": "2026-05-26T10:13:56.560524Z", "iopub.status.idle": "2026-05-26T10:13:56.562208Z", "shell.execute_reply": "2026-05-26T10:13:56.561966Z" } }, "outputs": [ { "data": { "text/plain": [ "C:140/50 [25]" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c = cone(lin(140, 50), 25)\n", "c" ] }, { "cell_type": "code", "execution_count": 37, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.562842Z", "iopub.status.busy": "2026-05-26T10:13:56.562763Z", "iopub.status.idle": "2026-05-26T10:13:56.564405Z", "shell.execute_reply": "2026-05-26T10:13:56.564184Z" } }, "outputs": [ { "data": { "text/plain": [ "360.0" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c.revangle" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Feature sets\n", "*APSG* provides several classes to process, analyze, and visualize sets of data. There are e.g. `vecset`, `linset` and `folset` classes to store groups of ``vec``, ``lin``, and ``fol`` objects. All these feature sets are created from homogeneous list of data with optional `name` attribute." ] }, { "cell_type": "code", "execution_count": 38, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.565079Z", "iopub.status.busy": "2026-05-26T10:13:56.565012Z", "iopub.status.idle": "2026-05-26T10:13:56.566650Z", "shell.execute_reply": "2026-05-26T10:13:56.566503Z" } }, "outputs": [ { "data": { "text/plain": [ "V3(5) Vectors" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v = vecset([vec(120,60), vec(116,50), vec(132,45), vec(90,60), vec(84,52)], name='Vectors')\n", "v" ] }, { "cell_type": "code", "execution_count": 39, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.567344Z", "iopub.status.busy": "2026-05-26T10:13:56.567282Z", "iopub.status.idle": "2026-05-26T10:13:56.568911Z", "shell.execute_reply": "2026-05-26T10:13:56.568735Z" } }, "outputs": [ { "data": { "text/plain": [ "L(5) Lineations" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l = linset([lin(120,60), lin(116,50), lin(132,45), lin(90,60), lin(84,52)], name='Lineations')\n", "l" ] }, { "cell_type": "code", "execution_count": 40, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.569597Z", "iopub.status.busy": "2026-05-26T10:13:56.569527Z", "iopub.status.idle": "2026-05-26T10:13:56.571250Z", "shell.execute_reply": "2026-05-26T10:13:56.571040Z" } }, "outputs": [ { "data": { "text/plain": [ "S(5) Foliations" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f = folset([fol(120,60), fol(116,50), fol(132,45), fol(90,60), fol(84,52)], name='Foliations')\n", "f" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To simplify interactive group creation, you can use function ``G``" ] }, { "cell_type": "code", "execution_count": 41, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.572110Z", "iopub.status.busy": "2026-05-26T10:13:56.572046Z", "iopub.status.idle": "2026-05-26T10:13:56.573716Z", "shell.execute_reply": "2026-05-26T10:13:56.573550Z" } }, "outputs": [ { "data": { "text/plain": [ "L(5) L1" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "g = G([lin(120,60), lin(116,50), lin(132,45), lin(90,60), lin(84,52)], name='L1')\n", "g" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Method ``len`` returns number of features in group" ] }, { "cell_type": "code", "execution_count": 42, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.574508Z", "iopub.status.busy": "2026-05-26T10:13:56.574412Z", "iopub.status.idle": "2026-05-26T10:13:56.575887Z", "shell.execute_reply": "2026-05-26T10:13:56.575694Z" } }, "outputs": [ { "data": { "text/plain": [ "5" ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "len(v)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Most of the `vec`, `lin` and `fol` methods could be used for feature sets as well. For example, to measure angles between all features in group and another feature, we can use method `angle`:" ] }, { "cell_type": "code", "execution_count": 43, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.576480Z", "iopub.status.busy": "2026-05-26T10:13:56.576416Z", "iopub.status.idle": "2026-05-26T10:13:56.578151Z", "shell.execute_reply": "2026-05-26T10:13:56.577970Z" } }, "outputs": [ { "data": { "text/plain": [ "array([11.49989817, 3.85569115, 15.61367789, 15.11039885, 16.3947936 ])" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l.angle(lin(110,50))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To rotate all features in group around another feature, we can use method ``rotate``" ] }, { "cell_type": "code", "execution_count": 44, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.578848Z", "iopub.status.busy": "2026-05-26T10:13:56.578770Z", "iopub.status.idle": "2026-05-26T10:13:56.580405Z", "shell.execute_reply": "2026-05-26T10:13:56.580151Z" } }, "outputs": [], "source": [ "lr = l.rotate(lin(150, 30), 45)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To show data in list you can use ``data`` property" ] }, { "cell_type": "code", "execution_count": 45, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.580985Z", "iopub.status.busy": "2026-05-26T10:13:56.580917Z", "iopub.status.idle": "2026-05-26T10:13:56.582480Z", "shell.execute_reply": "2026-05-26T10:13:56.582274Z" } }, "outputs": [ { "data": { "text/plain": [ "(L:120/60, L:116/50, L:132/45, L:90/60, L:84/52)" ] }, "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l.data" ] }, { "cell_type": "code", "execution_count": 46, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.583213Z", "iopub.status.busy": "2026-05-26T10:13:56.583149Z", "iopub.status.idle": "2026-05-26T10:13:56.584679Z", "shell.execute_reply": "2026-05-26T10:13:56.584488Z" } }, "outputs": [ { "data": { "text/plain": [ "(L:107/35, L:113/26, L:126/30, L:93/26, L:94/18)" ] }, "execution_count": 46, "metadata": {}, "output_type": "execute_result" } ], "source": [ "lr.data" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Method ``R`` returns the resultant of all features in set. Note that `Lineation` and `Foliation` are axial in nature, so resultant vector is not reliable. Check the orientation tensor analysis below." ] }, { "cell_type": "code", "execution_count": 47, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.585437Z", "iopub.status.busy": "2026-05-26T10:13:56.585370Z", "iopub.status.idle": "2026-05-26T10:13:56.586940Z", "shell.execute_reply": "2026-05-26T10:13:56.586713Z" } }, "outputs": [ { "data": { "text/plain": [ "Vector3(-0.941, 2.649, 3.993)" ] }, "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.R()" ] }, { "cell_type": "code", "execution_count": 48, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.587500Z", "iopub.status.busy": "2026-05-26T10:13:56.587437Z", "iopub.status.idle": "2026-05-26T10:13:56.589032Z", "shell.execute_reply": "2026-05-26T10:13:56.588812Z" } }, "outputs": [ { "data": { "text/plain": [ "L:110/55" ] }, "execution_count": 48, "metadata": {}, "output_type": "execute_result" } ], "source": [ "lin(v.R())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There are several methods to infer spherical statistics as spherical variance, Fisher's statistics, confidence cones on data etc." ] }, { "cell_type": "code", "execution_count": 49, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.589614Z", "iopub.status.busy": "2026-05-26T10:13:56.589551Z", "iopub.status.idle": "2026-05-26T10:13:56.591149Z", "shell.execute_reply": "2026-05-26T10:13:56.590925Z" } }, "outputs": [ { "data": { "text/plain": [ "0.02337168447438498" ] }, "execution_count": 49, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l.var()" ] }, { "cell_type": "code", "execution_count": 50, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.591706Z", "iopub.status.busy": "2026-05-26T10:13:56.591642Z", "iopub.status.idle": "2026-05-26T10:13:56.593534Z", "shell.execute_reply": "2026-05-26T10:13:56.593251Z" } }, "outputs": [ { "data": { "text/plain": [ "{'mu': Vector3(-0.193, 0.542, 0.818),\n", " 'k': np.float64(42.786817573888605),\n", " 'alpha': 13.26402990511733,\n", " 'csd': np.float64(12.383118421320239),\n", " 'uniform': False}" ] }, "execution_count": 50, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.fisher_statistics()" ] }, { "cell_type": "code", "execution_count": 51, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.594198Z", "iopub.status.busy": "2026-05-26T10:13:56.594125Z", "iopub.status.idle": "2026-05-26T10:13:56.596029Z", "shell.execute_reply": "2026-05-26T10:13:56.595839Z" } }, "outputs": [ { "data": { "text/plain": [ "C:110/55 [13.264]" ] }, "execution_count": 51, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.fisher_cone()" ] }, { "cell_type": "code", "execution_count": 52, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.596732Z", "iopub.status.busy": "2026-05-26T10:13:56.596664Z", "iopub.status.idle": "2026-05-26T10:13:56.598452Z", "shell.execute_reply": "2026-05-26T10:13:56.598250Z" } }, "outputs": [ { "data": { "text/plain": [ "C:110/55 [12.3831]" ] }, "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.fisher_cone_csd()" ] }, { "cell_type": "code", "execution_count": 53, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.599171Z", "iopub.status.busy": "2026-05-26T10:13:56.599103Z", "iopub.status.idle": "2026-05-26T10:13:56.600653Z", "shell.execute_reply": "2026-05-26T10:13:56.600443Z" } }, "outputs": [ { "data": { "text/plain": [ "12.411724720740516" ] }, "execution_count": 53, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.delta()" ] }, { "cell_type": "code", "execution_count": 54, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.601216Z", "iopub.status.busy": "2026-05-26T10:13:56.601145Z", "iopub.status.idle": "2026-05-26T10:13:56.602650Z", "shell.execute_reply": "2026-05-26T10:13:56.602477Z" } }, "outputs": [ { "data": { "text/plain": [ "95.32566310512297" ] }, "execution_count": 54, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.rdegree()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To calculate orientation tensor of all features in group, we can use `ortensor` method." ] }, { "cell_type": "code", "execution_count": 55, "metadata": { "execution": { "iopub.execute_input": "2026-05-26T10:13:56.603320Z", "iopub.status.busy": "2026-05-26T10:13:56.603256Z", "iopub.status.idle": "2026-05-26T10:13:56.605096Z", "shell.execute_reply": "2026-05-26T10:13:56.604927Z" } }, "outputs": [ { "data": { "text/plain": [ "OrientationTensor3\n", "[[ 0.074 -0.096 -0.143]\n", " [-0.096 0.284 0.421]\n", " [-0.143 0.421 0.642]]\n", "(S1:0.977, S2:0.201, S3:0.0758)" ] }, "execution_count": 55, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.ortensor()" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.3" } }, "nbformat": 4, "nbformat_minor": 4 }