apsg 1.3.4__py3-none-any.whl → 1.3.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
apsg/__init__.py CHANGED
@@ -1,56 +1,114 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
- from apsg.math import (
4
- Vector3 as vec,
5
- Vector2 as vec2,
6
- Matrix2 as matrix2,
7
- Matrix3 as matrix,
8
- )
9
3
  from apsg.config import apsg_conf
10
4
  from apsg.feature import (
11
- Lineation as lin,
12
- Foliation as fol,
13
- Pair as pair,
14
- Fault as fault,
5
+ ClusterSet as cluster,
6
+ )
7
+ from apsg.feature import (
15
8
  Cone as cone,
16
9
  )
17
10
  from apsg.feature import (
18
- Vector3Set as vecset,
19
- Vector2Set as vec2set,
20
- LineationSet as linset,
21
- FoliationSet as folset,
22
- PairSet as pairset,
23
- FaultSet as faultset,
24
11
  ConeSet as coneset,
12
+ )
13
+ from apsg.feature import (
14
+ DeformationGradient2 as defgrad2,
15
+ )
16
+ from apsg.feature import (
17
+ DeformationGradient3 as defgrad,
18
+ )
19
+ from apsg.feature import (
20
+ Direction as dir2,
21
+ )
22
+ from apsg.feature import (
23
+ Direction2Set as dir2set,
24
+ )
25
+ from apsg.feature import (
26
+ Ellipse as ellipse,
27
+ )
28
+ from apsg.feature import (
25
29
  EllipseSet as ellipseset,
30
+ )
31
+ from apsg.feature import (
32
+ Ellipsoid as ellipsoid,
33
+ )
34
+ from apsg.feature import (
26
35
  EllipsoidSet as ellipsoidset,
36
+ )
37
+ from apsg.feature import (
38
+ Fault as fault,
39
+ )
40
+ from apsg.feature import (
41
+ FaultSet as faultset,
42
+ )
43
+ from apsg.feature import (
44
+ Foliation as fol,
45
+ )
46
+ from apsg.feature import (
47
+ FoliationSet as folset,
48
+ )
49
+ from apsg.feature import G
50
+ from apsg.feature import (
51
+ Lineation as lin,
52
+ )
53
+ from apsg.feature import (
54
+ LineationSet as linset,
55
+ )
56
+ from apsg.feature import (
57
+ OrientationTensor2 as ortensor2,
58
+ )
59
+ from apsg.feature import (
27
60
  OrientationTensor2Set as ortensor2set,
61
+ )
62
+ from apsg.feature import (
63
+ OrientationTensor3 as ortensor,
64
+ )
65
+ from apsg.feature import (
28
66
  OrientationTensor3Set as ortensorset,
29
- ClusterSet as cluster,
30
67
  )
31
68
  from apsg.feature import (
32
- DeformationGradient3 as defgrad,
33
- VelocityGradient3 as velgrad,
69
+ Pair as pair,
70
+ )
71
+ from apsg.feature import (
72
+ PairSet as pairset,
73
+ )
74
+ from apsg.feature import (
75
+ Stress2 as stress2,
76
+ )
77
+ from apsg.feature import (
34
78
  Stress3 as stress,
35
- Ellipsoid as ellipsoid,
36
- OrientationTensor3 as ortensor,
37
79
  )
38
80
  from apsg.feature import (
39
- DeformationGradient2 as defgrad2,
81
+ Vector2Set as vec2set,
82
+ )
83
+ from apsg.feature import (
84
+ Vector3Set as vecset,
85
+ )
86
+ from apsg.feature import (
40
87
  VelocityGradient2 as velgrad2,
41
- Stress2 as stress2,
42
- Ellipse as ellipse,
43
- OrientationTensor2 as ortensor2,
44
88
  )
45
- from apsg.feature import G
89
+ from apsg.feature import (
90
+ VelocityGradient3 as velgrad,
91
+ )
92
+ from apsg.math import (
93
+ Matrix2 as matrix2,
94
+ )
95
+ from apsg.math import (
96
+ Matrix3 as matrix,
97
+ )
98
+ from apsg.math import (
99
+ Vector2 as vec2,
100
+ )
101
+ from apsg.math import (
102
+ Vector3 as vec,
103
+ )
46
104
  from apsg.plotting import (
105
+ FlinnPlot,
106
+ HsuPlot,
107
+ RamsayPlot,
108
+ RosePlot,
47
109
  StereoGrid,
48
110
  StereoNet,
49
- RosePlot,
50
111
  VollmerPlot,
51
- RamsayPlot,
52
- FlinnPlot,
53
- HsuPlot,
54
112
  quicknet,
55
113
  )
56
114
 
