apsg 1.2.1__py2.py3-none-any.whl → 1.2.3__py2.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
@@ -98,6 +98,6 @@ __all__ = (
98
98
  "quicknet",
99
99
  )
100
100
 
101
- __version__ = "1.2.1"
101
+ __version__ = "1.2.2"
102
102
  __author__ = "Ondrej Lexa"
103
103
  __email__ = "lexa.ondrej@gmail.com"
@@ -9,7 +9,7 @@ from apsg.config import apsg_conf
9
9
  from apsg.math._vector import Vector2, Vector3
10
10
  from apsg.helpers._math import acosd
11
11
  from apsg.feature._geodata import Lineation, Foliation, Pair, Fault, Cone
12
- from apsg.feature._tensor3 import OrientationTensor3, Ellipsoid
12
+ from apsg.feature._tensor3 import OrientationTensor3, Ellipsoid, DeformationGradient3
13
13
  from apsg.feature._tensor2 import OrientationTensor2, Ellipse
14
14
  from apsg.feature._statistics import KentDistribution, vonMisesFisher
15
15
 
@@ -48,7 +48,7 @@ class FeatureSet:
48
48
  """Return label"""
49
49
  return self.name
50
50
 
51
- def __array__(self, dtype=None):
51
+ def __array__(self, dtype=None, copy=None):
52
52
  return np.array([np.array(p) for p in self.data], dtype=dtype)
53
53
 
54
54
  def __eq__(self, other):
@@ -84,7 +84,7 @@ class FeatureSet:
84
84
  if isinstance(other, type(self)):
85
85
  return type(self)(self.data + other.data, name=self.name)
86
86
  else:
87
- raise TypeError("Only {self.__name__} is allowed")
87
+ raise TypeError(f"Only {self.__name__} is allowed")
88
88
 
89
89
  def rotate(self, axis, phi):
90
90
  """Rotate ``FeatureSet`` object `phi` degress about `axis`."""
@@ -902,7 +902,7 @@ class PairSet(FeatureSet):
902
902
  def __repr__(self):
903
903
  return f"P({len(self)}) {self.name}"
904
904
 
905
- def __array__(self, dtype=None):
905
+ def __array__(self, dtype=None, copy=None):
906
906
  return np.array([np.array(p) for p in self.data], dtype=dtype)
907
907
 
908
908
  @property
@@ -938,6 +938,45 @@ class PairSet(FeatureSet):
938
938
  """
939
939
  return Vector3Set([e.rax for e in self], name=self.name)
940
940
 
941
+ def angle(self, other=None):
942
+ """Return angles of all data in ``PairSet`` object
943
+
944
+ Without arguments it returns angles of all pairs in dataset.
945
+ If argument is ``PairSet`` of same length or single data object
946
+ element-wise angles are calculated.
947
+ """
948
+ res = []
949
+ if other is None:
950
+ res = [
951
+ abs(
952
+ DeformationGradient3.from_two_pairs(
953
+ e, f, symmetry=True
954
+ ).axisangle()[1]
955
+ )
956
+ for e, f in combinations(self.data, 2)
957
+ ]
958
+ elif issubclass(type(other), PairSet):
959
+ res = [
960
+ abs(
961
+ DeformationGradient3.from_two_pairs(
962
+ e, f, symmetry=True
963
+ ).axisangle()[1]
964
+ )
965
+ for e, f in zip(self, other)
966
+ ]
967
+ elif issubclass(type(other), Pair):
968
+ res = [
969
+ abs(
970
+ DeformationGradient3.from_two_pairs(
971
+ e, other, symmetry=True
972
+ ).axisangle()[1]
973
+ )
974
+ for e in self
975
+ ]
976
+ else:
977
+ raise TypeError("Wrong argument type!")
978
+ return np.asarray(res)
979
+
941
980
  @property
942
981
  def ortensor(self):
943
982
  """Return Lisle (1989) orientation tensor ``OrientationTensor3`` of orientations