@@ -60,6 +118,7 @@ __all__ = (
60
118
  "vec2",
61
119
  "matrix",
62
120
  "matrix2",
121
+ "dir2",
63
122
  "lin",
64
123
  "fol",
65
124
  "pair",
@@ -67,6 +126,7 @@ __all__ = (
67
126
  "cone",
68
127
  "vecset",
69
128
  "vec2set",
129
+ "dir2set",
70
130
  "linset",
71
131
  "folset",
72
132
  "pairset",
@@ -98,6 +158,6 @@ __all__ = (
98
158
  "quicknet",
99
159
  )
100
160
 
101
- __version__ = "1.3.4"
161
+ __version__ = "1.3.6"
102
162
  __author__ = "Ondrej Lexa"
103
163
  __email__ = "lexa.ondrej@gmail.com"
apsg/config.py CHANGED
@@ -138,7 +138,6 @@ apsg_conf = dict(
138
138
  ),
139
139
  roseplot_default_kwargs=dict(
140
140
  bins=36,
141
- axial=True,
142
141
  density=True,
143
142
  arrowness=0.95,
144
143
  rwidth=1,
apsg/database/_sdbread.py CHANGED
@@ -10,7 +10,7 @@ from apsg.feature._geodata import Lineation, Foliation
10
10
  from apsg.feature._container import LineationSet, FoliationSet
11
11
 
12
12
 
13
- class SDB(object):
13
+ class SDB:
14
14
  """
15
15
  sqlite3 based read-only interface to PySDB database
16
16
 
apsg/feature/__init__.py CHANGED
@@ -1,39 +1,42 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  import sys
3
- from apsg.feature._geodata import Lineation, Foliation, Pair, Fault, Cone
3
+
4
4
  from apsg.feature._container import (
5
- FeatureSet,
6
- Vector2Set,
7
- Vector3Set,
8
- LineationSet,
9
- FoliationSet,
10
- PairSet,
11
- FaultSet,
5
+ ClusterSet,
12
6
  ConeSet,
7
+ Direction2Set,
13
8
  EllipseSet,
14
9
  EllipsoidSet,
10
+ FaultSet,
11
+ FeatureSet,
12
+ FoliationSet,
13
+ G,
14
+ LineationSet,
15
15
  OrientationTensor2Set,
16
16
  OrientationTensor3Set,
17
- G,
18
- ClusterSet,
19
- )
20
- from apsg.feature._tensor3 import (
21
- DeformationGradient3,
22
- VelocityGradient3,
23
- Stress3,
24
- Ellipsoid,
25
- OrientationTensor3,
17
+ PairSet,
18
+ Vector2Set,
19
+ Vector3Set,
26
20
  )
21
+ from apsg.feature._geodata import Cone, Direction, Fault, Foliation, Lineation, Pair
22
+ from apsg.feature._paleomag import Core
27
23
  from apsg.feature._tensor2 import (
28
24
  DeformationGradient2,
29
- VelocityGradient2,
30
- Stress2,
31
25
  Ellipse,
32
26
  OrientationTensor2,
27
+ Stress2,
28
+ VelocityGradient2,
29
+ )
30
+ from apsg.feature._tensor3 import (
31
+ DeformationGradient3,
32
+ Ellipsoid,
33
+ OrientationTensor3,
34
+ Stress3,
35
+ VelocityGradient3,
33
36
  )
34
- from apsg.feature._paleomag import Core
35
37
 
36
38
  __all__ = (
39
+ "Direction",
37
40
  "Lineation",
38
41
  "Foliation",
39
42
  "Pair",
@@ -50,6 +53,7 @@ __all__ = (
50
53
  "Ellipse",
51
54
  "OrientationTensor2",
52
55
  "Vector2Set",
56
+ "Direction2Set",
53
57
  "FeatureSet",
54
58
  "Vector3Set",
55
59
  "LineationSet",
@@ -1,17 +1,19 @@
1
- import sys
1
+ import csv
2
2
  from itertools import combinations
3
- import numpy as np
3
+ from os.path import basename
4
+
4
5
  import matplotlib.pyplot as plt
6
+ import numpy as np
7
+ from scipy.cluster.hierarchy import dendrogram, fcluster, linkage
5
8
  from scipy.stats import vonmises
6
- from scipy.cluster.hierarchy import linkage, fcluster, dendrogram
7
9
 
8
10
  from apsg.config import apsg_conf
9
- from apsg.math._vector import Vector2, Vector3
10
- from apsg.helpers._math import acosd
11
- from apsg.feature._geodata import Lineation, Foliation, Pair, Fault, Cone
12
- from apsg.feature._tensor3 import OrientationTensor3, Ellipsoid, DeformationGradient3
13
- from apsg.feature._tensor2 import OrientationTensor2, Ellipse
11
+ from apsg.feature._geodata import Cone, Direction, Fault, Foliation, Lineation, Pair
14
12
  from apsg.feature._statistics import KentDistribution, vonMisesFisher
13
+ from apsg.feature._tensor2 import Ellipse, OrientationTensor2
14
+ from apsg.feature._tensor3 import DeformationGradient3, Ellipsoid, OrientationTensor3
15
+ from apsg.helpers._math import acosd
16
+ from apsg.math._vector import Axial2, Axial3, Vector2, Vector3
15
17
 
16
18
 
17
19
  class FeatureSet:
@@ -22,12 +24,11 @@ class FeatureSet:
22
24
  __slots__ = ("data", "name")
23
25
 
24
26
  def __init__(self, data, name="Default"):
25
- dtype_cls = getattr(sys.modules[__name__], type(self).__feature_type__)
26
27
  assert all(
27
- [isinstance(obj, dtype_cls) for obj in data]
28
- ), f"Data must be instances of {type(self).__feature_type__}"
28
+ [isinstance(obj, self.__feature_class__) for obj in data]
29
+ ), f"Data must be instances of {self.__feature_class__.__name__}"
29
30
  # cast to correct instances
30
- self.data = tuple([dtype_cls(d) for d in data])
31
+ self.data = tuple([self.__feature_class__(d) for d in data])
31
32
  self.name = name
32
33
  self._cache = {}
33
34
 
@@ -117,7 +118,7 @@ class Vector2Set(FeatureSet):
117
118
  Class to store set of ``Vector2`` features
118
119
  """
119
120
 
120
- __feature_type__ = "Vector2"
121
+ __feature_class__ = Vector2
121
122
 
122
123
  def __repr__(self):
123
124
  return f"V2({len(self)}) {self.name}"
@@ -141,6 +142,14 @@ class Vector2Set(FeatureSet):
141
142
  """Return array of direction angles"""
142
143
  return np.asarray([e.direction for e in self]).T
143
144
 
145
+ def to_vec2(self):
146
+ """Return ``Vector2Set`` object with all data converted to ``Vector2``."""
147
+ return Vector2Set([Vector2(e) for e in self], name=self.name)
148
+
149
+ def to_dir2(self):
150
+ """Return ``Direction2Set`` object with all data converted to ``Direction``."""
151
+ return Direction2Set([Direction(e) for e in self], name=self.name)
152
+
144
153
  def proj(self, vec):
145
154
  """Return projections of all features in ``Vector2Set`` onto vector."""
146
155
  return type(self)([e.project() for e in self], name=self.name)
@@ -283,7 +292,6 @@ class Vector2Set(FeatureSet):
283
292
  resultant.
284
293
 
285
294
  """
286
- dtype_cls = getattr(sys.modules[__name__], type(self).__feature_type__)
287
295
  v = Vector3Set(self)
288
296
  v_data = list(v)
289
297
  alldone = np.all(v.angle(v.R()) <= 90)
@@ -294,10 +302,10 @@ class Vector2Set(FeatureSet):
294
302
  v_data[ix] = -v_data[ix]
295
303
  v = Vector3Set(v_data)
296
304
  alldone = np.all(v.angle(v.R()) <= 90)
297
- return type(self)([dtype_cls(vec) for vec in v], name=self.name)
305
+ return type(self)([self.__feature_class__(vec) for vec in v], name=self.name)
298
306
 
299
307
  @classmethod
300
- def from_direction(cls, angles, name="Default"):
308
+ def from_directions(cls, angles, name="Default"):
301
309
  """Create ``Vector2Set`` object from arrays of direction angles
302
310
 
303
311
  Args:
@@ -309,8 +317,7 @@ class Vector2Set(FeatureSet):
309
317
  Example:
310
318
  >>> f = vec2set.from_angles([120,130,140,125, 132. 131])
311
319
  """
312
- dtype_cls = getattr(sys.modules[__name__], cls.__feature_type__)
313
- return cls([dtype_cls(a) for a in angles], name=name)
320
+ return cls([cls.__feature_class__(a) for a in angles], name=name)
314
321
 
315
322
  @classmethod
316
323
  def from_xy(cls, x, y, name="Default"):
@@ -327,8 +334,7 @@ class Vector2Set(FeatureSet):
327
334
  >>> v = vec2set.from_xy([-0.4330127, -0.4330127, -0.66793414],
328
335
  [0.75, 0.25, 0.60141061])
329
336
  """
330
- dtype_cls = getattr(sys.modules[__name__], cls.__feature_type__)
331
- return cls([dtype_cls(xx, yy) for xx, yy in zip(x, y)], name=name)
337
+ return cls([cls.__feature_class__(xx, yy) for xx, yy in zip(x, y)], name=name)
332
338
 
333
339
  @classmethod
334
340
  def random(cls, n=100, name="Default"):
@@ -344,8 +350,7 @@ class Vector2Set(FeatureSet):
344
350
  >>> l = vec2set.random(100)
345
351
 
346
352
  """
347
- dtype_cls = getattr(sys.modules[__name__], cls.__feature_type__)
348
- return cls([dtype_cls.random() for i in range(n)], name=name)
353
+ return cls([cls.__feature_class__.random() for i in range(n)], name=name)
349
354
 
350
355
  @classmethod
351
356
  def random_vonmises(cls, n=100, position=0, kappa=5, name="Default"):
@@ -361,9 +366,19 @@ class Vector2Set(FeatureSet):
361
366
  Example:
362
367
  >>> l = linset.random_fisher(position=lin(120,50))
363
368
  """
364
- dtype_cls = getattr(sys.modules[__name__], cls.__feature_type__)
365
369
  angles = np.degrees(vonmises.rvs(kappa, loc=np.radians(position), size=n))
366
- return cls([dtype_cls(a) for a in angles], name=name)
370
+ return cls([cls.__feature_class__(a) for a in angles], name=name)
371
+
372
+
373
+ class Direction2Set(Vector2Set):
374
+ """
375
+ Class to store set of ``Direction`` features
376
+ """
377
+
378
+ __feature_class__ = Direction
379
+
380
+ def __repr__(self):
381
+ return f"D2({len(self)}) {self.name}"
367
382
 
368
383
 
369
384
  class Vector3Set(FeatureSet):
@@ -371,7 +386,7 @@ class Vector3Set(FeatureSet):
371
386
  Class to store set of ``Vector3`` features
372
387
  """
373
388
 
374
- __feature_type__ = "Vector3"
389
+ __feature_class__ = Vector3
375
390
 
376
391
  def __repr__(self):
377
392
  return f"V3({len(self)}) {self.name}"
@@ -597,7 +612,6 @@ class Vector3Set(FeatureSet):
597
612
  resultant.
598
613
 
599
614
  """
600
- dtype_cls = getattr(sys.modules[__name__], type(self).__feature_type__)
601
615
  v = Vector3Set(self)
602
616
  v_data = list(v)
603
617
  alldone = np.all(v.angle(v.R()) <= 90)
@@ -608,7 +622,7 @@ class Vector3Set(FeatureSet):
608
622
  v_data[ix] = -v_data[ix]
609
623
  v = Vector3Set(v_data)
610
624
  alldone = np.all(v.angle(v.R()) <= 90)
611
- return type(self)([dtype_cls(vec) for vec in v], name=self.name)
625
+ return type(self)([self.__feature_class__(vec) for vec in v], name=self.name)
612
626
 
613
627
  @classmethod
614
628
  def from_csv(cls, filename, acol=0, icol=1):
@@ -627,9 +641,6 @@ class Vector3Set(FeatureSet):
627
641
  >>> gl = linset.from_csv('file2.csv', acol=1, icol=2) #doctest: +SKIP
628
642
 
629
643
  """
630
- from os.path import basename
631
- import csv
632
-
633
644
  with open(filename) as csvfile:
634
645
  has_header = csv.Sniffer().has_header(csvfile.read(1024))
635
646
  csvfile.seek(0)
@@ -665,7 +676,6 @@ class Vector3Set(FeatureSet):
665
676
  Note: Written values are rounded according to `ndigits` settings in apsg_conf
666
677
 
667
678
  """
668
- import csv
669
679
 
670
680
  n = apsg_conf["ndigits"]
671
681
 
@@ -692,8 +702,9 @@ class Vector3Set(FeatureSet):
692
702
  >>> f = folset.from_array([120,130,140], [10,20,30])
693
703
  >>> l = linset.from_array([120,130,140], [10,20,30])
694
704
  """
695
- dtype_cls = getattr(sys.modules[__name__], cls.__feature_type__)
696
- return cls([dtype_cls(azi, inc) for azi, inc in zip(azis, incs)], name=name)
705
+ return cls(
706
+ [cls.__feature_class__(azi, inc) for azi, inc in zip(azis, incs)], name=name
707
+ )
697
708
 
698
709
  @classmethod
699
710
  def from_xyz(cls, x, y, z, name="Default"):
@@ -712,8 +723,10 @@ class Vector3Set(FeatureSet):
712
723
  [0.75, 0.25, 0.60141061],
713
724
  [0.5, 0.8660254, 0.43837115])
714
725
  """
715
- dtype_cls = getattr(sys.modules[__name__], cls.__feature_type__)
716
- return cls([dtype_cls(xx, yy, zz) for xx, yy, zz in zip(x, y, z)], name=name)
726
+ return cls(
727
+ [cls.__feature_class__(xx, yy, zz) for xx, yy, zz in zip(x, y, z)],
728
+ name=name,
729
+ )
717
730
 
718
731
  @classmethod
719
732
  def random_normal(cls, n=100, position=Vector3(0, 0, 1), sigma=20, name="Default"):
@@ -733,7 +746,6 @@ class Vector3Set(FeatureSet):
733
746
 
734
747
  """
735
748
  data = []
736
- dtype_cls = getattr(sys.modules[__name__], cls.__feature_type__)
737
749
  orig = Vector3(0, 0, 1)
738
750
  ax = orig.cross(position)
739
751
  ang = orig.angle(position)
@@ -742,7 +754,7 @@ class Vector3Set(FeatureSet):
742
754
  np.random.normal(loc=0, scale=sigma, size=n),
743
755
  ):
744
756
  v = orig.rotate(Vector3(s, 0), r).rotate(ax, ang)
745
- data.append(dtype_cls(v))
757
+ data.append(cls.__feature_class__(v))
746
758
  return cls(data, name=name)
747
759
 
748
760
  @classmethod
@@ -759,9 +771,8 @@ class Vector3Set(FeatureSet):
759
771
  Example:
760
772
  >>> l = linset.random_fisher(position=lin(120,50))
761
773
  """
762
- dtype_cls = getattr(sys.modules[__name__], cls.__feature_type__)
763
774
  dc = vonMisesFisher(position, kappa, n)
764
- return cls([dtype_cls(d) for d in dc], name=name)
775
+ return cls([cls.__feature_class__(d) for d in dc], name=name)
765
776
 
766
777
  @classmethod
767
778
  def random_fisher2(cls, n=100, position=Vector3(0, 0, 1), kappa=20, name="Default"):
@@ -807,11 +818,10 @@ class Vector3Set(FeatureSet):
807
818
  >>> l = linset.random_kent(p, n=300, kappa=30)
808
819
  """
809
820
  assert issubclass(type(p), Pair), "Argument must be Pair object."
810
- dtype_cls = getattr(sys.modules[__name__], cls.__feature_type__)
811
821
  if beta is None:
812
822
  beta = kappa / 2
813
823
  kd = KentDistribution(p.lvec, p.fvec.cross(p.lvec), p.fvec, kappa, beta)
814
- return cls([dtype_cls(d) for d in kd.rvs(n)], name=name)
824
+ return cls([cls.__feature_class__(d) for d in kd.rvs(n)], name=name)
815
825
 
816
826
  @classmethod
817
827
  def uniform_sfs(cls, n=100, name="Default"):
@@ -830,14 +840,13 @@ class Vector3Set(FeatureSet):
830
840
  >>> v.ortensor().eigenvalues()
831
841
  (0.3334645347163635, 0.33333474915201167, 0.33320071613162483)
832
842
  """
833
- dtype_cls = getattr(sys.modules[__name__], cls.__feature_type__)
834
843
  phi = (1 + np.sqrt(5)) / 2
835
844
  i2 = 2 * np.arange(n) - n + 1
836
845
  theta = 2 * np.pi * i2 / phi
837
846
  sp = i2 / n
838
847
  cp = np.sqrt((n + i2) * (n - i2)) / n
839
848
  dc = np.array([cp * np.sin(theta), cp * np.cos(theta), sp]).T
840
- return cls([dtype_cls(d) for d in dc], name=name)
849
+ return cls([cls.__feature_class__(d) for d in dc], name=name)
841
850
 
842
851
  @classmethod
843
852
  def uniform_gss(cls, n=100, name="Default"):
@@ -855,7 +864,6 @@ class Vector3Set(FeatureSet):
855
864
  >>> v.ortensor().eigenvalues()
856
865
  (0.33335688569571587, 0.33332315115436933, 0.33331996314991513)
857
866
  """
858
- dtype_cls = getattr(sys.modules[__name__], cls.__feature_type__)
859
867
  inc = np.pi * (3 - np.sqrt(5))
860
868
  off = 2 / n
861
869
  k = np.arange(n)
@@ -863,7 +871,7 @@ class Vector3Set(FeatureSet):
863
871
  r = np.sqrt(1 - y * y)
864
872
  phi = k * inc
865
873
  dc = np.array([np.cos(phi) * r, y, np.sin(phi) * r]).T
866
- return cls([dtype_cls(d) for d in dc], name=name)
874
+ return cls([cls.__feature_class__(d) for d in dc], name=name)
867
875
 
868
876
 
869
877
  class LineationSet(Vector3Set):
@@ -871,7 +879,7 @@ class LineationSet(Vector3Set):
871
879
  Class to store set of ``Lineation`` features
872
880
  """
873
881
 
874
- __feature_type__ = "Lineation"
882
+ __feature_class__ = Lineation
875
883
 
876
884
  def __repr__(self):
877
885
  return f"L({len(self)}) {self.name}"
@@ -882,7 +890,7 @@ class FoliationSet(Vector3Set):
882
890
  Class to store set of ``Foliation`` features
883
891
  """
884
892
 
885
- __feature_type__ = "Foliation"
893
+ __feature_class__ = Foliation
886
894
 
887
895
  def __repr__(self):
888
896
  return f"S({len(self)}) {self.name}"
@@ -897,7 +905,7 @@ class PairSet(FeatureSet):
897
905
  Class to store set of ``Pair`` features
898
906
  """
899
907
 
900
- __feature_type__ = "Pair"
908
+ __feature_class__ = Pair
901
909
 
902
910
  def __repr__(self):
903
911
  return f"P({len(self)}) {self.name}"
@@ -995,9 +1003,6 @@ class PairSet(FeatureSet):
995
1003
  def from_csv(cls, filename, delimiter=",", facol=0, ficol=1, lacol=2, licol=3):
996
1004
  """Read ``PairSet`` from csv file"""
997
1005
 
998
- from os.path import basename
999
- import csv
1000
-
1001
1006
  with open(filename) as csvfile:
1002
1007
  has_header = csv.Sniffer().has_header(csvfile.read(1024))
1003
1008
  csvfile.seek(0)
@@ -1063,7 +1068,6 @@ class PairSet(FeatureSet):
1063
1068
  Note: Written values are rounded according to `ndigits` settings in apsg_conf
1064
1069
 
1065
1070
  """
1066
- import csv
1067
1071
 
1068
1072
  n = apsg_conf["ndigits"]
1069
1073
 
@@ -1095,10 +1099,9 @@ class PairSet(FeatureSet):
1095
1099
  name: name of ``PairSet`` object. Default is 'Default'
1096
1100
  """
1097
1101
 
1098
- dtype_cls = getattr(sys.modules[__name__], cls.__feature_type__)
1099
1102
  return cls(
1100
1103
  [
1101
- dtype_cls(fazi, finc, lazi, linc)
1104
+ cls.__feature_class__(fazi, finc, lazi, linc)
1102
1105
  for fazi, finc, lazi, linc in zip(fazis, fincs, lazis, lincs)
1103
1106
  ],
1104
1107
  name=name,
@@ -1110,7 +1113,7 @@ class FaultSet(PairSet):
1110
1113
  Class to store set of ``Fault`` features
1111
1114
  """
1112
1115
 
1113
- __feature_type__ = "Fault"
1116
+ __feature_class__ = Fault
1114
1117
 
1115
1118
  def __repr__(self):
1116
1119
  return f"F({len(self)}) {self.name}"
@@ -1120,6 +1123,11 @@ class FaultSet(PairSet):
1120
1123
  """Return array of sense values"""
1121
1124
  return np.array([f.sense for f in self])
1122
1125
 
1126
+ @property
1127
+ def sense_str(self):
1128
+ """Return array of sense characters"""
1129
+ return np.array([f.sense_str for f in self])
1130
+
1123
1131
  @property
1124
1132
  def p_vector(self, ptangle=90):
1125
1133
  """Return p-axes of FaultSet as Vector3Set"""
@@ -1196,13 +1204,18 @@ class FaultSet(PairSet):
1196
1204
 
1197
1205
  @classmethod
1198
1206
  def from_csv(
1199
- cls, filename, delimiter=",", facol=0, ficol=1, lacol=2, licol=3, scol=4
1207
+ cls,
1208
+ filename,
1209
+ delimiter=",",
1210
+ sense_str=False,
1211
+ facol=0,
1212
+ ficol=1,
1213
+ lacol=2,
1214
+ licol=3,
1215
+ scol=4,
1200
1216
  ):
1201
1217
  """Read ``FaultSet`` from csv file"""
1202
1218
 
1203
- from os.path import basename
1204
- import csv
1205
-
1206
1219
  with open(filename) as csvfile:
1207
1220
  has_header = csv.Sniffer().has_header(csvfile.read(1024))
1208
1221
  csvfile.seek(0)
@@ -1220,48 +1233,73 @@ class FaultSet(PairSet):
1220
1233
  faname, finame = reader.fieldnames[facol], reader.fieldnames[ficol]
1221
1234
  laname, liname = reader.fieldnames[lacol], reader.fieldnames[licol]
1222
1235
  sname = reader.fieldnames[scol]
1223
- r = [
1224
- (
1225
- float(row[faname]),
1226
- float(row[finame]),
1227
- float(row[laname]),
1228
- float(row[liname]),
1229
- int(row[sname]),
1230
- )
1231
- for row in reader
1232
- ]
1236
+ if sense_str:
1237
+ r = [
1238
+ (
1239
+ float(row[faname]),
1240
+ float(row[finame]),
1241
+ float(row[laname]),
1242
+ float(row[liname]),
1243
+ row[sname],
1244
+ )
1245
+ for row in reader
1246
+ ]
1247
+ else:
1248
+ r = [
1249
+ (
1250
+ float(row[faname]),
1251
+ float(row[finame]),
1252
+ float(row[laname]),
1253
+ float(row[liname]),
1254
+ int(row[sname]),
1255
+ )
1256
+ for row in reader
1257
+ ]
1233
1258
  else:
1234
1259
  reader = csv.reader(csvfile, dialect=dialect)
1260
+
1235
1261
  r = [
1236
1262
  (
1237
1263
  float(row[facol]),
1238
1264
  float(row[ficol]),
1239
1265
  float(row[lacol]),
1240
1266
  float(row[licol]),
1241
- int(row[scol]),
1267
+ row[scol],
1242
1268
  )
1243
1269
  for row in reader
1244
1270
  ]
1245
1271
  else:
1246
1272
  if has_header:
1247
1273
  reader = csv.DictReader(csvfile, dialect=dialect)
1248
- r = [
1249
- (
1250
- float(row[facol]),
1251
- float(row[ficol]),
1252
- float(row[lacol]),
1253
- float(row[licol]),
1254
- int(row[scol]),
1255
- )
1256
- for row in reader
1257
- ]
1274
+ if sense_str:
1275
+ r = [
1276
+ (
1277
+ float(row[facol]),
1278
+ float(row[ficol]),
1279
+ float(row[lacol]),
1280
+ float(row[licol]),
1281
+ row[scol],
1282
+ )
1283
+ for row in reader
1284
+ ]
1285
+ else:
1286
+ r = [
1287
+ (
1288
+ float(row[facol]),
1289
+ float(row[ficol]),
1290
+ float(row[lacol]),
1291
+ float(row[licol]),
1292
+ int(row[scol]),
1293
+ )
1294
+ for row in reader
1295
+ ]
1258
1296
  else:
1259
1297
  raise ValueError("No header line in CSV file...")
1260
1298
 
1261
1299
  fazi, finc, lazi, linc, sense = zip(*r)
1262
1300
  return cls.from_array(fazi, finc, lazi, linc, sense, name=basename(filename))
1263
1301
 
1264
- def to_csv(self, filename, delimiter=","):
1302
+ def to_csv(self, filename, delimiter=",", sense_str=False):
1265
1303
  """Save ``FaultSet`` object to csv file
1266
1304
 
1267
1305
  Args:
@@ -1269,11 +1307,11 @@ class FaultSet(PairSet):
1269
1307
 
1270
1308
  Keyword Args:
1271
1309
  delimiter (str): values delimiter. Default ','
1310
+ sense_str (bool): save sense as N, R, S or D. Default False
1272
1311
 
1273
1312
  Note: Written values are rounded according to `ndigits` settings in apsg_conf
1274
1313
 
1275
1314
  """
1276
- import csv
1277
1315
 
1278
1316
  n = apsg_conf["ndigits"]
1279
1317
 
@@ -1284,19 +1322,30 @@ class FaultSet(PairSet):
1284
1322
  for dt in self:
1285
1323
  fazi, finc = dt.fol.geo
1286
1324
  lazi, linc = dt.lin.geo
1287
- writer.writerow(
1288
- {
1289
- "fazi": round(fazi, n),
1290
- "finc": round(finc, n),
1291
- "lazi": round(lazi, n),
1292
- "linc": round(linc, n),
1293
- "sense": dt.sense,
1294
- }
1295
- )
1325
+ if sense_str:
1326
+ writer.writerow(
1327
+ {
1328
+ "fazi": round(fazi, n),
1329
+ "finc": round(finc, n),
1330
+ "lazi": round(lazi, n),
1331
+ "linc": round(linc, n),
1332
+ "sense": dt.sense_str,
1333
+ }
1334
+ )
1335
+ else:
1336
+ writer.writerow(
1337
+ {
1338
+ "fazi": round(fazi, n),
1339
+ "finc": round(finc, n),
1340
+ "lazi": round(lazi, n),
1341
+ "linc": round(linc, n),
1342
+ "sense": dt.sense,
1343
+ }
1344
+ )
1296
1345
 
1297
1346
  @classmethod
1298
1347
  def from_array(cls, fazis, fincs, lazis, lincs, senses, name="Default"):
1299
- """Create ``PairSet`` from arrays of azimuths and inclinations
1348
+ """Create ``FaultSet`` from arrays of azimuths, inclinations and senses
1300
1349
 
1301
1350
  Args:
1302
1351
  azis: list or array of azimuths
@@ -1306,10 +1355,9 @@ class FaultSet(PairSet):
1306
1355
  name: name of ``PairSet`` object. Default is 'Default'
1307
1356
  """
1308
1357
 
1309
- dtype_cls = getattr(sys.modules[__name__], cls.__feature_type__)
1310
1358
  return cls(
1311
1359
  [
1312
- dtype_cls(fazi, finc, lazi, linc, sense)
1360
+ cls.__feature_class__(fazi, finc, lazi, linc, sense)
1313
1361
  for fazi, finc, lazi, linc, sense in zip(
1314
1362
  fazis, fincs, lazis, lincs, senses
1315
1363
  )
@@ -1323,7 +1371,7 @@ class ConeSet(FeatureSet):
1323
1371
  Class to store set of ``Cone`` features
1324
1372
  """
1325
1373
 
1326
- __feature_type__ = "Cone"
1374
+ __feature_class__ = Cone
1327
1375
 
1328
1376
  def __repr__(self):
1329
1377
  return f"C({len(self)}) {self.name}"
@@ -1334,7 +1382,7 @@ class EllipseSet(FeatureSet):
1334
1382
  Class to store set of ``Ellipse`` features
1335
1383
  """
1336
1384
 
1337
- __feature_type__ = "Ellipse"
1385
+ __feature_class__ = Ellipse
1338
1386
 
1339
1387
  @property
1340
1388
  def S1(self) -> np.ndarray:
@@ -1391,7 +1439,7 @@ class OrientationTensor2Set(EllipseSet):
1391
1439
  Class to store set of ``OrientationTensor2`` features
1392
1440
  """
1393
1441
 
1394
- __feature_type__ = "OrientationTensor2"
1442
+ __feature_class__ = OrientationTensor2
1395
1443
 
1396
1444
 
1397
1445
  class EllipsoidSet(FeatureSet):
@@ -1399,7 +1447,7 @@ class EllipsoidSet(FeatureSet):
1399
1447
  Class to store set of ``Ellipsoid`` features
1400
1448
  """
1401
1449
 
1402
- __feature_type__ = "Ellipsoid"
1450
+ __feature_class__ = Ellipsoid
1403
1451
 
1404
1452
  @property
1405
1453
  def strength(self) -> np.ndarray:
@@ -1633,7 +1681,7 @@ class OrientationTensor3Set(EllipsoidSet):
1633
1681
  Class to store set of ``OrientationTensor3`` features
1634
1682
  """
1635
1683
 
1636
- __feature_type__ = "OrientationTensor3"
1684
+ __feature_class__ = OrientationTensor3
1637
1685
 
1638
1686
 
1639
1687
  class ClusterSet(object):
@@ -1660,7 +1708,7 @@ class ClusterSet(object):
1660
1708
  isinstance(d, Vector2Set)
1661
1709
  or isinstance(d, Vector3Set)
1662
1710
  or isinstance(d, PairSet)
1663
- ), "Only vec2set or vecset could be clustered"
1711
+ ), "Only vec2set, vecset and pairset could be clustered"
1664
1712
  self.data = d.copy()
1665
1713
  self.maxclust = kwargs.get("maxclust", 2)
1666
1714
  self.angle = kwargs.get("angle", None)
@@ -1712,7 +1760,10 @@ class ClusterSet(object):
1712
1760
  """
1713
1761
 
1714
1762
  self.method = kwargs.get("method", self.method)
1715
- self.Z = linkage(self.pdist, method=self.method, metric=angle_metric)
1763
+ if issubclass(self.data.__feature_class__, (Axial2, Axial3)):
1764
+ self.Z = linkage(self.pdist, method=self.method, metric=angle_metric_axial)
1765
+ else:
1766
+ self.Z = linkage(self.pdist, method=self.method, metric=angle_metric)
1716
1767
 
1717
1768
  def dendrogram(self, **kwargs):
1718
1769
  """Show dendrogram
@@ -1805,4 +1856,8 @@ def G(lst, name="Default"):
1805
1856
 
1806
1857
 
1807
1858
  def angle_metric(u, v):
1859
+ return np.degrees(np.arccos(np.dot(u, v)))
1860
+
1861
+
1862
+ def angle_metric_axial(u, v):
1808
1863
  return np.degrees(np.arccos(np.abs(np.dot(u, v))))
apsg/feature/_geodata.py CHANGED
@@ -1,15 +1,50 @@
1
1
  import warnings
2
+
2
3
  import numpy as np
3
4
 
5
+ from apsg.decorator._decorator import ensure_arguments, ensure_first_arg_same
4
6
  from apsg.helpers._notation import (
5
7
  geo2vec_planar,
6
- vec2geo_planar,
7
- vec2geo_planar_signed,
8
8
  vec2geo_linear,
9
9
  vec2geo_linear_signed,
10
+ vec2geo_planar,
11
+ vec2geo_planar_signed,
10
12
  )
11
- from apsg.decorator._decorator import ensure_first_arg_same, ensure_arguments
12
- from apsg.math._vector import Vector3, Axial3
13
+ from apsg.math._vector import Axial2, Axial3, Vector3
14
+
15
+
16
+ class Direction(Axial2):
17
+ """
18
+ A class to represent axial (non-oriented) 2D linear feature (direction).
19
+
20
+ There are different way to create ``Direction`` object:
21
+
22
+ - without arguments create default ``Direction`` D:0
23
+ - with single argument `d`, where:
24
+
25
+ - `d` could be Vector2-like object
26
+ - `d` could be string 'x' or 'y' - principal axes of coordinate system
27
+ - `d` could be tuple of (x, y) - vector components
28
+ - with 1 argument direction
29
+ - with 2 numerical arguments defining vector components
30
+
31
+ Args:
32
+ direction (float): plunge direction of linear feature in degrees
33
+
34
+ Example:
35
+ >>> dir2()
36
+ >>> dir2('y')
37
+ >>> dir2(45)
38
+ >>> d = dir2(1, -1)
39
+ """
40
+
41
+ def __repr__(self):
42
+ return f"D:{self.direction:.0f}"
43
+
44
+ def to_json(self):
45
+ """Return as JSON dict"""
46
+ azi, inc = vec2geo_linear_signed(self)
47
+ return {"datatype": type(self).__name__, "args": (azi, inc)}
13
48
 
14
49
 
15
50
  class Lineation(Axial3):
@@ -446,15 +481,15 @@ class Fault(Pair):
446
481
  elif isinstance(sense, str):
447
482
  p = Pair(fvec, lvec)
448
483
  if sense.lower() == "s":
449
- if p.rax == p.rax.lower():
450
- res = -1
451
- else:
452
- res = 1
453
- elif sense.lower() == "d":
454
- if p.rax == p.rax.lower():
484
+ if p.rax.is_upper():
455
485
  res = 1
456
486
  else:
457
487
  res = -1
488
+ elif sense.lower() == "d":
489
+ if p.rax.is_upper():
490
+ res = -1
491
+ else:
492
+ res = 1
458
493
  elif sense.lower() == "n":
459
494
  res = 1
460
495
  elif sense.lower() == "r":
@@ -464,7 +499,8 @@ class Fault(Pair):
464
499
  def __repr__(self):
465
500
  fazi, finc = self.fol.geo
466
501
  lazi, linc = self.lin.geo
467
- schar = [" ", "+", "-"][self.sense]
502
+ schar = self.sense_str
503
+ # schar = [" ", "+", "-"][self.sense]
468
504
  return f"F:{fazi:.0f}/{finc:.0f}-{lazi:.0f}/{linc:.0f} {schar}"
469
505
 
470
506
  @ensure_first_arg_same
@@ -519,6 +555,24 @@ class Fault(Pair):
519
555
  else:
520
556
  return -1
521
557
 
558
+ @property
559
+ def sense_str(self):
560
+ if abs(self.rax.geo[1]) > 75:
561
+ if self.rax.z > 0:
562
+ schar = "D"
563
+ elif self.rax.z < 0:
564
+ schar = "S"
565
+ else:
566
+ schar = " "
567
+ else:
568
+ if self.sense < 0:
569
+ schar = "R"
570
+ elif self.sense > 0:
571
+ schar = "N"
572
+ else:
573
+ schar = " "
574
+ return schar
575
+
522
576
  def p_vector(self, ptangle=90):
523
577
  """Return P axis as ``Vector3``"""
524
578
  return self.fvec.rotate(self.lvec.cross(self.fvec), -ptangle / 2)
apsg/feature/_tensor3.py CHANGED
@@ -440,6 +440,30 @@ class Stress3(Tensor3):
440
440
 
441
441
  return cls([[xx, xy, xz], [xy, yy, yz], [xz, yz, zz]])
442
442
 
443
+ @classmethod
444
+ def from_ratio(cls, r=0.5, mag=1):
445
+ """
446
+ Return ``Stress`` tensor with given shape ration.
447
+
448
+ Keyword Args:
449
+ r (float): shape ratio between 0 and 1. Default 0.5
450
+ mag (float): magnitude of differential stress. Default 1.
451
+
452
+ Example:
453
+ >>> S = stress.from_ratio(r=0.25, mag=10)
454
+ >>> S
455
+ Stress3
456
+ [[-5. 0. 0. ]
457
+ [ 0. -2.5 0. ]
458
+ [ 0. 0. 5. ]]
459
+
460
+ """
461
+
462
+ xx = -mag / 2
463
+ yy = xx + r * mag
464
+ zz = mag / 2
465
+ return cls([[xx, 0, 0], [0, yy, 0], [0, 0, zz]])
466
+
443
467
  @property
444
468
  def mean_stress(self):
445
469
  """
apsg/math/_matrix.py CHANGED
@@ -4,10 +4,6 @@ from apsg.config import apsg_conf
4
4
  from apsg.decorator._decorator import ensure_first_arg_same
5
5
  from apsg.math._vector import Vector3, Vector2
6
6
 
7
- """
8
- TO BE ADDED
9
- """
10
-
11
7
 
12
8
  class Matrix:
13
9
  """Base class for Matrix2 and Matrix3"""
@@ -128,7 +124,7 @@ class Matrix:
128
124
  return self._coefs[1][1]
129
125
 
130
126
  @property
131
- def I(self):
127
+ def I(self): # noqa: E743
132
128
  return type(self)(np.linalg.inv(self))
133
129
 
134
130
  @property
@@ -1,12 +1,13 @@
1
1
  import pickle
2
2
 
3
- import numpy as np
4
3
  import matplotlib.pyplot as plt
5
- from scipy.stats import vonmises, circmean
4
+ import numpy as np
5
+ from scipy.stats import circmean, vonmises
6
6
 
7
7
  from apsg.config import apsg_conf
8
- from apsg.plotting._plot_artists import RosePlotArtistFactory
9
8
  from apsg.feature import feature_from_json
9
+ from apsg.math._vector import Axial2, Axial3
10
+ from apsg.plotting._plot_artists import RosePlotArtistFactory
10
11
 
11
12
  __all__ = ["RosePlot"]
12
13
 
@@ -20,7 +21,6 @@ class RosePlot(object):
20
21
  title_kws (dict): dictionary of keyword arguments passed to matplotlib suptitle
21
22
  method.
22
23
  bins (int): Number of bins. Default 36
23
- axial (bool): Directional data are axial. Defaut True
24
24
  density (bool): Use density instead of counts. Default False
25
25
  pdf (bool): Plot Von Mises density function instead histogram. Default False
26
26
  pdf_res (int): Resolution of pdf. Default 901
@@ -245,7 +245,7 @@ class RosePlot(object):
245
245
  width = 2 * np.pi / self._kwargs["bins"]
246
246
  legend = kwargs.pop("legend")
247
247
  for arg in args:
248
- if self._kwargs["axial"]:
248
+ if issubclass(arg.__feature_class__, (Axial2, Axial3)):
249
249
  ang = np.concatenate((arg.direction % 360, (arg.direction + 180) % 360))
250
250
  weights = np.concatenate((abs(arg), abs(arg)))
251
251
  else:
@@ -279,7 +279,7 @@ class RosePlot(object):
279
279
  ang = arg.direction % 360
280
280
  # weights = abs(arg)
281
281
  radii = np.zeros_like(theta)
282
- if self._kwargs["axial"]:
282
+ if issubclass(arg.__feature_class__, (Axial2, Axial3)):
283
283
  for a in ang:
284
284
  radii += (
285
285
  vonmises.pdf(theta, self._kwargs["kappa"], loc=np.radians(a))
@@ -308,32 +308,21 @@ class RosePlot(object):
308
308
  bottom = bottom + radii
309
309
 
310
310
  def _muci(self, *args, **kwargs):
311
- ang = np.radians(np.concatenate([arg.direction for arg in args]))
312
311
  conflevel = kwargs.pop("confidence_level")
313
312
  n_resamples = kwargs.pop("n_resamples")
314
- # calculate mean and CI
315
- if self._kwargs["axial"]:
316
- mu = circmean(2 * ang) / 2
317
- ang_shift = ang + np.pi / 2 - mu
318
- bsmu = [
319
- circmean(np.random.choice(2 * ang_shift, size=len(ang_shift)))
320
- for i in range(n_resamples)
321
- ]
322
- low = np.percentile(bsmu, 100 - conflevel) / 2 + mu - np.pi / 2
323
- high = np.percentile(bsmu, conflevel) / 2 + mu - np.pi / 2
324
- else:
325
- mu = circmean(ang)
326
- ang_shift = ang + np.pi - mu
327
- bsmu = [
328
- circmean(np.random.choice(ang_shift, size=len(ang_shift)))
329
- for i in range(n_resamples)
330
- ]
331
- low = np.percentile(bsmu, (100 - conflevel) / 2) + mu - np.pi
332
- high = np.percentile(bsmu, 100 - (100 - conflevel) / 2) + mu - np.pi
333
- radii = []
334
313
  for arg in args:
314
+ radii = []
335
315
  p = 0
336
- if self._kwargs["axial"]:
316
+ ang = np.radians(arg.direction)
317
+ if issubclass(arg.__feature_class__, (Axial2, Axial3)):
318
+ mu = circmean(2 * ang) / 2
319
+ ang_shift = ang + np.pi / 2 - mu
320
+ bsmu = [
321
+ circmean(np.random.choice(2 * ang_shift, size=len(ang_shift)))
322
+ for i in range(n_resamples)
323
+ ]
324
+ low = np.percentile(bsmu, 100 - conflevel) / 2 + mu - np.pi / 2
325
+ high = np.percentile(bsmu, conflevel) / 2 + mu - np.pi / 2
337
326
  for a in arg.direction:
338
327
  p += vonmises.pdf(mu, self._kwargs["kappa"], loc=np.radians(a)) / 2
339
328
  p += (
@@ -341,16 +330,28 @@ class RosePlot(object):
341
330
  / 2
342
331
  )
343
332
  else:
333
+ mu = circmean(ang)
334
+ ang_shift = ang + np.pi - mu
335
+ bsmu = [
336
+ circmean(np.random.choice(ang_shift, size=len(ang_shift)))
337
+ for i in range(n_resamples)
338
+ ]
339
+ low = np.percentile(bsmu, (100 - conflevel) / 2) + mu - np.pi
340
+ high = np.percentile(bsmu, 100 - (100 - conflevel) / 2) + mu - np.pi
344
341
  for a in arg.direction:
345
342
  p += vonmises.pdf(mu, self._kwargs["kappa"], loc=np.radians(a))
346
343
  radii.append(p / len(arg))
347
- if self._kwargs["scaled"]:
348
- radii = np.sqrt(radii)
349
- mur = 1.1 * sum(radii)
350
- ci_angles = np.linspace(low, high, int(5 * np.degrees(high - low)))
351
- self.ax.plot([mu, mu + np.pi], [mur, mur], **kwargs)
352
- self.ax.plot(ci_angles, mur * np.ones_like(ci_angles), **kwargs)
353
- self.ax.plot(ci_angles + np.pi, mur * np.ones_like(ci_angles), **kwargs)
344
+ if self._kwargs["scaled"]:
345
+ radii = np.sqrt(radii)
346
+ mur = 1.1 * sum(radii)
347
+ ci_angles = np.linspace(low, high, int(5 * np.degrees(high - low)))
348
+ if issubclass(arg.__feature_class__, (Axial2, Axial3)):
349
+ self.ax.plot([mu, mu + np.pi], [mur, mur], **kwargs)
350
+ self.ax.plot(ci_angles, mur * np.ones_like(ci_angles), **kwargs)
351
+ self.ax.plot(ci_angles + np.pi, mur * np.ones_like(ci_angles), **kwargs)
352
+ else:
353
+ self.ax.plot([0, mu], [0, mur], **kwargs)
354
+ self.ax.plot(ci_angles, mur * np.ones_like(ci_angles), **kwargs)
354
355
 
355
356
 
356
357
  def roseartist_from_json(obj_json):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: apsg
3
- Version: 1.3.4
3
+ Version: 1.3.6
4
4
  Summary: APSG - The package for structural geologists
5
5
  Author-email: Ondrej Lexa <lexa.ondrej@gmail.com>
6
6
  Maintainer-email: Ondrej Lexa <lexa.ondrej@gmail.com>
@@ -59,14 +59,8 @@ Requires-Dist: ipykernel; extra == "docs"
59
59
  Requires-Dist: nbsphinx; extra == "docs"
60
60
  Requires-Dist: autodocsumm; extra == "docs"
61
61
  Provides-Extra: dev
62
- Requires-Dist: pytest; extra == "dev"
62
+ Requires-Dist: apsg[docs,extra,tests]; extra == "dev"
63
63
  Requires-Dist: black; extra == "dev"
64
- Requires-Dist: sphinx; extra == "dev"
65
- Requires-Dist: sphinx_rtd_theme; extra == "dev"
66
- Requires-Dist: readthedocs-sphinx-search; extra == "dev"
67
- Requires-Dist: ipykernel; extra == "dev"
68
- Requires-Dist: nbsphinx; extra == "dev"
69
- Requires-Dist: autodocsumm; extra == "dev"
70
64
  Dynamic: license-file
71
65
 
72
66
  <img src="https://ondrolexa.github.io/apsg/apsg_banner.svg" alt="APSG logo" width="300px"/>
@@ -1,24 +1,24 @@
1
- apsg/__init__.py,sha256=-6B9IAuTnyKs_jwpjcUz4lRL5QvrcH1pzUyazuh5gwc,1966
2
- apsg/config.py,sha256=X3_yXT96xXlVxFA94EfYFKJbrcGIHT0PvB9s8EKmYOg,4569
1
+ apsg/__init__.py,sha256=er5PTmzLPoYoorvyKGhTjeyE6lVsLZr0nB5ariut94o,2849
2
+ apsg/config.py,sha256=vwJZVqWQ2bXe4TNW3hzse-dIam3QBwNeFx5VJUhNjU8,4549
3
3
  apsg/shell.py,sha256=1D0PeB7qXzlpiOf2QYGo6OJlEVN1KJPYld1GEREBiFg,707
4
4
  apsg/database/__init__.py,sha256=7Rvcf1KBBBNhoM28ZlvQ01CkScQTroFkoS4d1kD55Ws,315
5
5
  apsg/database/_alchemy.py,sha256=geV3Q6ZLdGvjzxry7GTHHIQq6t_ccsUxZvuv13CLYFQ,19467
6
- apsg/database/_sdbread.py,sha256=EP0hSp6_4-DZZptkMNDgKnQ3GD58mpr_SAgFohKu6xQ,11017
6
+ apsg/database/_sdbread.py,sha256=lKvImHCFaxXr0wx5FnogVRp6bAPeaP01MDpUn_rH3Ek,11009
7
7
  apsg/decorator/__init__.py,sha256=fZ-dxpldQIk6-2JhVnCj-Tsl8bz2nvoGOyG7uXKvBfg,160
8
8
  apsg/decorator/_decorator.py,sha256=8TMSrcVvhU5UCbNMrnyrW3-65qo20_6N2ShtXd3bP-k,1194
9
- apsg/feature/__init__.py,sha256=XGLq3GXpiWtzX6ROtuSc0kCPJEPTVRoIUtr8VpRZOWI,1664
10
- apsg/feature/_container.py,sha256=2hQtc6a5Z6puwfHcia4AAXsFoD8OuXO-Iqfbq6zRmnw,59283
11
- apsg/feature/_geodata.py,sha256=NJ6jZJbq_-DX2ZLADEf5AMsPzz0T17RLizIq3uH_i7U,22553
9
+ apsg/feature/__init__.py,sha256=XkyS-X8lUaXCVaXgoK0GETmTCCGqB1BmSwZRZG3blZQ,1733
10
+ apsg/feature/_container.py,sha256=7RLkTnEwDDhm6c4jErQOTIPg5KBM46SLpcFlrtyZHvg,60812
11
+ apsg/feature/_geodata.py,sha256=tjgPSKXyEOXiAN3iPeHpm8kpj__jI4ahtTpDuWhQNBE,24008
12
12
  apsg/feature/_paleomag.py,sha256=WIICUOEJGGFHbCDF0gbW7lMt10jI0el0UVhkbMH7XAs,14911
13
13
  apsg/feature/_statistics.py,sha256=WwBU2D7SyIHMpWnO7WFqbIpSkz6KUCT9xkG8oVzgskQ,13916
14
14
  apsg/feature/_tensor2.py,sha256=XzGuSU46RkeVHQu3pqKzgzf0cYZCgbs9eP_yfYa82SU,13451
15
- apsg/feature/_tensor3.py,sha256=Z6mHoQ4Dm_ZokVMlhIUnkvHhZfUHG4VbpIkWHamRY7M,29720
15
+ apsg/feature/_tensor3.py,sha256=uRC-Vi3HFNwOM33wg5r5N8JUwOeKC64PyRV5J9QbSTk,30329
16
16
  apsg/helpers/__init__.py,sha256=6SF_Srq6fS-uomvpwdW0JSQs-tmWnzUoTk4a1K_J1aE,532
17
17
  apsg/helpers/_helper.py,sha256=1Xf1yiNYIEoUJqXH4C0390osGWk6AERr_LrCSTnsRVw,146
18
18
  apsg/helpers/_math.py,sha256=NLHw9UGiSlNggwZB-o0ORpG2sY00qIcbMbDJftRWFE8,896
19
19
  apsg/helpers/_notation.py,sha256=oSxvZdv06eJ5GotS2IwbAJ-8UTZ49z8slqdhUDQJ9e8,2486
20
20
  apsg/math/__init__.py,sha256=qJa4JP79nXn-6Xb7aaZUPWmz0qadmC4F0tGORTOZDVI,211
21
- apsg/math/_matrix.py,sha256=BGFljlkZ7khpoHZkFq-vFwWV7lUiXGAezURuKlN8eTI,10418
21
+ apsg/math/_matrix.py,sha256=4LcafIEdpnJ0yoeoD1bypfeyyVPeDDzSbQKKlF5nerg,10411
22
22
  apsg/math/_vector.py,sha256=mD8kYggfGys-XWtnE90X2ZcTGBtDN49wEAUXQYXj3dI,16587
23
23
  apsg/pandas/__init__.py,sha256=jmlsulHmH9IbErJgSWlJx1J33-v--O5zxSE4kdt6fUI,456
24
24
  apsg/pandas/_pandas_api.py,sha256=MKV7MIhPIeSMH8ryjC858F3MjyB47cA_bAKtlKbFlNc,13576
@@ -27,12 +27,12 @@ apsg/plotting/_fabricplot.py,sha256=yjy3DEhIZfq448FYKnQb3EhqLm9-f-EZHJEamG98k9Q,
27
27
  apsg/plotting/_paleomagplots.py,sha256=Gw-fqYJVjNxTNXLwAiUKnFUBoOTZv2MEd3XACLmQ6AM,2325
28
28
  apsg/plotting/_plot_artists.py,sha256=6S0EKCqYU6rlBxcxcXALTk9PaUK6QL-BgUKmZH8tkMc,21059
29
29
  apsg/plotting/_projection.py,sha256=ix67PwOU2WGjryEcsHlVIMpcVC9yxy45ycOV9k5x_Q8,11805
30
- apsg/plotting/_roseplot.py,sha256=jbaUXSb3DIcXs0pWAQUTZfdlA2XcbquT0yHLYDjLirQ,12808
30
+ apsg/plotting/_roseplot.py,sha256=Wq5NBCDZMUQWEioIC6hYAZzjDKZsiDIJtjk_vQzzCd8,13104
31
31
  apsg/plotting/_stereogrid.py,sha256=awh7MwN1WgszhOlr6UgR20wHQJ8u778-Tf_w1uflrV4,11869
32
32
  apsg/plotting/_stereonet.py,sha256=uHJXluFMkeaI4yzD9pGc4DIlgjZA01INySLKtUHLAlU,36624
33
- apsg-1.3.4.dist-info/licenses/LICENSE,sha256=lY0kfpVRrzcgVZq7pI6rLK5WYiUMWe0bdKpDelN6hk8,1120
34
- apsg-1.3.4.dist-info/METADATA,sha256=7HV-9ufjlab_qZ0vL3D-Il9UObgVg_FTRUfOZxGmENY,8298
35
- apsg-1.3.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
36
- apsg-1.3.4.dist-info/entry_points.txt,sha256=SowP7_uRI0NJuzznKBXyM9BJcSwBxbXo6Iz5LUo9mEQ,42
37
- apsg-1.3.4.dist-info/top_level.txt,sha256=xWxwi0nqqOyKdmpsszfR-bmqnNpgVbhnLRuIKGJnaUM,5
38
- apsg-1.3.4.dist-info/RECORD,,
33
+ apsg-1.3.6.dist-info/licenses/LICENSE,sha256=lY0kfpVRrzcgVZq7pI6rLK5WYiUMWe0bdKpDelN6hk8,1120
34
+ apsg-1.3.6.dist-info/METADATA,sha256=tD60lfw5Bi1DY0NlsQG6FEnKxv87Bukfz5a-_-jVdks,8047
35
+ apsg-1.3.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
36
+ apsg-1.3.6.dist-info/entry_points.txt,sha256=SowP7_uRI0NJuzznKBXyM9BJcSwBxbXo6Iz5LUo9mEQ,42
37
+ apsg-1.3.6.dist-info/top_level.txt,sha256=xWxwi0nqqOyKdmpsszfR-bmqnNpgVbhnLRuIKGJnaUM,5
38
+ apsg-1.3.6.dist-info/RECORD,,
File without changes