@@ -1111,6 +1150,45 @@ class FaultSet(PairSet):
1111
1150
  """Return dihedra planes of FaultSet as FoliationSet"""
1112
1151
  return FoliationSet([e.d for e in self], name=self.name + "-D")
1113
1152
 
1153
+ def angle(self, other=None):
1154
+ """Return angles of all data in ``FaultSet`` object
1155
+
1156
+ Without arguments it returns angles of all pairs in dataset.
1157
+ If argument is ``FaultSet`` of same length or single data object
1158
+ element-wise angles are calculated.
1159
+ """
1160
+ res = []
1161
+ if other is None:
1162
+ res = [
1163
+ abs(
1164
+ DeformationGradient3.from_two_pairs(
1165
+ e, f, symmetry=False
1166
+ ).axisangle()[1]
1167
+ )
1168
+ for e, f in combinations(self.data, 2)
1169
+ ]
1170
+ elif issubclass(type(other), FaultSet):
1171
+ res = [
1172
+ abs(
1173
+ DeformationGradient3.from_two_pairs(
1174
+ e, f, symmetry=False
1175
+ ).axisangle()[1]
1176
+ )
1177
+ for e, f in zip(self, other)
1178
+ ]
1179
+ elif issubclass(type(other), Fault):
1180
+ res = [
1181
+ abs(
1182
+ DeformationGradient3.from_two_pairs(
1183
+ e, other, symmetry=False
1184
+ ).axisangle()[1]
1185
+ )
1186
+ for e in self
1187
+ ]
1188
+ else:
1189
+ raise TypeError("Wrong argument type!")
1190
+ return np.asarray(res)
1191
+
1114
1192
  @classmethod
1115
1193
  def random(cls, n=25):
1116
1194
  """Create PairSet of random pairs"""
@@ -1578,8 +1656,10 @@ class ClusterSet(object):
1578
1656
  """
1579
1657
 
1580
1658
  def __init__(self, d, **kwargs):
1581
- assert isinstance(d, Vector2Set) or isinstance(
1582
- d, Vector3Set
1659
+ assert (
1660
+ isinstance(d, Vector2Set)
1661
+ or isinstance(d, Vector3Set)
1662
+ or isinstance(d, PairSet)
1583
1663
  ), "Only vec2set or vecset could be clustered"
1584
1664
  self.data = d.copy()
1585
1665
  self.maxclust = kwargs.get("maxclust", 2)
apsg/feature/_geodata.py CHANGED
@@ -265,7 +265,7 @@ class Pair:
265
265
  """
266
266
  return not self == other
267
267
 
268
- def __array__(self, dtype=None):
268
+ def __array__(self, dtype=None, copy=None):
269
269
  return np.hstack((self.fvec, self.lvec)).astype(dtype)
270
270
 
271
271
  def label(self):
@@ -485,7 +485,7 @@ class Fault(Pair):
485
485
  """
486
486
  return not self == other
487
487
 
488
- def __array__(self, dtype=None):
488
+ def __array__(self, dtype=None, copy=None):
489
489
  return np.hstack((self.fvec, self.lvec, self.sense)).astype(dtype)
490
490
 
491
491
  def to_json(self):
@@ -649,7 +649,7 @@ class Cone:
649
649
  def __ne__(self, other):
650
650
  return not self == other
651
651
 
652
- def __array__(self, dtype=None):
652
+ def __array__(self, dtype=None, copy=None):
653
653
  return np.hstack((self.axis, self.secant, self.revangle)).astype(dtype)
654
654
 
655
655
  def label(self):
apsg/math/_vector.py CHANGED
@@ -26,7 +26,7 @@ class Vector:
26
26
  def __hash__(self):
27
27
  return hash((type(self).__name__,) + self._coords)
28
28
 
29
- def __array__(self, dtype=None):
29
+ def __array__(self, dtype=None, copy=None):
30
30
  return np.array(self._coords, dtype=dtype)
31
31
 
32
32
  def to_json(self):
@@ -84,9 +84,6 @@ class Vector:
84
84
 
85
85
  __pos__ = __copy__
86
86
 
87
- def __pow__(self, other):
88
- return type(self)(np.power(self, other))
89
-
90
87
  def __abs__(self):
91
88
  return math.sqrt(sum(map(lambda x: x * x, self._coords)))
92
89
 
@@ -452,6 +449,12 @@ class Vector3(Vector):
452
449
  else:
453
450
  return float(r)
454
451
 
452
+ def __pow__(self, other):
453
+ if issubclass(type(other), Vector3):
454
+ return self.cross(other)
455
+ else:
456
+ return type(self)(np.power(self, other))
457
+
455
458
  @ensure_first_arg_same
456
459
  def cross(self, other):
457
460
  """
@@ -103,7 +103,7 @@ class Vector3Array(ExtensionArray):
103
103
  """
104
104
  return Vec3Dtype()
105
105
 
106
- def __array__(self, dtype=str):
106
+ def __array__(self, dtype=str, copy=None):
107
107
  return np.array([str(f) for f in self._obj], dtype=dtype)
108
108
 
109
109
  @classmethod
@@ -951,38 +951,39 @@ def quicknet(*args, **kwargs):
951
951
  filename = kwargs.get("filename", "stereonet.png")
952
952
  savefig_kwargs = kwargs.get("savefig_kwargs", {})
953
953
  fol_as_pole = kwargs.get("fol_as_pole", False)
954
+ label = kwargs.get("label", "_nolegend_")
954
955
  s = StereoNet(**kwargs)
955
956
  for arg in args:
956
957
  if isinstance(arg, Vector3):
957
958
  if isinstance(arg, Foliation):
958
959
  if fol_as_pole:
959
- s.pole(arg)
960
+ s.pole(arg, label=label)
960
961
  else:
961
- s.great_circle(arg)
962
+ s.great_circle(arg, label=label)
962
963
  elif isinstance(arg, Lineation):
963
- s.line(arg)
964
+ s.line(arg, label=label)
964
965
  else:
965
- s.vector(arg)
966
+ s.vector(arg, label=label)
966
967
  elif isinstance(arg, Fault):
967
- s.fault(arg)
968
+ s.fault(arg, label=label)
968
969
  elif isinstance(arg, Pair):
969
- s.pair(arg)
970
+ s.pair(arg, label=label)
970
971
  elif isinstance(arg, Cone):
971
- s.cone(arg)
972
+ s.cone(arg, label=label)
972
973
  elif isinstance(arg, Vector3Set):
973
974
  if isinstance(arg, FoliationSet):
974
975
  if fol_as_pole:
975
- s.pole(arg)
976
+ s.pole(arg, label=label)
976
977
  else:
977
- s.great_circle(arg)
978
+ s.great_circle(arg, label=label)
978
979
  elif isinstance(arg, LineationSet):
979
- s.line(arg)
980
+ s.line(arg, label=label)
980
981
  else:
981
- s.vector(arg)
982
+ s.vector(arg, label=label)
982
983
  elif isinstance(arg, FaultSet):
983
- s.fault(arg)
984
+ s.fault(arg, label=label)
984
985
  elif isinstance(arg, PairSet):
985
- s.pair(arg)
986
+ s.pair(arg, label=label)
986
987
  else:
987
988
  print(f"{type(arg)} not supported.")
988
989
  if savefig:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: apsg
3
- Version: 1.2.1
3
+ Version: 1.2.3
4
4
  Summary: APSG - The package for structural geologists
5
5
  Home-page: https://github.com/ondrolexa/apsg
6
6
  Author: Ondrej Lexa
@@ -140,6 +140,14 @@ APSG is free software: you can redistribute it and/or modify it under the terms
140
140
 
141
141
  # Changes
142
142
 
143
+ ### 1.2.3 (Nov 18 2024)
144
+ * ClusterSet accepts PairSet and FaultSet
145
+ * quicknet label option added
146
+ * vector pow bug fix
147
+
148
+ ### 1.2.2 (Oct 21 2024)
149
+ * Fault sense could be defined by str, one of 's', 'd', 'n' and 'r'
150
+
143
151
  ### 1.2.1 (Sep 23 2024)
144
152
  * Fault sense could be defined by str, one of 's', 'd', 'n' and 'r'
145
153
 
@@ -1,4 +1,4 @@
1
- apsg/__init__.py,sha256=eM1G1KfWHxjUXGjUDXt4VOergl1vv69DCjV5s4tk_Xk,1966
1
+ apsg/__init__.py,sha256=6n0THwRqQoQB3yTyIfOmPJe0LT28VWp1nHDN_PYuCww,1966
2
2
  apsg/config.py,sha256=X3_yXT96xXlVxFA94EfYFKJbrcGIHT0PvB9s8EKmYOg,4569
3
3
  apsg/shell.py,sha256=UFIOy01KckLsOlqfB0UomyWZ1ITL36-lBUFhlxWdZLE,718
4
4
  apsg/database/__init__.py,sha256=7Rvcf1KBBBNhoM28ZlvQ01CkScQTroFkoS4d1kD55Ws,315
@@ -7,8 +7,8 @@ apsg/database/_sdbread.py,sha256=Gzj0bpp0vnMvCfxIuX6Ktf01LoQWDCOcXST7HZp_XTY,108
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
9
  apsg/feature/__init__.py,sha256=XGLq3GXpiWtzX6ROtuSc0kCPJEPTVRoIUtr8VpRZOWI,1664
10
- apsg/feature/_container.py,sha256=XFsoaDxsR-cSpbFfcY-g3aPbWT0u5j6AYDYZjPgDVLg,56601
11
- apsg/feature/_geodata.py,sha256=cGF8B-KdGtiwtFBQQycgWwMWtHuZY3xMYnHicnNv-ZI,22520
10
+ apsg/feature/_container.py,sha256=2hQtc6a5Z6puwfHcia4AAXsFoD8OuXO-Iqfbq6zRmnw,59283
11
+ apsg/feature/_geodata.py,sha256=NJ6jZJbq_-DX2ZLADEf5AMsPzz0T17RLizIq3uH_i7U,22553
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=-S-fI7_97UmJG78Q2gnXVUD_Qu7k0J9BXJ_AcoEKkOo,12397
@@ -19,9 +19,9 @@ 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
21
  apsg/math/_matrix.py,sha256=iXeBoTepWsPCNX4zPGQj9NM4TT6aNACVESDFSP9BQPE,10398
22
- apsg/math/_vector.py,sha256=IDaTiEpRtHCPqv2vjZP0dLTq5dYNOaeD3qOhq18_SuQ,16476
22
+ apsg/math/_vector.py,sha256=mD8kYggfGys-XWtnE90X2ZcTGBtDN49wEAUXQYXj3dI,16587
23
23
  apsg/pandas/__init__.py,sha256=jmlsulHmH9IbErJgSWlJx1J33-v--O5zxSE4kdt6fUI,456
24
- apsg/pandas/_pandas_api.py,sha256=dHzrZyD2v3beY_sShQWombhxNw_SxqZhU5GMXpBxDtM,13864
24
+ apsg/pandas/_pandas_api.py,sha256=_WpY5QJYAYZv9116xjWS0hOX2sgYcsGMPoSab7MWUFc,13875
25
25
  apsg/plotting/__init__.py,sha256=immav5OfKhYlOGZWUsFjuBp7k71vr2xLYygQkO6Oimc,627
26
26
  apsg/plotting/_fabricplot.py,sha256=QSqbRrL4EWbDsucfZLG0Oh1F0UP5ruK9tb3e9z9ff38,18863
27
27
  apsg/plotting/_paleomagplots.py,sha256=Gw-fqYJVjNxTNXLwAiUKnFUBoOTZv2MEd3XACLmQ6AM,2325
@@ -29,11 +29,11 @@ apsg/plotting/_plot_artists.py,sha256=6S0EKCqYU6rlBxcxcXALTk9PaUK6QL-BgUKmZH8tkM
29
29
  apsg/plotting/_projection.py,sha256=qnJgTQaFW0v2Pu9ySAEPADHhLgpXmfJ6QIrydry8rXQ,11473
30
30
  apsg/plotting/_roseplot.py,sha256=wqXo6b0k7lEvMrnByJYuoR_cuK1QIYZyZkObvigUx-g,12809
31
31
  apsg/plotting/_stereogrid.py,sha256=Buj0kp5P4cvTPowN6Jyt8wzvRMu3h5If1pwVWaal53M,11981
32
- apsg/plotting/_stereonet.py,sha256=f1nmBSKs_SjDW0npQJSX4gN2idqxtsHcfEwI64ITDak,36489
33
- apsg-1.2.1.dist-info/AUTHORS.md,sha256=OEu_2jVMx1fm5EOj4vBlI04uvX4P2sqjPYP12VjPIcI,130
34
- apsg-1.2.1.dist-info/LICENSE,sha256=NhDqn8b2aOSNn4U4tCfJTOQ6jeggFpLIBgJrAkzdiH0,1117
35
- apsg-1.2.1.dist-info/METADATA,sha256=rsi7FGSi8u-DnQaVRmQXuWDl8POHI1yPvrt5rS1FZc4,15355
36
- apsg-1.2.1.dist-info/WHEEL,sha256=AHX6tWk3qWuce7vKLrj7lnulVHEdWoltgauo8bgCXgU,109
37
- apsg-1.2.1.dist-info/entry_points.txt,sha256=SowP7_uRI0NJuzznKBXyM9BJcSwBxbXo6Iz5LUo9mEQ,42
38
- apsg-1.2.1.dist-info/top_level.txt,sha256=xWxwi0nqqOyKdmpsszfR-bmqnNpgVbhnLRuIKGJnaUM,5
39
- apsg-1.2.1.dist-info/RECORD,,
32
+ apsg/plotting/_stereonet.py,sha256=EMklIw7aWwzDUI2xTRHIBTya-yKiWuPUkPDB8Zz2KNA,36704
33
+ apsg-1.2.3.dist-info/AUTHORS.md,sha256=OEu_2jVMx1fm5EOj4vBlI04uvX4P2sqjPYP12VjPIcI,130
34
+ apsg-1.2.3.dist-info/LICENSE,sha256=NhDqn8b2aOSNn4U4tCfJTOQ6jeggFpLIBgJrAkzdiH0,1117
35
+ apsg-1.2.3.dist-info/METADATA,sha256=O1_PeJhALpIYZNRI9j4M4BarkxOjl2z16YzbkPkSMs4,15570
36
+ apsg-1.2.3.dist-info/WHEEL,sha256=0VNUDWQJzfRahYI3neAhz2UVbRCtztpN5dPHAGvmGXc,109
37
+ apsg-1.2.3.dist-info/entry_points.txt,sha256=SowP7_uRI0NJuzznKBXyM9BJcSwBxbXo6Iz5LUo9mEQ,42
38
+ apsg-1.2.3.dist-info/top_level.txt,sha256=xWxwi0nqqOyKdmpsszfR-bmqnNpgVbhnLRuIKGJnaUM,5
39
+ apsg-1.2.3.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.1.0)
2
+ Generator: setuptools (75.5.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py2-none-any
5
5
  Tag: py3-none-any
File without changes